Sweden-Number/scheduler/services.c

324 lines
7.7 KiB
C
Raw Normal View History

1999-04-11 17:01:20 +02:00
/*
* Kernel Services Thread
*
* Copyright 1999 Ulrich Weigand
*/
#include <sys/time.h>
#include <unistd.h>
#include "services.h"
#include "process.h"
#include "debugtools.h"
1999-04-11 17:01:20 +02:00
DEFAULT_DEBUG_CHANNEL(timer)
1999-04-11 17:01:20 +02:00
typedef struct _SERVICE
{
struct _SERVICE *next;
HANDLE self;
1999-04-11 17:01:20 +02:00
PAPCFUNC callback;
ULONG_PTR callback_arg;
1999-04-11 17:01:20 +02:00
BOOL disabled;
HANDLE object;
1999-04-11 17:01:20 +02:00
} SERVICE;
typedef struct _SERVICETABLE
1999-04-11 17:01:20 +02:00
{
HANDLE thread;
1999-04-11 17:01:20 +02:00
SERVICE *first;
DWORD counter;
1999-04-11 17:01:20 +02:00
} SERVICETABLE;
/***********************************************************************
* SERVICE_Loop
*/
static DWORD CALLBACK SERVICE_Loop( SERVICETABLE *service )
{
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
int count = 0;
DWORD retval = WAIT_FAILED;
1999-04-11 17:01:20 +02:00
while ( TRUE )
{
PAPCFUNC callback;
ULONG_PTR callback_arg;
SERVICE *s;
/* Check whether some condition is fulfilled */
HeapLock( GetProcessHeap() );
1999-04-11 17:01:20 +02:00
callback = NULL;
callback_arg = 0L;
for ( s = service->first; s; s = s->next )
{
if (s->disabled) continue;
if ( retval >= WAIT_OBJECT_0 && retval < WAIT_OBJECT_0 + count )
{
if ( handles[retval - WAIT_OBJECT_0] == s->object )
1999-04-11 17:01:20 +02:00
{
retval = WAIT_TIMEOUT;
1999-04-11 17:01:20 +02:00
callback = s->callback;
callback_arg = s->callback_arg;
break;
}
}
1999-04-11 17:01:20 +02:00
}
HeapUnlock( GetProcessHeap() );
1999-04-11 17:01:20 +02:00
/* If found, call callback routine */
if ( callback )
{
callback( callback_arg );
1999-04-11 17:01:20 +02:00
continue;
}
/* If not found, determine wait condition */
HeapLock( GetProcessHeap() );
1999-04-11 17:01:20 +02:00
count = 0;
for ( s = service->first; s; s = s->next )
{
if (s->disabled) continue;
1999-04-11 17:01:20 +02:00
if ( count < MAXIMUM_WAIT_OBJECTS )
handles[count++] = s->object;
1999-04-11 17:01:20 +02:00
}
HeapUnlock( GetProcessHeap() );
1999-04-11 17:01:20 +02:00
/* Wait until some condition satisfied */
TRACE("Waiting for %d objects\n", count );
1999-04-11 17:01:20 +02:00
retval = WaitForMultipleObjectsEx( count, handles, FALSE, INFINITE, TRUE );
1999-04-11 17:01:20 +02:00
TRACE("Wait returned: %ld\n", retval );
1999-04-11 17:01:20 +02:00
}
return 0L;
}
/***********************************************************************
* SERVICE_CreateServiceTable
1999-04-11 17:01:20 +02:00
*/
static BOOL SERVICE_CreateServiceTable( void )
1999-04-11 17:01:20 +02:00
{
HANDLE thread;
SERVICETABLE *service_table;
PDB *pdb = PROCESS_Current();
1999-04-11 17:01:20 +02:00
service_table = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICETABLE) );
if ( !service_table )
1999-04-11 17:01:20 +02:00
{
return FALSE;
}
/* service_table field in PDB must be set *BEFORE* calling CreateThread
* otherwise the thread cleanup service will cause an infinite recursion
* when installed
*/
pdb->service_table = service_table;
1999-04-11 17:01:20 +02:00
thread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)SERVICE_Loop,
service_table, 0, NULL );
1999-04-11 17:01:20 +02:00
if ( thread == INVALID_HANDLE_VALUE )
{
pdb->service_table = 0;
HeapFree( GetProcessHeap(), 0, service_table );
1999-04-11 17:01:20 +02:00
return FALSE;
}
service_table->thread = thread;
1999-04-11 17:01:20 +02:00
return TRUE;
}
/***********************************************************************
* SERVICE_AddObject
*
* Warning: the object supplied by the caller must not be closed. It'll
* be destroyed when the service is deleted. It's up to the caller
* to ensure that object will not be destroyed in between.
1999-04-11 17:01:20 +02:00
*/
HANDLE SERVICE_AddObject( HANDLE object,
PAPCFUNC callback, ULONG_PTR callback_arg )
{
SERVICE *s;
SERVICETABLE *service_table;
HANDLE handle;
if ( object == INVALID_HANDLE_VALUE || !callback )
1999-04-11 17:01:20 +02:00
return INVALID_HANDLE_VALUE;
if (PROCESS_Current()->service_table == 0 && !SERVICE_CreateServiceTable())
return INVALID_HANDLE_VALUE;
service_table = PROCESS_Current()->service_table;
1999-04-11 17:01:20 +02:00
s = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SERVICE) );
if ( !s ) return INVALID_HANDLE_VALUE;
1999-04-11 17:01:20 +02:00
s->callback = callback;
s->callback_arg = callback_arg;
s->object = object;
s->disabled = FALSE;
1999-04-11 17:01:20 +02:00
HeapLock( GetProcessHeap() );
s->self = handle = (HANDLE)++service_table->counter;
s->next = service_table->first;
service_table->first = s;
1999-04-11 17:01:20 +02:00
HeapUnlock( GetProcessHeap() );
1999-04-11 17:01:20 +02:00
QueueUserAPC( NULL, service_table->thread, 0L );
1999-04-11 17:01:20 +02:00
return handle;
}
/***********************************************************************
* SERVICE_AddTimer
*/
HANDLE SERVICE_AddTimer( LONG rate,
PAPCFUNC callback, ULONG_PTR callback_arg )
{
HANDLE handle, ret;
LARGE_INTEGER when;
1999-04-11 17:01:20 +02:00
if ( !rate || !callback )
1999-04-11 17:01:20 +02:00
return INVALID_HANDLE_VALUE;
handle = CreateWaitableTimerA( NULL, FALSE, NULL );
if (!handle) return INVALID_HANDLE_VALUE;
1999-04-11 17:01:20 +02:00
if (!rate) rate = 1;
when.s.LowPart = when.s.HighPart = 0;
if (!SetWaitableTimer( handle, &when, rate, NULL, NULL, FALSE ))
{
CloseHandle( handle );
return INVALID_HANDLE_VALUE;
}
1999-04-11 17:01:20 +02:00
if ((ret = SERVICE_AddObject( handle, callback, callback_arg )) == INVALID_HANDLE_VALUE)
{
CloseHandle( handle );
return INVALID_HANDLE_VALUE;
}
return ret;
1999-04-11 17:01:20 +02:00
}
/***********************************************************************
* SERVICE_Delete
*/
BOOL SERVICE_Delete( HANDLE service )
{
HANDLE handle = INVALID_HANDLE_VALUE;
BOOL retv = FALSE;
SERVICE **s, *next;
SERVICETABLE *service_table;
1999-04-11 17:01:20 +02:00
/* service table must have been created on previous SERVICE_Add??? call */
if ((service_table = PROCESS_Current()->service_table) == 0)
return retv;
1999-04-11 17:01:20 +02:00
HeapLock( GetProcessHeap() );
1999-04-11 17:01:20 +02:00
for ( s = &service_table->first; *s; s = &(*s)->next )
{
1999-04-11 17:01:20 +02:00
if ( (*s)->self == service )
{
handle = (*s)->object;
next = (*s)->next;
HeapFree( GetProcessHeap(), 0, *s );
*s = next;
retv = TRUE;
1999-04-11 17:01:20 +02:00
break;
}
}
1999-04-11 17:01:20 +02:00
HeapUnlock( GetProcessHeap() );
1999-04-11 17:01:20 +02:00
if ( handle != INVALID_HANDLE_VALUE )
CloseHandle( handle );
QueueUserAPC( NULL, service_table->thread, 0L );
1999-04-11 17:01:20 +02:00
return retv;
}
/***********************************************************************
* SERVICE_Enable
*/
BOOL SERVICE_Enable( HANDLE service )
{
BOOL retv = FALSE;
SERVICE *s;
SERVICETABLE *service_table;
1999-04-11 17:01:20 +02:00
/* service table must have been created on previous SERVICE_Add??? call */
if ((service_table = PROCESS_Current()->service_table) == 0)
return retv;
1999-04-11 17:01:20 +02:00
HeapLock( GetProcessHeap() );
1999-04-11 17:01:20 +02:00
for ( s = service_table->first; s; s = s->next )
{
1999-04-11 17:01:20 +02:00
if ( s->self == service )
{
s->disabled = FALSE;
retv = TRUE;
1999-04-11 17:01:20 +02:00
break;
}
}
1999-04-11 17:01:20 +02:00
HeapUnlock( GetProcessHeap() );
1999-04-11 17:01:20 +02:00
QueueUserAPC( NULL, service_table->thread, 0L );
1999-04-11 17:01:20 +02:00
return retv;
}
/***********************************************************************
* SERVICE_Disable
*/
BOOL SERVICE_Disable( HANDLE service )
{
BOOL retv = TRUE;
SERVICE *s;
SERVICETABLE *service_table;
1999-04-11 17:01:20 +02:00
/* service table must have been created on previous SERVICE_Add??? call */
if ((service_table = PROCESS_Current()->service_table) == 0)
return retv;
1999-04-11 17:01:20 +02:00
HeapLock( GetProcessHeap() );
1999-04-11 17:01:20 +02:00
for ( s = service_table->first; s; s = s->next )
{
1999-04-11 17:01:20 +02:00
if ( s->self == service )
{
s->disabled = TRUE;
retv = TRUE;
1999-04-11 17:01:20 +02:00
break;
}
}
1999-04-11 17:01:20 +02:00
HeapUnlock( GetProcessHeap() );
1999-04-11 17:01:20 +02:00
QueueUserAPC( NULL, service_table->thread, 0L );
1999-04-11 17:01:20 +02:00
return retv;
}