You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
7.9 KiB
268 lines
7.9 KiB
#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);
|
|
};
|
|
|