Kernel/vfs - Return matched flags from VFS_SelectNode
[tpg/acess2.git] / KernelLand / Kernel / vfs / select.c
index 439afc0..a18b91c 100644 (file)
@@ -5,7 +5,6 @@
  * select.c
  * - Implements the select() system call (and supporting code)
  *
- * TODO: Implment timeouts (via an alarm event?)
  * TODO: Remove malloc for read/write queues
  */
 #define DEBUG  0
 #include <semaphore.h>
 #include <threads.h>
 #include <events.h>
+#include <timers.h>
 
 // === CONSTANTS ===
 #define        NUM_THREADS_PER_ALLOC   4
 
-// === IMPORTS ===
-extern tThread *Proc_GetCurThread(void);
-
 // === TYPES ===
 typedef struct sVFS_SelectListEnt      tVFS_SelectListEnt;
 
@@ -58,13 +55,14 @@ void        VFS_int_Select_SignalAll(tVFS_SelectList *List);
 // === FUNCTIONS ===
 int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *Name)
 {
-       tThread *thisthread = Proc_GetCurThread();
-        int    ret, type;
+       tThread * const thisthread = Proc_GetCurThread();
+        int    ret;
        
        ENTER("pNode iTypeFlags pTimeout sName", Node, TypeFlags, Timeout, Name);
        
        // Initialise
-       for( type = 0; type < 3; type ++ )
+       ret = 0;
+       for( int type = 0; type < 3; type ++ )
        {
                tVFS_SelectList **list;
                 int    *flag, wanted, maxAllowed;
@@ -80,35 +78,49 @@ int VFS_SelectNode(tVFS_Node *Node, int TypeFlags, tTime *Timeout, const char *N
                VFS_int_Select_AddThread(*list, thisthread, maxAllowed);
                if( *flag == wanted )
                {
-                       VFS_int_Select_RemThread(*list, thisthread);
-                       LEAVE('i', 1);
-                       return 1;
+                       ret |= (1 << type);
                }
        }
 
-       // - Fast return for polling
-       if( Timeout && *Timeout == 0 )  return 0;
-
        // Wait for things      
-       if( !Timeout || *Timeout > 0 )
+       if( ret )
+       {
+               // Skip wait, conditions already met
+               LOG("ret = %i, skipping wait", ret);
+       }
+       else if( !Timeout )
        {
                LOG("Semaphore_Wait()");
-               // TODO: Actual timeout
-               Threads_WaitEvents( THREAD_EVENT_VFS );
+               Threads_WaitEvents( THREAD_EVENT_VFS|THREAD_EVENT_SIGNAL );
+       }
+       else if( *Timeout > 0 )
+       {
+               tTimer *t = Time_AllocateTimer(NULL, NULL);
+               // Clear timer event
+               Threads_ClearEvent( THREAD_EVENT_TIMER );
+               LOG("Timeout %lli ms", *Timeout);
+               Time_ScheduleTimer( t, *Timeout );
+               // Wait for the timer or a VFS event
+               Threads_WaitEvents( THREAD_EVENT_VFS|THREAD_EVENT_TIMER|THREAD_EVENT_SIGNAL );
+               Time_FreeTimer(t);
        }
        
        // Get return value
        ret = 0;
-       for( type = 0; type < 3; type ++ )
+       for( int type = 0; type < 3; type ++ )
        {
                tVFS_SelectList **list;
                 int    *flag, wanted, maxAllowed;
                if( !(TypeFlags & (1 << type)) )        continue;
                VFS_int_Select_GetType(type, Node, &list, &flag, &wanted, &maxAllowed);
-               LOG("VFS_int_Select_RemThread()");
+               LOG("VFS_int_Select_RemThread() for %i", type);
+               ASSERT(*list);
                VFS_int_Select_RemThread(*list, thisthread);
                ret = ret || *flag == wanted;
        }
+
+       Threads_ClearEvent( THREAD_EVENT_VFS );
+       Threads_ClearEvent( THREAD_EVENT_TIMER );
        
        LEAVE('i', ret);
        return ret;
@@ -119,8 +131,8 @@ int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set
        tThread *thisthread = Proc_GetCurThread();
         int    ret;
        
-       ENTER("iMaxHandle pReadHandles pWriteHandles pErrHandles pTimeout bIsKernel",
-               MaxHandle, ReadHandles, WriteHandles, ErrHandles, Timeout, IsKernel);
+       ENTER("iMaxHandle pReadHandles pWriteHandles pErrHandles pTimeout xExtraEvents bIsKernel",
+               MaxHandle, ReadHandles, WriteHandles, ErrHandles, Timeout, ExtraEvents, IsKernel);
        
        // Notes: The idea is to make sure we only enter wait (Threads_WaitEvents)
        // if we are going to be woken up (either by an event at a later time,
@@ -130,6 +142,8 @@ int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set
        // or the semaphore is incremeneted (or both, but never none)
        
        // Register with nodes
+       if( ReadHandles )
+               LOG(" - ReadHandles[0] = %x", ReadHandles->flags[0]);
        ret  = VFS_int_Select_Register(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
        ret += VFS_int_Select_Register(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
        ret += VFS_int_Select_Register(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
@@ -139,29 +153,44 @@ int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set
        // If there were events waiting, de-register and return
        if( ret > 0 )
        {
+               LOG(" - ReadHandles[0] = %x", ReadHandles->flags[0]);
                ret  = VFS_int_Select_Deregister(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
                ret += VFS_int_Select_Deregister(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
                ret += VFS_int_Select_Deregister(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
+               LOG(" - ReadHandles[0] = %x", ReadHandles->flags[0]);
                LEAVE('i', ret);
                return ret;
        }
-       
-       // TODO: Implement timeout
-       LOG("Timeout = %p", Timeout);
-       
-       // Wait (only if there is no timeout, or it is greater than zero
-       if( !Timeout || *Timeout > 0 )
+
+       // Wait for things      
+       if( !Timeout )
        {
-               // TODO: Timeout
-               // TODO: Allow extra events to be waited upon
-               Threads_WaitEvents( THREAD_EVENT_VFS|ExtraEvents );
+               LOG("Waiting for VFS/SIGNAL events (Plus 0x%x)", ExtraEvents);
+               // TODO: Actual timeout
+               Threads_WaitEvents( THREAD_EVENT_VFS|THREAD_EVENT_SIGNAL|ExtraEvents );
+       }
+       else if( *Timeout > 0 )
+       {
+               tTimer *t = Time_AllocateTimer(NULL, NULL);
+               // Clear timer event
+               Threads_ClearEvent( THREAD_EVENT_TIMER );
+               // TODO: Convert *Timeout?
+               LOG("Timeout %lli ms", *Timeout);
+               Time_ScheduleTimer( t, *Timeout );
+               // Wait for the timer or a VFS event
+               Threads_WaitEvents( THREAD_EVENT_VFS|THREAD_EVENT_TIMER|ExtraEvents );
+               Time_FreeTimer(t);
        }
-       
        // Fill output (modify *Handles)
+       LOG("De-registering");
        // - Also, de-register
        ret  = VFS_int_Select_Deregister(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
        ret += VFS_int_Select_Deregister(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
        ret += VFS_int_Select_Deregister(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
+       
+       Threads_ClearEvent( THREAD_EVENT_VFS );
+       Threads_ClearEvent( THREAD_EVENT_TIMER );
+       
        LEAVE('i', ret);
        return ret;
 }
@@ -169,6 +198,7 @@ int VFS_Select(int MaxHandle, fd_set *ReadHandles, fd_set *WriteHandles, fd_set
 // Mark a node as having data ready for reading
 int VFS_MarkAvaliable(tVFS_Node *Node, BOOL IsDataAvaliable)
 {
+       ASSERTR(Node, 1);
        ENTER("pNode bIsDataAvaliable", Node, IsDataAvaliable);
        Node->DataAvaliable = !!IsDataAvaliable;
        if( Node->DataAvaliable )
@@ -180,6 +210,7 @@ int VFS_MarkAvaliable(tVFS_Node *Node, BOOL IsDataAvaliable)
 // Mark a node as having a full buffer
 int VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull)
 {
+       ASSERTR(Node, 1);
        ENTER("pNode bIsBufferFull", Node, IsBufferFull);
        Node->BufferFull = !!IsBufferFull;
        if( !Node->BufferFull )
@@ -191,6 +222,7 @@ int VFS_MarkFull(tVFS_Node *Node, BOOL IsBufferFull)
 // Mark a node as errored
 int VFS_MarkError(tVFS_Node *Node, BOOL IsErrorState)
 {
+       ASSERTR(Node, 1);
        ENTER("pNode bIsErrorState", Node, IsErrorState);
        Node->ErrorOccurred = !!IsErrorState;
        if( Node->ErrorOccurred )
@@ -284,8 +316,10 @@ int VFS_int_Select_Register(tThread *Thread, int MaxHandle, fd_set *Handles, int
                }
                
                // Check for the flag
-               if( !!*flag == !!wantedFlagValue )
+               if( !!*flag == !!wantedFlagValue ) {
+                       LOG(" %i == want %i", !!*flag, !!wantedFlagValue);
                        numFlagged ++;
+               }
        }
        
        LEAVE('i', numFlagged);
@@ -326,8 +360,6 @@ int VFS_int_Select_Deregister(tThread *Thread, int MaxHandle, fd_set *Handles, i
                        continue;
                }
        
-               // Get the type of the listen
-       
                // Get the type of the listen
                if( VFS_int_Select_GetType(Type, handle->Node, &list, &flag, &wantedFlagValue, NULL) ) {
                        LEAVE('i', 0);
@@ -340,6 +372,8 @@ int VFS_int_Select_Deregister(tThread *Thread, int MaxHandle, fd_set *Handles, i
                // Check for the flag
                if( !!*flag == !!wantedFlagValue ) {
                        numFlagged ++;
+                       LOG(" %i == want %i", !!*flag, !!wantedFlagValue);
+                       FD_SET(i, Handles);
                }
                else {
                        FD_CLR(i, Handles);
@@ -380,6 +414,7 @@ int VFS_int_Select_AddThread(tVFS_SelectList *List, tThread *Thread, int MaxAllo
                        }
                        count ++;
                        if( MaxAllowed && count >= MaxAllowed ) {
+                               Mutex_Release(&List->Lock);
                                LEAVE('i', 1);
                                return 1;
                        }
@@ -417,7 +452,6 @@ int VFS_int_Select_AddThread(tVFS_SelectList *List, tThread *Thread, int MaxAllo
 
 void VFS_int_Select_RemThread(tVFS_SelectList *List, tThread *Thread)
 {
-        int    i;
        tVFS_SelectListEnt      *block, *prev = NULL;
        
        ENTER("pList pThread", List, Thread);
@@ -430,7 +464,7 @@ void VFS_int_Select_RemThread(tVFS_SelectList *List, tThread *Thread)
        // Look for the thread
        do
        {
-               for( i = 0; i < NUM_THREADS_PER_ALLOC; i ++ )
+               for( int i = 0; i < NUM_THREADS_PER_ALLOC; i ++ )
                {
                        if( block->Threads[i] == Thread )
                        {

UCC git Repository :: git.ucc.asn.au