channels/smartcard: add improve completed IRP management

This commit is contained in:
Marc-André Moreau 2014-05-07 17:41:53 -04:00
parent d53a9415ae
commit 67f691f90a
3 changed files with 122 additions and 13 deletions

View File

@ -35,6 +35,8 @@
#include "smartcard_main.h" #include "smartcard_main.h"
#define DEBUG_SMARTCARD_INIT 1
static BOOL g_SmartCardAsync = TRUE; static BOOL g_SmartCardAsync = TRUE;
static void smartcard_free(DEVICE* device) static void smartcard_free(DEVICE* device)
@ -51,6 +53,7 @@ static void smartcard_free(DEVICE* device)
MessageQueue_Free(smartcard->IrpQueue); MessageQueue_Free(smartcard->IrpQueue);
ListDictionary_Free(smartcard->rgSCardContextList); ListDictionary_Free(smartcard->rgSCardContextList);
ListDictionary_Free(smartcard->rgOutstandingMessages); ListDictionary_Free(smartcard->rgOutstandingMessages);
Queue_Free(smartcard->CompletedIrpQueue);
free(device); free(device);
} }
@ -62,6 +65,7 @@ static void smartcard_free(DEVICE* device)
static void smartcard_init(DEVICE* device) static void smartcard_init(DEVICE* device)
{ {
IRP* irp;
int index; int index;
int keyCount; int keyCount;
ULONG_PTR* pKeys; ULONG_PTR* pKeys;
@ -76,6 +80,16 @@ static void smartcard_init(DEVICE* device)
* be removed from rgSCardContextList. * be removed from rgSCardContextList.
*/ */
/**
* Step 1: Call SCardCancel on existing contexts, unblocking all outstanding IRPs.
*/
#ifdef DEBUG_SMARTCARD_INIT
printf("[1] rgSCardContextList: %d rgOutstandingMessages: %d\n",
ListDictionary_Count(smartcard->rgSCardContextList),
ListDictionary_Count(smartcard->rgOutstandingMessages));
#endif
if (ListDictionary_Count(smartcard->rgSCardContextList) > 0) if (ListDictionary_Count(smartcard->rgSCardContextList) > 0)
{ {
pKeys = NULL; pKeys = NULL;
@ -85,11 +99,73 @@ static void smartcard_init(DEVICE* device)
{ {
hContext = (SCARDCONTEXT) ListDictionary_GetItemValue(smartcard->rgSCardContextList, (void*) pKeys[index]); hContext = (SCARDCONTEXT) ListDictionary_GetItemValue(smartcard->rgSCardContextList, (void*) pKeys[index]);
if (SCardIsValidContext(hContext))
{
SCardCancel(hContext); SCardCancel(hContext);
} }
}
free(pKeys); free(pKeys);
} }
/**
* Step 2: Wait for all outstanding IRPs to complete.
*/
#ifdef DEBUG_SMARTCARD_INIT
printf("[2] rgSCardContextList: %d rgOutstandingMessages: %d\n",
ListDictionary_Count(smartcard->rgSCardContextList),
ListDictionary_Count(smartcard->rgOutstandingMessages));
#endif
if (ListDictionary_Count(smartcard->rgOutstandingMessages) > 0)
{
pKeys = NULL;
keyCount = ListDictionary_GetKeys(smartcard->rgOutstandingMessages, &pKeys);
for (index = 0; index < keyCount; index++)
{
irp = (IRP*) ListDictionary_GetItemValue(smartcard->rgOutstandingMessages, (void*) pKeys[index]);
ListDictionary_Remove(smartcard->rgOutstandingMessages, (void*) pKeys[index]);
}
free(pKeys);
}
/**
* Step 3: Call SCardReleaseContext on remaining contexts and remove them from rgSCardContextList.
*/
#ifdef DEBUG_SMARTCARD_INIT
printf("[3] rgSCardContextList: %d rgOutstandingMessages: %d\n",
ListDictionary_Count(smartcard->rgSCardContextList),
ListDictionary_Count(smartcard->rgOutstandingMessages));
#endif
if (ListDictionary_Count(smartcard->rgSCardContextList) > 0)
{
pKeys = NULL;
keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys);
for (index = 0; index < keyCount; index++)
{
hContext = (SCARDCONTEXT) ListDictionary_GetItemValue(smartcard->rgSCardContextList, (void*) pKeys[index]);
ListDictionary_Remove(smartcard->rgSCardContextList, (void*) pKeys[index]);
if (SCardIsValidContext(hContext))
{
SCardReleaseContext(hContext);
}
}
free(pKeys);
}
#ifdef DEBUG_SMARTCARD_INIT
printf("[4] rgSCardContextList: %d rgOutstandingMessages: %d\n",
ListDictionary_Count(smartcard->rgSCardContextList),
ListDictionary_Count(smartcard->rgOutstandingMessages));
#endif
} }
void smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) void smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
@ -110,6 +186,8 @@ void* smartcard_process_irp_worker_proc(IRP* irp)
smartcard_irp_device_control(smartcard, irp); smartcard_irp_device_control(smartcard, irp);
Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) irp);
ExitThread(0); ExitThread(0);
return NULL; return NULL;
} }
@ -162,6 +240,8 @@ void smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
if (!asyncIrp) if (!asyncIrp)
{ {
smartcard_irp_device_control(smartcard, irp); smartcard_irp_device_control(smartcard, irp);
Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) irp);
} }
else else
{ {
@ -174,22 +254,32 @@ void smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
{ {
fprintf(stderr, "Unexpected SmartCard IRP: MajorFunction 0x%08X MinorFunction: 0x%08X", fprintf(stderr, "Unexpected SmartCard IRP: MajorFunction 0x%08X MinorFunction: 0x%08X",
irp->MajorFunction, irp->MinorFunction); irp->MajorFunction, irp->MinorFunction);
irp->IoStatus = STATUS_NOT_SUPPORTED; irp->IoStatus = STATUS_NOT_SUPPORTED;
smartcard_complete_irp(smartcard, irp);
Queue_Enqueue(smartcard->CompletedIrpQueue, (void*) irp);
} }
} }
static void* smartcard_thread_func(void* arg) static void* smartcard_thread_func(void* arg)
{ {
IRP* irp; IRP* irp;
DWORD nCount;
DWORD status;
HANDLE hEvents[2];
wMessage message; wMessage message;
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) arg; SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) arg;
nCount = 0;
hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue);
hEvents[nCount++] = Queue_Event(smartcard->CompletedIrpQueue);
while (1) while (1)
{ {
if (!MessageQueue_Wait(smartcard->IrpQueue)) status = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
break;
if (WaitForSingleObject(MessageQueue_Event(smartcard->IrpQueue), 0) == WAIT_OBJECT_0)
{
if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE)) if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE))
break; break;
@ -199,8 +289,27 @@ static void* smartcard_thread_func(void* arg)
irp = (IRP*) message.wParam; irp = (IRP*) message.wParam;
if (irp) if (irp)
{
smartcard_process_irp(smartcard, irp); smartcard_process_irp(smartcard, irp);
} }
}
if (WaitForSingleObject(Queue_Event(smartcard->CompletedIrpQueue), 0) == WAIT_OBJECT_0)
{
irp = (IRP*) Queue_Dequeue(smartcard->CompletedIrpQueue);
if (irp)
{
if (irp->thread)
{
WaitForSingleObject(irp->thread, INFINITE);
CloseHandle(irp->thread);
}
smartcard_complete_irp(smartcard, irp);
}
}
}
ExitThread(0); ExitThread(0);
return NULL; return NULL;
@ -267,6 +376,7 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
smartcard->IrpQueue = MessageQueue_New(NULL); smartcard->IrpQueue = MessageQueue_New(NULL);
smartcard->rgSCardContextList = ListDictionary_New(TRUE); smartcard->rgSCardContextList = ListDictionary_New(TRUE);
smartcard->rgOutstandingMessages = ListDictionary_New(TRUE); smartcard->rgOutstandingMessages = ListDictionary_New(TRUE);
smartcard->CompletedIrpQueue = Queue_New(TRUE, -1, -1);
smartcard->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) smartcard_thread_func, smartcard->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) smartcard_thread_func,
smartcard, CREATE_SUSPENDED, NULL); smartcard, CREATE_SUSPENDED, NULL);

View File

@ -92,6 +92,7 @@ struct _SMARTCARD_DEVICE
HANDLE thread; HANDLE thread;
wMessageQueue* IrpQueue; wMessageQueue* IrpQueue;
wQueue* CompletedIrpQueue;
wListDictionary* rgSCardContextList; wListDictionary* rgSCardContextList;
wListDictionary* rgOutstandingMessages; wListDictionary* rgOutstandingMessages;
}; };

View File

@ -1350,6 +1350,4 @@ void smartcard_irp_device_control(SMARTCARD_DEVICE* smartcard, IRP* irp)
Stream_Write_UINT32(irp->output, result); /* Result (4 bytes) */ Stream_Write_UINT32(irp->output, result); /* Result (4 bytes) */
Stream_SetPosition(irp->output, Stream_Length(irp->output)); Stream_SetPosition(irp->output, Stream_Length(irp->output));
smartcard_complete_irp(smartcard, irp);
} }