|
|
#include "thread.h"
// Thread callback...
#pragma LOCKEDCODE
VOID CThread::ThreadFunction(CThread* Thread) { if(Thread) Thread->ThreadRoutine(NULL); }
#pragma PAGEDCODE
VOID CThread::ThreadRoutine(PVOID context) { NTSTATUS status; TRACE("================= STARTING THREAD %8.8lX ===============\n", thread);
// Wait for a request to Start pooling or for
// someone to kill this thread.
PVOID mainevents[] = {(PVOID) &evKill,(PVOID) &evStart}; PVOID pollevents[] = {(PVOID) &evKill,(PVOID) timer->getHandle(),(PVOID) &smOnDemandStart};
ASSERT(arraysize(mainevents) <= THREAD_WAIT_OBJECTS); ASSERT(arraysize(pollevents) <= THREAD_WAIT_OBJECTS);
BOOLEAN kill = FALSE; while (!kill && thread) { // until told to start or to quit
ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL);
// Before going to thread routine thread considered to be Idle
if(event) event->set(&evIdle, IO_NO_INCREMENT, FALSE); status = event->waitForMultipleObjects(arraysize(mainevents), mainevents, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
if(!NT_SUCCESS(status)) { // error in wait
TRACE("Thread: waitForMultipleObjects failed - %X\n", status); break; } if (status == STATUS_WAIT_0) { DEBUG_START(); TRACE("Request to kill thread arrived...\n"); TRACE("================= KILLING THREAD! ===============\n"); break; // kill event was set
}
// Starting the timer with a zero due time will cause us to perform the
// first poll immediately. Thereafter, polls occur at the POLLING_INTERVAL
// interval (measured in milliseconds).
// Now thread is busy...
if(event) event->clear(&evIdle);
LARGE_INTEGER duetime = {0};// Signal timer right away!
timer->set(duetime, PoolingTimeout, NULL); while (TRUE) { // Block until time to poll again
ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL); status = event->waitForMultipleObjects(arraysize(pollevents), pollevents, WaitAny, Executive, KernelMode, FALSE, NULL, NULL); if (!NT_SUCCESS(status)) { // error in wait
DEBUG_START(); TRACE("CTread - waitForMultipleObjects failed - %X\n", status); TRACE("================= KILLING THREAD! ===============\n"); timer->cancel(); kill = TRUE; break; } if (status == STATUS_WAIT_0) { // told to quit
DEBUG_START(); TRACE("Loop: Request to kill thread arrived...\n"); TRACE("================= KILLING THREAD! ===============\n"); timer->cancel(); status = STATUS_DELETE_PENDING; kill = TRUE; break; } //if(device)
if(pfClientThreadFunction) { if(StopRequested) break; // Do device specific thread processing...
//TRACE("Calling thread %8.8lX function...\n",thread);
if(status = pfClientThreadFunction(ClientContext)) { TRACE("Device reported error %8.8lX\n",status); timer->cancel(); break; } } else { DEBUG_START(); TRACE("================= THREAD FUNCTION POINTER IS NOT SET!! FINISHED... ===============\n"); TRACE("================= KILLING THREAD! ===============\n"); status = STATUS_DELETE_PENDING; kill = TRUE; break; } } }// until told to quit
TRACE(" Leaving thread %8.8lX...\n", thread); if(event) event->set(&evIdle, IO_NO_INCREMENT, FALSE); if(event) event->set(&evStopped, IO_NO_INCREMENT, FALSE); if(semaphore) semaphore->initialize(&smOnDemandStart, 0, MAXLONG); if(system) system->terminateSystemThread(STATUS_SUCCESS); }
#pragma PAGEDCODE
CThread::CThread(PCLIENT_THREAD_ROUTINE ClientThreadFunction,PVOID ClientContext, ULONG delay) { // StartPollingThread for the device
NTSTATUS status; HANDLE hthread; m_Status = STATUS_INSUFFICIENT_RESOURCES; //this->device = device;
// Create objects..
event = kernel->createEvent(); system = kernel->createSystem(); timer = kernel->createTimer(SynchronizationTimer); semaphore = kernel->createSemaphore();
debug = kernel->createDebug();
StopRequested = FALSE; ThreadActive = FALSE; if(ALLOCATED_OK(event)) { event->initialize(&evKill, NotificationEvent, FALSE); event->initialize(&evStart, SynchronizationEvent, FALSE); event->initialize(&evStopped, NotificationEvent, FALSE); event->initialize(&evIdle, NotificationEvent, TRUE); } // At the begining there is no request to start,
// so semaphore is not at signal state.
if(ALLOCATED_OK(semaphore)) semaphore->initialize(&smOnDemandStart, 0, MAXLONG); pfClientThreadFunction = ClientThreadFunction; this->ClientContext = ClientContext; PoolingTimeout = delay; // Default thread pooling interval...
// Create system thread object...
status = system->createSystemThread(&hthread, THREAD_ALL_ACCESS, NULL, NULL, NULL, (PKSTART_ROUTINE) ThreadFunction, this); if(NT_SUCCESS(status)) // Get thread pointer...
{ thread = NULL; status = system->referenceObjectByHandle(hthread, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID*) &thread, NULL); if(!NT_SUCCESS(status)) { TRACE("FAILED TO REFERENCE OBJECT! Error %8.8lX\n", status); } } else TRACE("FAILED TO CREATE SYSTEM THREAD! Error %8.8lX\n", status);
system->ZwClose(hthread); if(NT_SUCCESS(status) && ALLOCATED_OK(event)&& ALLOCATED_OK(system)&& ALLOCATED_OK(timer)&& ALLOCATED_OK(semaphore) && thread) m_Status = STATUS_SUCCESS; } // StartPollingThread
#pragma PAGEDCODE
CThread::~CThread() { // StopPollingThread
DEBUG_START(); TRACE("Terminating thread %8.8lX...\n", thread); if(event) event->set(&evKill, IO_NO_INCREMENT, FALSE); StopRequested = TRUE; //device = NULL;
if (thread) { // wait for the thread to die
if(system && event) { ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL); event->waitForSingleObject(&evStopped, Executive, KernelMode, FALSE, NULL); if(!isWin98()) event->waitForSingleObject(thread, Executive, KernelMode, FALSE, NULL); system->dereferenceObject(thread); thread = NULL; } } TRACE("Thread terminated...\n");
if(event) event->dispose(); if(system) system->dispose(); if(timer) timer->dispose(); if(semaphore) semaphore->dispose();
if(debug) debug->dispose(); }
#pragma PAGEDCODE
VOID CThread::kill() { DEBUG_START(); TRACE("Killing thread %8.8lX...\n", thread); StopRequested = TRUE;
if(system) { ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL); } if(event) event->set(&evKill, IO_NO_INCREMENT, FALSE); if(event) event->waitForSingleObject(&evStopped, Executive, KernelMode, FALSE, NULL); }
#pragma PAGEDCODE
VOID CThread::start() { DEBUG_START(); TRACE("Starting thread %8.8lX...\n", thread); if(system) { ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL); } StopRequested = FALSE; ThreadActive = TRUE; // Start Card pooling...
if(event) event->set(&evStart, IO_NO_INCREMENT, FALSE); }
#pragma PAGEDCODE
VOID CThread::stop() { DEBUG_START(); TRACE("Stop thread %8.8lX...\n", thread); StopRequested = TRUE; ThreadActive = FALSE; if(system) { ASSERT(system->getCurrentIrql()<=DISPATCH_LEVEL); } if(event) event->clear(&evStart); // Unblock thread if it is blocked...
if(semaphore) semaphore->release(&smOnDemandStart,0,1,FALSE); // Wait for for the thread to go to the idle state...
if(event) event->waitForSingleObject(&evIdle, Executive, KernelMode, FALSE, NULL); // Stop thread ...
if(semaphore) semaphore->initialize(&smOnDemandStart, 0, MAXLONG); }
#pragma PAGEDCODE
BOOL CThread::isThreadActive() { return ThreadActive; }
#pragma PAGEDCODE
VOID CThread::setPoolingInterval(ULONG delay) { PoolingTimeout = delay; };
#pragma PAGEDCODE
VOID CThread::callThreadFunction() { // This will force thread function to be called right away.
// Useful if we want to update some information or
// start some processing without waiting for the pooling
// timeout to occure.
if(semaphore) semaphore->release(&smOnDemandStart,0,1,FALSE); };
|