Windows2003-3790/drivers/smartcrd/gempc430/thread.cpp
2020-09-30 16:53:55 +02:00

269 lines
7.9 KiB
C++

#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);
};