* 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;
}
}
- // - Fast return for polling
- if( Timeout && *Timeout == 0 ) return 0;
-
// Wait for things
- if( !Timeout || *Timeout > 0 )
+ 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 );
+ // 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|THREAD_EVENT_SIGNAL );
+ Time_FreeTimer(t);
}
// Get return value
if( !(TypeFlags & (1 << type)) ) continue;
VFS_int_Select_GetType(type, Node, &list, &flag, &wanted, &maxAllowed);
LOG("VFS_int_Select_RemThread()");
+ 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;
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,
// 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);
// 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("Semaphore_Wait()");
+ // 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)
// - 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;
}
}
// Check for the flag
- if( !!*flag == !!wantedFlagValue )
+ if( !!*flag == !!wantedFlagValue ) {
+ LOG(" %i == want %i", !!*flag, !!wantedFlagValue);
numFlagged ++;
+ }
}
LEAVE('i', numFlagged);
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);
// Check for the flag
if( !!*flag == !!wantedFlagValue ) {
numFlagged ++;
+ LOG(" %i == want %i", !!*flag, !!wantedFlagValue);
+ FD_SET(i, Handles);
}
else {
FD_CLR(i, Handles);
}
count ++;
if( MaxAllowed && count >= MaxAllowed ) {
+ Mutex_Release(&List->Lock);
LEAVE('i', 1);
return 1;
}
void VFS_int_Select_RemThread(tVFS_SelectList *List, tThread *Thread)
{
- int i;
tVFS_SelectListEnt *block, *prev = NULL;
ENTER("pList pThread", List, 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 )
{