mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-02-28 06:13:03 +01:00
merge windows and posix scheduler.c into one source file
This commit is contained in:
parent
1256cacca3
commit
d7e54b2dad
@ -1,310 +0,0 @@
|
||||
#include "common.h"
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
typedef struct _WaitableEntry
|
||||
{
|
||||
Remote * remote;
|
||||
int waitable;
|
||||
EVENT* pause;
|
||||
EVENT* resume;
|
||||
LPVOID context;
|
||||
BOOL running;
|
||||
WaitableNotifyRoutine routine;
|
||||
WaitableDestroyRoutine destroy;
|
||||
} WaitableEntry;
|
||||
|
||||
/*
|
||||
* The list of all currenltly running threads in the scheduler subsystem.
|
||||
*/
|
||||
LIST * schedulerThreadList = NULL;
|
||||
|
||||
/*
|
||||
* The Remote that is associated with the scheduler subsystem
|
||||
*/
|
||||
Remote * schedulerRemote = NULL;
|
||||
|
||||
/*
|
||||
* Initialize the scheduler subsystem. Must be called before any calls to scheduler_insert_waitable.
|
||||
*/
|
||||
DWORD scheduler_initialize( Remote * remote )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_initialize." );
|
||||
|
||||
if( remote == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
schedulerThreadList = list_create();
|
||||
if( schedulerThreadList == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
schedulerRemote = remote;
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_initialize." );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the scheduler subsystem. All waitable threads at signaled to terminate.
|
||||
* this function blocks untill all waitable threads have terminated.
|
||||
*/
|
||||
DWORD scheduler_destroy( VOID )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
DWORD index = 0;
|
||||
DWORD count = 0;
|
||||
LIST * jlist = list_create();
|
||||
THREAD * thread = NULL;
|
||||
WaitableEntry * entry = NULL;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_destroy." );
|
||||
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
|
||||
count = list_count( schedulerThreadList );
|
||||
|
||||
for( index=0 ; index < count ; index++ )
|
||||
{
|
||||
thread = (THREAD *)list_get( schedulerThreadList, index );
|
||||
if( thread == NULL )
|
||||
continue;
|
||||
|
||||
list_push( jlist, thread );
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
|
||||
if( !entry->running )
|
||||
event_signal( entry->resume );
|
||||
|
||||
thread_sigterm( thread );
|
||||
}
|
||||
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, joining all waitable threads..." );
|
||||
|
||||
while( TRUE )
|
||||
{
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, popping off another item from thread liat..." );
|
||||
|
||||
thread = (THREAD *)list_pop( jlist );
|
||||
if( thread == NULL )
|
||||
break;
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, joining thread 0x%08X...", thread );
|
||||
|
||||
thread_join( thread );
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, destroying lists..." );
|
||||
|
||||
list_destroy( jlist );
|
||||
|
||||
list_destroy( schedulerThreadList );
|
||||
|
||||
schedulerThreadList = NULL;
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_destroy." );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new waitable thread for checking and processing.
|
||||
*/
|
||||
DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID entryContext, LPVOID threadContext, WaitableNotifyRoutine routine, WaitableDestroyRoutine destroy )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
THREAD * swt = NULL;
|
||||
|
||||
WaitableEntry * entry = (WaitableEntry *)malloc( sizeof( WaitableEntry ) );
|
||||
if( entry == NULL )
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_insert_waitable( 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X )",
|
||||
waitable, entryContext, threadContext, routine, destroy );
|
||||
|
||||
memset( entry, 0, sizeof( WaitableEntry ) );
|
||||
|
||||
entry->remote = schedulerRemote;
|
||||
entry->waitable = waitable;
|
||||
entry->destroy = destroy;
|
||||
entry->context = entryContext;
|
||||
entry->routine = routine;
|
||||
entry->pause = event_create();
|
||||
entry->resume = event_create();
|
||||
|
||||
swt = thread_create( scheduler_waitable_thread, entry, threadContext, NULL );
|
||||
if( swt != NULL )
|
||||
{
|
||||
dprintf( "[SCHEDULER] created scheduler_waitable_thread 0x%08X", swt );
|
||||
thread_run( swt );
|
||||
}
|
||||
else
|
||||
{
|
||||
free( entry );
|
||||
result = ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_insert_waitable" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal a waitable object.
|
||||
*/
|
||||
DWORD scheduler_signal_waitable( HANDLE waitable, SchedularSignal signal )
|
||||
{
|
||||
DWORD index = 0;
|
||||
DWORD count = 0;
|
||||
THREAD * thread = NULL;
|
||||
WaitableEntry * entry = NULL;
|
||||
DWORD result = ERROR_NOT_FOUND;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_signal_waitable( 0x%08X )", waitable );
|
||||
|
||||
if( schedulerThreadList == NULL || waitable == 0 )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
|
||||
count = list_count( schedulerThreadList );
|
||||
|
||||
for( index=0 ; index < count ; index++ )
|
||||
{
|
||||
thread = (THREAD *)list_get( schedulerThreadList, index );
|
||||
if( thread == NULL )
|
||||
continue;
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
if( entry == NULL )
|
||||
continue;
|
||||
|
||||
if( entry->waitable == waitable )
|
||||
{
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: signaling waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
if( signal == Pause )
|
||||
{
|
||||
if( entry->running ) {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread running, pausing. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, entry->pause->handle );
|
||||
event_signal( entry->pause );
|
||||
} else {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread already paused. waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !entry->running ) {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread paused, resuming. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, entry->resume->handle );
|
||||
event_signal( entry->resume );
|
||||
}
|
||||
|
||||
if( signal == Stop ) {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: stopping thread. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, thread->sigterm->handle );
|
||||
thread_sigterm( thread );
|
||||
} else {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread already running. waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
}
|
||||
}
|
||||
|
||||
result = ERROR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_signal_waitable" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The schedulers waitable thread. Each scheduled item will have its own thread which
|
||||
* waits for either data to process or the threads signal to terminate.
|
||||
*/
|
||||
DWORD THREADCALL scheduler_waitable_thread( THREAD * thread )
|
||||
{
|
||||
struct pollfd pollDetail = {0};
|
||||
WaitableEntry * entry = NULL;
|
||||
DWORD result = 0;
|
||||
BOOL terminate = FALSE;
|
||||
UINT signalIndex = 0;
|
||||
|
||||
if( thread == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
if( entry == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if( entry->routine == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if( schedulerThreadList == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
list_add( schedulerThreadList, thread );
|
||||
|
||||
pollDetail.fd = entry->waitable;
|
||||
pollDetail.events = POLLRDNORM;
|
||||
pollDetail.revents = 0;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_waitable_thread( 0x%08X )", thread );
|
||||
|
||||
|
||||
entry->running = TRUE;
|
||||
while( !terminate )
|
||||
{
|
||||
if( event_poll( thread->sigterm, 0 ) ) {
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to terminate...", thread );
|
||||
terminate = TRUE;
|
||||
}
|
||||
else if( event_poll( entry->pause, 0 ) ) {
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to pause...", thread );
|
||||
entry->running = FALSE;
|
||||
while( !event_poll( entry->resume, 1000 ) );
|
||||
entry->running = TRUE;
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to resume...", thread );
|
||||
}
|
||||
else if( poll( &pollDetail, 1, 100 ) == POLLIN ) {
|
||||
//dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled on waitable...", thread );
|
||||
entry->routine( entry->remote, entry->context, (LPVOID)thread->parameter2 );
|
||||
}
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_waitable_thread( 0x%08X )", thread );
|
||||
|
||||
// we acquire the lock for this block as we are freeing 'entry' which may be accessed
|
||||
// in a second call to scheduler_signal_waitable for this thread (unlikely but best practice).
|
||||
dprintf( "[SCHEDULER] attempting to remove thread( 0x%08X )", thread );
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
if( list_remove( schedulerThreadList, thread ) )
|
||||
{
|
||||
if( entry->destroy ) {
|
||||
dprintf( "[SCHEDULER] destroying thread( 0x%08X )", thread );
|
||||
entry->destroy( entry->waitable, entry->context, (LPVOID)thread->parameter2 );
|
||||
dprintf( "[SCHEDULER] destroyed thread( 0x%08X )", thread );
|
||||
}
|
||||
else if( entry->waitable ) {
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ) closing handle 0x%08X", thread, entry->waitable);
|
||||
close( entry->waitable );
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] cleaning up resume thread( 0x%08X )", thread );
|
||||
event_destroy( entry->resume );
|
||||
dprintf( "[SCHEDULER] cleaning up pause thread( 0x%08X )", thread );
|
||||
event_destroy( entry->pause );
|
||||
dprintf( "[SCHEDULER] cleaning up thread( 0x%08X )", thread );
|
||||
thread_destroy( thread );
|
||||
dprintf( "[SCHEDULER] cleaning up entry( 0x%08X )", thread );
|
||||
free( entry );
|
||||
}
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
@ -1,309 +1,350 @@
|
||||
#include "common.h"
|
||||
|
||||
typedef struct _WaitableEntry
|
||||
{
|
||||
Remote * remote;
|
||||
HANDLE waitable;
|
||||
EVENT* pause;
|
||||
EVENT* resume;
|
||||
LPVOID context;
|
||||
BOOL running;
|
||||
WaitableNotifyRoutine routine;
|
||||
WaitableDestroyRoutine destroy;
|
||||
} WaitableEntry;
|
||||
|
||||
/*
|
||||
* The list of all currenltly running threads in the scheduler subsystem.
|
||||
*/
|
||||
LIST * schedulerThreadList = NULL;
|
||||
|
||||
/*
|
||||
* The Remote that is associated with the scheduler subsystem
|
||||
*/
|
||||
Remote * schedulerRemote = NULL;
|
||||
|
||||
/*
|
||||
* Initialize the scheduler subsystem. Must be called before any calls to scheduler_insert_waitable.
|
||||
*/
|
||||
DWORD scheduler_initialize( Remote * remote )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_initialize." );
|
||||
|
||||
if( remote == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
schedulerThreadList = list_create();
|
||||
if( schedulerThreadList == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
schedulerRemote = remote;
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_initialize." );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the scheduler subsystem. All waitable threads at signaled to terminate.
|
||||
* this function blocks untill all waitable threads have terminated.
|
||||
*/
|
||||
DWORD scheduler_destroy( VOID )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
DWORD index = 0;
|
||||
DWORD count = 0;
|
||||
LIST * jlist = list_create();
|
||||
THREAD * thread = NULL;
|
||||
WaitableEntry * entry = NULL;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_destroy." );
|
||||
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
|
||||
count = list_count( schedulerThreadList );
|
||||
|
||||
for( index=0 ; index < count ; index++ )
|
||||
{
|
||||
thread = (THREAD *)list_get( schedulerThreadList, index );
|
||||
if( thread == NULL )
|
||||
continue;
|
||||
|
||||
list_push( jlist, thread );
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
|
||||
if( !entry->running )
|
||||
event_signal( entry->resume );
|
||||
|
||||
thread_sigterm( thread );
|
||||
}
|
||||
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, joining all waitable threads..." );
|
||||
|
||||
while( TRUE )
|
||||
{
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, popping off another item from thread list..." );
|
||||
|
||||
thread = (THREAD *)list_pop( jlist );
|
||||
if( thread == NULL )
|
||||
break;
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, joining thread 0x%08X...", thread );
|
||||
|
||||
thread_join( thread );
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, destroying lists..." );
|
||||
|
||||
list_destroy( jlist );
|
||||
|
||||
list_destroy( schedulerThreadList );
|
||||
|
||||
schedulerThreadList = NULL;
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_destroy." );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new waitable thread for checking and processing.
|
||||
*/
|
||||
DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID entryContext, LPVOID threadContext, WaitableNotifyRoutine routine, WaitableDestroyRoutine destroy )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
THREAD * swt = NULL;
|
||||
|
||||
WaitableEntry * entry = (WaitableEntry *)malloc( sizeof( WaitableEntry ) );
|
||||
if( entry == NULL )
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_insert_waitable( 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X )",
|
||||
waitable, entryContext, threadContext, routine, destroy );
|
||||
|
||||
memset( entry, 0, sizeof( WaitableEntry ) );
|
||||
|
||||
entry->remote = schedulerRemote;
|
||||
entry->waitable = waitable;
|
||||
entry->destroy = destroy;
|
||||
entry->context = entryContext;
|
||||
entry->routine = routine;
|
||||
entry->pause = event_create();
|
||||
entry->resume = event_create();
|
||||
|
||||
swt = thread_create( scheduler_waitable_thread, entry, threadContext, NULL );
|
||||
if( swt != NULL )
|
||||
{
|
||||
dprintf( "[SCHEDULER] created scheduler_waitable_thread 0x%08X", swt );
|
||||
thread_run( swt );
|
||||
}
|
||||
else
|
||||
{
|
||||
free( entry );
|
||||
result = ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_insert_waitable" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal a waitable object.
|
||||
*/
|
||||
DWORD scheduler_signal_waitable( HANDLE waitable, SchedularSignal signal )
|
||||
{
|
||||
DWORD index = 0;
|
||||
DWORD count = 0;
|
||||
THREAD * thread = NULL;
|
||||
WaitableEntry * entry = NULL;
|
||||
DWORD result = ERROR_NOT_FOUND;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_signal_waitable( 0x%08X )", waitable );
|
||||
|
||||
if( schedulerThreadList == NULL || waitable == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
|
||||
count = list_count( schedulerThreadList );
|
||||
|
||||
for( index=0 ; index < count ; index++ )
|
||||
{
|
||||
thread = (THREAD *)list_get( schedulerThreadList, index );
|
||||
if( thread == NULL )
|
||||
continue;
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
if( entry == NULL )
|
||||
continue;
|
||||
|
||||
if( entry->waitable == waitable )
|
||||
{
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: signaling waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
if( signal == Pause )
|
||||
{
|
||||
if( entry->running ) {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread running, pausing. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, entry->pause->handle );
|
||||
event_signal( entry->pause );
|
||||
} else {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread already paused. waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !entry->running ) {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread paused, resuming. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, entry->resume->handle );
|
||||
event_signal( entry->resume );
|
||||
}
|
||||
|
||||
if( signal == Stop ) {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: stopping thread. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, thread->sigterm->handle );
|
||||
thread_sigterm( thread );
|
||||
} else {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread already running. waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
}
|
||||
}
|
||||
|
||||
result = ERROR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_signal_waitable" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The schedulers waitable thread. Each scheduled item will have its own thread which
|
||||
* waits for either data to process or the threads signal to terminate.
|
||||
*/
|
||||
DWORD THREADCALL scheduler_waitable_thread( THREAD * thread )
|
||||
{
|
||||
HANDLE waitableHandles[3] = {0};
|
||||
WaitableEntry * entry = NULL;
|
||||
DWORD result = 0;
|
||||
BOOL terminate = FALSE;
|
||||
UINT signalIndex = 0;
|
||||
|
||||
if( thread == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
if( entry == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if( entry->routine == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if( schedulerThreadList == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
list_add( schedulerThreadList, thread );
|
||||
|
||||
waitableHandles[0] = thread->sigterm->handle;
|
||||
waitableHandles[1] = entry->pause->handle;
|
||||
waitableHandles[2] = entry->waitable;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_waitable_thread( 0x%08X )", thread );
|
||||
dprintf( "[SCHEDULER] waiting on term=0x%X pause=0x%X waitable=0x%X", waitableHandles[0], waitableHandles[1], waitableHandles[2] );
|
||||
|
||||
entry->running = TRUE;
|
||||
while( !terminate )
|
||||
{
|
||||
dprintf( "[SCHEDULER] About to wait ( 0x%08X )", thread );
|
||||
result = WaitForMultipleObjects( 3, waitableHandles, FALSE, INFINITE );
|
||||
dprintf( "[SCHEDULER] Wait returned ( 0x%08X )", thread );
|
||||
signalIndex = result - WAIT_OBJECT_0;
|
||||
switch( signalIndex )
|
||||
{
|
||||
case 0:
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to terminate...", thread );
|
||||
terminate = TRUE;
|
||||
break;
|
||||
case 1:
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to pause...", thread );
|
||||
entry->running = FALSE;
|
||||
event_poll( entry->resume, INFINITE );
|
||||
entry->running = TRUE;
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to resume...", thread );
|
||||
case 2:
|
||||
//dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled on waitable...", thread );
|
||||
entry->routine( entry->remote, entry->context, thread->parameter2 );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_waitable_thread( 0x%08X )", thread );
|
||||
|
||||
// we acquire the lock for this block as we are freeing 'entry' which may be accessed
|
||||
// in a second call to scheduler_signal_waitable for this thread (unlikely but best practice).
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
if( list_remove( schedulerThreadList, thread ) )
|
||||
{
|
||||
if( entry->destroy ) {
|
||||
entry->destroy( entry->waitable, entry->context, thread->parameter2 );
|
||||
}
|
||||
else if( entry->waitable ) {
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ) closing handle 0x%08X", thread, entry->waitable);
|
||||
CloseHandle( entry->waitable );
|
||||
}
|
||||
|
||||
event_destroy( entry->resume );
|
||||
event_destroy( entry->pause );
|
||||
thread_destroy( thread );
|
||||
free( entry );
|
||||
}
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
#include "common.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
typedef struct _WaitableEntry
|
||||
{
|
||||
Remote * remote;
|
||||
#ifdef _WIN32
|
||||
HANDLE waitable;
|
||||
#else
|
||||
int waitable;
|
||||
#endif
|
||||
EVENT* pause;
|
||||
EVENT* resume;
|
||||
LPVOID context;
|
||||
BOOL running;
|
||||
WaitableNotifyRoutine routine;
|
||||
WaitableDestroyRoutine destroy;
|
||||
} WaitableEntry;
|
||||
|
||||
/*
|
||||
* The list of all currenltly running threads in the scheduler subsystem.
|
||||
*/
|
||||
LIST * schedulerThreadList = NULL;
|
||||
|
||||
/*
|
||||
* The Remote that is associated with the scheduler subsystem
|
||||
*/
|
||||
Remote * schedulerRemote = NULL;
|
||||
|
||||
/*
|
||||
* Initialize the scheduler subsystem. Must be called before any calls to scheduler_insert_waitable.
|
||||
*/
|
||||
DWORD scheduler_initialize( Remote * remote )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_initialize." );
|
||||
|
||||
if( remote == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
schedulerThreadList = list_create();
|
||||
if( schedulerThreadList == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
schedulerRemote = remote;
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_initialize." );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the scheduler subsystem. All waitable threads at signaled to terminate.
|
||||
* this function blocks untill all waitable threads have terminated.
|
||||
*/
|
||||
DWORD scheduler_destroy( VOID )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
DWORD index = 0;
|
||||
DWORD count = 0;
|
||||
LIST * jlist = list_create();
|
||||
THREAD * thread = NULL;
|
||||
WaitableEntry * entry = NULL;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_destroy." );
|
||||
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
|
||||
count = list_count( schedulerThreadList );
|
||||
|
||||
for( index=0 ; index < count ; index++ )
|
||||
{
|
||||
thread = (THREAD *)list_get( schedulerThreadList, index );
|
||||
if( thread == NULL )
|
||||
continue;
|
||||
|
||||
list_push( jlist, thread );
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
|
||||
if( !entry->running )
|
||||
event_signal( entry->resume );
|
||||
|
||||
thread_sigterm( thread );
|
||||
}
|
||||
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, joining all waitable threads..." );
|
||||
|
||||
while( TRUE )
|
||||
{
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, popping off another item from thread list..." );
|
||||
|
||||
thread = (THREAD *)list_pop( jlist );
|
||||
if( thread == NULL )
|
||||
break;
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, joining thread 0x%08X...", thread );
|
||||
|
||||
thread_join( thread );
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] scheduler_destroy, destroying lists..." );
|
||||
|
||||
list_destroy( jlist );
|
||||
|
||||
list_destroy( schedulerThreadList );
|
||||
|
||||
schedulerThreadList = NULL;
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_destroy." );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new waitable thread for checking and processing.
|
||||
*/
|
||||
DWORD scheduler_insert_waitable( HANDLE waitable, LPVOID entryContext, LPVOID threadContext, WaitableNotifyRoutine routine, WaitableDestroyRoutine destroy )
|
||||
{
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
THREAD * swt = NULL;
|
||||
|
||||
WaitableEntry * entry = (WaitableEntry *)malloc( sizeof( WaitableEntry ) );
|
||||
if( entry == NULL )
|
||||
return ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_insert_waitable( 0x%08X, 0x%08X, 0x%08X, 0x%08X, 0x%08X )",
|
||||
waitable, entryContext, threadContext, routine, destroy );
|
||||
|
||||
memset( entry, 0, sizeof( WaitableEntry ) );
|
||||
|
||||
entry->remote = schedulerRemote;
|
||||
entry->waitable = waitable;
|
||||
entry->destroy = destroy;
|
||||
entry->context = entryContext;
|
||||
entry->routine = routine;
|
||||
entry->pause = event_create();
|
||||
entry->resume = event_create();
|
||||
|
||||
swt = thread_create( scheduler_waitable_thread, entry, threadContext, NULL );
|
||||
if( swt != NULL )
|
||||
{
|
||||
dprintf( "[SCHEDULER] created scheduler_waitable_thread 0x%08X", swt );
|
||||
thread_run( swt );
|
||||
}
|
||||
else
|
||||
{
|
||||
free( entry );
|
||||
result = ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_insert_waitable" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal a waitable object.
|
||||
*/
|
||||
DWORD scheduler_signal_waitable( HANDLE waitable, SchedularSignal signal )
|
||||
{
|
||||
DWORD index = 0;
|
||||
DWORD count = 0;
|
||||
THREAD * thread = NULL;
|
||||
WaitableEntry * entry = NULL;
|
||||
DWORD result = ERROR_NOT_FOUND;
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_signal_waitable( 0x%08X )", waitable );
|
||||
|
||||
if( schedulerThreadList == NULL || !waitable )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
|
||||
count = list_count( schedulerThreadList );
|
||||
|
||||
for( index=0 ; index < count ; index++ )
|
||||
{
|
||||
thread = (THREAD *)list_get( schedulerThreadList, index );
|
||||
if( thread == NULL )
|
||||
continue;
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
if( entry == NULL )
|
||||
continue;
|
||||
|
||||
if( entry->waitable == waitable )
|
||||
{
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: signaling waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
if( signal == Pause )
|
||||
{
|
||||
if( entry->running ) {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread running, pausing. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, entry->pause->handle );
|
||||
event_signal( entry->pause );
|
||||
} else {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread already paused. waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !entry->running ) {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread paused, resuming. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, entry->resume->handle );
|
||||
event_signal( entry->resume );
|
||||
}
|
||||
|
||||
if( signal == Stop ) {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: stopping thread. waitable = 0x%08X, thread = 0x%08X, handle = 0x%X", waitable, thread, thread->sigterm->handle );
|
||||
thread_sigterm( thread );
|
||||
} else {
|
||||
dprintf( "[SCHEDULER] scheduler_signal_waitable: thread already running. waitable = 0x%08X, thread = 0x%08X", waitable, thread );
|
||||
}
|
||||
}
|
||||
|
||||
result = ERROR_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_signal_waitable" );
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* The schedulers waitable thread. Each scheduled item will have its own thread which
|
||||
* waits for either data to process or the threads signal to terminate.
|
||||
*/
|
||||
DWORD THREADCALL scheduler_waitable_thread( THREAD * thread )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HANDLE waitableHandles[3] = {0};
|
||||
#else
|
||||
struct pollfd pollDetail = {0};
|
||||
#endif
|
||||
|
||||
WaitableEntry * entry = NULL;
|
||||
DWORD result = 0;
|
||||
BOOL terminate = FALSE;
|
||||
UINT signalIndex = 0;
|
||||
|
||||
if( thread == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
entry = (WaitableEntry *)thread->parameter1;
|
||||
if( entry == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if( entry->routine == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
if( schedulerThreadList == NULL )
|
||||
return ERROR_INVALID_HANDLE;
|
||||
|
||||
list_add( schedulerThreadList, thread );
|
||||
|
||||
#ifdef _WIN32
|
||||
waitableHandles[0] = thread->sigterm->handle;
|
||||
waitableHandles[1] = entry->pause->handle;
|
||||
waitableHandles[2] = entry->waitable;
|
||||
#else
|
||||
pollDetail.fd = entry->waitable;
|
||||
pollDetail.events = POLLRDNORM;
|
||||
pollDetail.revents = 0;
|
||||
#endif
|
||||
|
||||
dprintf( "[SCHEDULER] entering scheduler_waitable_thread( 0x%08X )", thread );
|
||||
|
||||
entry->running = TRUE;
|
||||
while( !terminate )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
dprintf( "[SCHEDULER] About to wait ( 0x%08X )", thread );
|
||||
result = WaitForMultipleObjects( 3, waitableHandles, FALSE, INFINITE );
|
||||
dprintf( "[SCHEDULER] Wait returned ( 0x%08X )", thread );
|
||||
signalIndex = result - WAIT_OBJECT_0;
|
||||
switch( signalIndex )
|
||||
{
|
||||
case 0:
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to terminate...", thread );
|
||||
terminate = TRUE;
|
||||
break;
|
||||
case 1:
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to pause...", thread );
|
||||
entry->running = FALSE;
|
||||
event_poll( entry->resume, INFINITE );
|
||||
entry->running = TRUE;
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to resume...", thread );
|
||||
case 2:
|
||||
//dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled on waitable...", thread );
|
||||
entry->routine( entry->remote, entry->context, thread->parameter2 );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if( event_poll( thread->sigterm, 0 ) ) {
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to terminate...", thread );
|
||||
terminate = TRUE;
|
||||
}
|
||||
else if( event_poll( entry->pause, 0 ) ) {
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to pause...", thread );
|
||||
entry->running = FALSE;
|
||||
while( !event_poll( entry->resume, 1000 ) );
|
||||
entry->running = TRUE;
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled to resume...", thread );
|
||||
}
|
||||
else if( poll( &pollDetail, 1, 100 ) == POLLIN ) {
|
||||
//dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ), signaled on waitable...", thread );
|
||||
entry->routine( entry->remote, entry->context, (LPVOID)thread->parameter2 );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
dprintf( "[SCHEDULER] leaving scheduler_waitable_thread( 0x%08X )", thread );
|
||||
|
||||
// we acquire the lock for this block as we are freeing 'entry' which may be accessed
|
||||
// in a second call to scheduler_signal_waitable for this thread (unlikely but best practice).
|
||||
lock_acquire( schedulerThreadList->lock );
|
||||
if( list_remove( schedulerThreadList, thread ) )
|
||||
{
|
||||
if( entry->destroy ) {
|
||||
entry->destroy( entry->waitable, entry->context, thread->parameter2 );
|
||||
}
|
||||
else if( entry->waitable ) {
|
||||
dprintf( "[SCHEDULER] scheduler_waitable_thread( 0x%08X ) closing handle 0x%08X", thread, entry->waitable);
|
||||
#ifdef _WIN32
|
||||
CloseHandle( entry->waitable );
|
||||
#else
|
||||
close( entry->waitable );
|
||||
#endif
|
||||
}
|
||||
|
||||
event_destroy( entry->resume );
|
||||
event_destroy( entry->pause );
|
||||
thread_destroy( thread );
|
||||
free( entry );
|
||||
}
|
||||
lock_release( schedulerThreadList->lock );
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user