/*++ Copyright (c) 1998-1999 Microsoft Corporation Module Name: t.c Abstract: Basic functionality tests for the RM APIs Revision History: Who When What -------- -------- ---------------------------------------------- josephj 01-13-99 Created Notes: --*/ #include "c.h" #ifdef TESTPROGRAM enum { LOCKLEVEL_GLOBALS=1, LOCKLEVEL_O1, LOCKLEVEL_O2 }; typedef struct { RM_OBJECT_HEADER Hdr; RM_LOCK Lock; // // Resources // BOOLEAN fInited1; // Resource1 BOOLEAN fInited2; // Resource2 // // Groups // RM_GROUP Group; } GLOBALS; //================================ O1 Information ================================== PRM_OBJECT_HEADER O1Create( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD psr ); VOID O1Delete( PRM_OBJECT_HEADER Obj, PRM_STACK_RECORD psr ); // // Hash table comparison function. // BOOLEAN O1CompareKey( PVOID pKey, PRM_HASH_LINK pItem ); // // Hash generating function. // ULONG O1Hash( PVOID pKey ); typedef struct { RM_OBJECT_HEADER Hdr; RM_LOCK Lock; UINT Key; BOOLEAN fInited; } O1; RM_HASH_INFO O1_HashInfo = { NULL, // pfnTableAllocator NULL, // pfnTableDeallocator O1CompareKey, // fnCompare // Function to generate a ULONG-sized hash. // O1Hash // pfnHash }; RM_STATIC_OBJECT_INFO O1_StaticInfo = { 0, // TypeUID 0, // TypeFlags "O1", // TypeName 0, // Timeout O1Create, O1Delete, NULL, // Verifier 0, // ResourceTable size NULL, // ResourceTable &O1_HashInfo, // pHashInfo }; //================================ O2 Information ================================== PRM_OBJECT_HEADER O2Create( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD psr ); VOID O2Delete( PRM_OBJECT_HEADER Obj, PRM_STACK_RECORD psr ); // // Hash table comparison function. // BOOLEAN O2CompareKey( PVOID pKey, PRM_HASH_LINK pItem ); // // Hash generating function. // ULONG O2Hash( PVOID pKey ); typedef struct { RM_OBJECT_HEADER Hdr; RM_LOCK Lock; UINT Key; BOOLEAN fInited; RM_TASK O2Task; } O2; RM_HASH_INFO O2_HashInfo = { NULL, // pfnTableAllocator NULL, // pfnTableDeallocator O2CompareKey, // fnCompare // Function to generate a ULONG-sized hash. // O2Hash // pfnHash }; RM_STATIC_OBJECT_INFO O2_StaticInfo = { 0, // TypeUID 0, // TypeFlags "O2", // TypeName 0, // Timeout O2Create, O2Delete, NULL, //verifier 0, // ResourceTable size NULL, // ResourceTable &O2_HashInfo, // pHashInfo }; //================================ GLOBALS (ROOT Object) Information ================= // // List of fixed resources used by ArpGlobals // enum { RTYPE_GLOBAL_RESOURCE1, RTYPE_GLOBAL_RESOURCE2 }; // ARP_GLOBAL_RESOURCES; RM_STATUS testResHandleGlobalResource1( PRM_OBJECT_HEADER pObj, RM_RESOURCE_OPERATION Op, PVOID pvUserParams, PRM_STACK_RECORD psr ); RM_STATUS testResHandleGlobalResource2( PRM_OBJECT_HEADER pObj, RM_RESOURCE_OPERATION Op, PVOID pvUserParams, PRM_STACK_RECORD psr ); VOID testTaskDelete ( PRM_OBJECT_HEADER pObj, PRM_STACK_RECORD psr ); // // Identifies information pertaining to the use of the above resources. // Following table MUST be in strict increasing order of the RTYPE_GLOBAL // enum. // RM_RESOURCE_TABLE_ENTRY Globals_ResourceTable[] = { {RTYPE_GLOBAL_RESOURCE1, testResHandleGlobalResource1}, {RTYPE_GLOBAL_RESOURCE2, testResHandleGlobalResource2} }; RM_STATIC_OBJECT_INFO Globals_StaticInfo = { 0, // TypeUID 0, // TypeFlags "Globals", // TypeName 0, // Timeout NULL, // pfnCreate NULL, // pfnDelete NULL, // verifier sizeof(Globals_ResourceTable)/sizeof(Globals_ResourceTable[1]), Globals_ResourceTable }; RM_STATIC_OBJECT_INFO Tasks_StaticInfo = { 0, // TypeUID 0, // TypeFlags "TEST Task", // TypeName 0, // Timeout NULL, // pfnCreate testTaskDelete, // pfnDelete NULL, // LockVerifier 0, // length of resource table NULL // Resource Table }; RM_STATIC_OBJECT_INFO O2Tasks_StaticInfo = { 0, // TypeUID 0, // TypeFlags "O2 Task", // TypeName 0, // Timeout NULL, // pfnCreate NULL, // pfnDelete NULL because it's contained in O2. NULL, // LockVerifier 0, // length of resource table NULL // Resource Table }; typedef struct { RM_TASK TskHdr; int i; } T1_TASK; typedef struct { RM_TASK TskHdr; int i; } T2_TASK; typedef struct { RM_TASK TskHdr; int i; } T3_TASK; typedef union { RM_TASK TskHdr; T1_TASK T1; T2_TASK T2; T3_TASK T3; } TESTTASK; GLOBALS Globals; RM_STATUS init_globals( PRM_STACK_RECORD psr ); VOID deinit_globals( PRM_STACK_RECORD psr ); NDIS_STATUS Task1 ( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Op, IN UINT_PTR UserParam, // Unused IN PRM_STACK_RECORD pSR ); NDIS_STATUS Task2 ( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, // Unused IN PRM_STACK_RECORD pSR ); NDIS_STATUS Task3 ( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, // Task to pend on. IN PRM_STACK_RECORD pSR ); NDIS_STATUS TaskO2 ( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Op, IN UINT_PTR UserParam, // Unused IN PRM_STACK_RECORD pSR ); NDIS_STATUS TaskUnloadO2 ( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Op, IN UINT_PTR UserParam, // Unused IN PRM_STACK_RECORD pSR ); NDIS_STATUS AllocateTask( IN PRM_OBJECT_HEADER pParentObject, IN PFN_RM_TASK_HANDLER pfnHandler, IN UINT Timeout, IN const char * szDescription, OUT PRM_TASK *ppTask, IN PRM_STACK_RECORD pSR ) { TESTTASK *pTTask = ALLOCSTRUCT(TESTTASK); NDIS_STATUS Status = NDIS_STATUS_RESOURCES; *ppTask = NULL; if (pTTask != NULL) { RmInitializeTask( &(pTTask->TskHdr), pParentObject, pfnHandler, &Tasks_StaticInfo, szDescription, Timeout, pSR ); *ppTask = &(pTTask->TskHdr); Status = NDIS_STATUS_SUCCESS; } return Status; } VOID FreeTask( IN PRM_TASK pTask, IN PRM_STACK_RECORD pSR ) { FREE(pTask); } PRM_OBJECT_HEADER O1Create( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD psr ) { O1 * po1 = ALLOCSTRUCT(O1); if (po1) { RmInitializeLock( &po1->Lock, LOCKLEVEL_O1 ); RmInitializeHeader( pParentObject, // NULL, // pParentObject, &po1->Hdr, 123, &po1->Lock, &O1_StaticInfo, NULL, psr ); po1->Key = (UINT) (UINT_PTR) pCreateParams; } return &po1->Hdr; } VOID O1Delete( PRM_OBJECT_HEADER Obj, PRM_STACK_RECORD psr ) { FREE(Obj); } PRM_OBJECT_HEADER O2Create( PRM_OBJECT_HEADER pParentObject, PVOID pCreateParams, PRM_STACK_RECORD pSR ) { O2 * po2 = ALLOCSTRUCT(O2); if (po2) { RmInitializeLock( &po2->Lock, LOCKLEVEL_O2 ); RmInitializeHeader( pParentObject, // NULL, // pParentObject, &po2->Hdr, 234, &po2->Lock, &O2_StaticInfo, NULL, pSR ); RmInitializeTask( &(po2->O2Task), &po2->Hdr, TaskO2, &O2Tasks_StaticInfo, "TaskO2", 0, pSR ); po2->Key = (UINT) (UINT_PTR) pCreateParams; } return &po2->Hdr; } VOID O2Delete( PRM_OBJECT_HEADER Obj, PRM_STACK_RECORD psr ) { FREE(Obj); } RM_STATUS testResHandleGlobalResource1( PRM_OBJECT_HEADER pObj, RM_RESOURCE_OPERATION Op, PVOID pvUserParams, PRM_STACK_RECORD psr ) { NDIS_STATUS Status = NDIS_STATUS_FAILURE; GLOBALS *pGlobals = CONTAINING_RECORD(pObj, GLOBALS, Hdr); ENTER("GlobalResource1", 0xd7c1efbb); if (Op == RM_RESOURCE_OP_LOAD) { TR_INFO(("LOADING RESOUCE1\n")); pGlobals->fInited1 = TRUE; Status = NDIS_STATUS_SUCCESS; } else if (Op == RM_RESOURCE_OP_UNLOAD) { TR_INFO(("UNLOADING RESOUCE1\n")); // // Were unloading this "resource." // ASSERTEX(pGlobals->fInited1, pGlobals); pGlobals->fInited1 = FALSE; // Always return success on unload. // Status = NDIS_STATUS_SUCCESS; } else { // Unexpected op code. // ASSERTEX(FALSE, pObj); } EXIT() return Status; } RM_STATUS testResHandleGlobalResource2( PRM_OBJECT_HEADER pObj, RM_RESOURCE_OPERATION Op, PVOID pvUserParams, PRM_STACK_RECORD psr ) { NDIS_STATUS Status = NDIS_STATUS_FAILURE; GLOBALS *pGlobals = CONTAINING_RECORD(pObj, GLOBALS, Hdr); ENTER("GlobalResource2", 0xca85474f) if (Op == RM_RESOURCE_OP_LOAD) { TR_INFO(("LOADING RESOUCE2\n")); pGlobals->fInited2 = TRUE; Status = NDIS_STATUS_SUCCESS; } else if (Op == RM_RESOURCE_OP_UNLOAD) { TR_INFO(("UNLOADING RESOUCE2\n")); // // Were unloading this "resource." // ASSERTEX(pGlobals->fInited2, pGlobals); pGlobals->fInited2 = FALSE; // Always return success on unload. // Status = NDIS_STATUS_SUCCESS; } else { // Unexpected op code. // ASSERTEX(FALSE, pObj); } EXIT() return Status; } RM_STATUS init_globals( PRM_STACK_RECORD psr ) { NDIS_STATUS Status; // // Initialize the global, statically-allocated object Globals; // RmInitializeLock( &Globals.Lock, LOCKLEVEL_GLOBALS ); RmInitializeHeader( NULL, // pParentObject, &Globals.Hdr, 001, &Globals.Lock, &Globals_StaticInfo, NULL, psr ); // // Load resource1 // Status = RmLoadGenericResource( &Globals.Hdr, RTYPE_GLOBAL_RESOURCE1, psr ); if (!FAIL(Status)) { // // Load resource1 // Status = RmLoadGenericResource( &Globals.Hdr, RTYPE_GLOBAL_RESOURCE2, psr ); } return Status; } VOID deinit_globals( PRM_STACK_RECORD psr ) { RmUnloadGenericResource( &Globals.Hdr, RTYPE_GLOBAL_RESOURCE1, psr ); RmUnloadAllGenericResources( &Globals.Hdr, psr ); RmDeallocateObject( &Globals.Hdr, psr ); } // // Hash comparision function. // BOOLEAN O1CompareKey( PVOID pKey, PRM_HASH_LINK pItem ) { O1 *pO1 = CONTAINING_RECORD(pItem, O1, Hdr.HashLink); return *((UINT*)pKey) == pO1->Key; } // // Hash generating function. // ULONG O1Hash( PVOID pKey ) { return *(UINT*)pKey; } // // Hash comparision function. // BOOLEAN O2CompareKey( PVOID pKey, PRM_HASH_LINK pItem ) { O2 *pO2 = CONTAINING_RECORD(pItem, O2, Hdr.HashLink); return *((UINT*)pKey) == pO2->Key; } // // Hash generating function. // ULONG O2Hash( PVOID pKey ) { return *(UINT*)pKey; } VOID testTaskDelete ( PRM_OBJECT_HEADER pObj, PRM_STACK_RECORD psr ) { printf("testTaskDelete: Called to delete obj %p\n", pObj); } NDIS_STATUS Task1( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, // Unused IN PRM_STACK_RECORD pSR ) // // DONE // { NDIS_STATUS Status = NDIS_STATUS_FAILURE; O1* po1 = (O1*) RM_PARENT_OBJECT(pTask); ENTER("Task1", 0x4abf3903) switch(Code) { case RM_TASKOP_START: printf("Task1: START called\n"); Status = NDIS_STATUS_SUCCESS; break; case RM_TASKOP_END: printf("Task1: END called\n"); Status = (NDIS_STATUS) UserParam; break; default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RM_ASSERT_NOLOCKS(pSR); EXIT() return Status; } NDIS_STATUS Task2( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, // Unused IN PRM_STACK_RECORD pSR ) // // DONE // { NDIS_STATUS Status = NDIS_STATUS_FAILURE; O1* po1 = (O1*) RM_PARENT_OBJECT(pTask); ENTER("Task2", 0x6e65b76c) // Following are the list of pending states for this task. // enum { PEND_OnStart }; switch(Code) { case RM_TASKOP_START: { printf("Task2: START called\n"); RmSuspendTask(pTask, PEND_OnStart, pSR); RM_ASSERT_NOLOCKS(pSR); Status = NDIS_STATUS_PENDING; } break; case RM_TASKOP_PENDCOMPLETE: { switch(RM_PEND_CODE(pTask)) { case PEND_OnStart: { printf("Task2: PEND_OnStart complete\n"); Status = (NDIS_STATUS) UserParam; // Status of the completed operation can't itself be pending! // ASSERT(Status != NDIS_STATUS_PENDING); } // end case PEND_OnStart break; default: { ASSERTEX(!"Unknown pend op", pTask); } break; } // end switch(RM_PEND_CODE(pTask)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { printf("Task2: END called\n"); Status = (NDIS_STATUS) UserParam; } break; default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RM_ASSERT_NOLOCKS(pSR); EXIT() return Status; } NDIS_STATUS Task3( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, IN PRM_STACK_RECORD pSR ) { NDIS_STATUS Status = NDIS_STATUS_FAILURE; O1* po1 = (O1*) RM_PARENT_OBJECT(pTask); T3_TASK *pT3Task = (T3_TASK *) pTask; ENTER("Task3", 0x7e89bf6d) // Following are the list of pending states for this task. // enum { PEND_OnStart }; printf ("pT3Task.i = %d\n", pT3Task->i); switch(Code) { case RM_TASKOP_START: { PRM_TASK pOtherTask = (PRM_TASK) UserParam; printf("Task3: START called\n"); RmPendTaskOnOtherTask(pTask, PEND_OnStart, pOtherTask, pSR); RM_ASSERT_NOLOCKS(pSR); Status = NDIS_STATUS_PENDING; } break; case RM_TASKOP_PENDCOMPLETE: { switch(RM_PEND_CODE(pTask)) { case PEND_OnStart: { printf("Task3: PEND_OnStart complete\n"); Status = (NDIS_STATUS) UserParam; // Status of the completed operation can't itself be pending! // ASSERT(Status != NDIS_STATUS_PENDING); } // end case PEND_OnStart break; default: { ASSERTEX(!"Unknown pend op", pTask); } break; } // end switch(RM_PEND_CODE(pTask)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { printf("Task3: END called\n"); Status = (NDIS_STATUS) UserParam; } break; default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RM_ASSERT_NOLOCKS(pSR); EXIT() return Status; } NDIS_STATUS TaskO2( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, // Unused IN PRM_STACK_RECORD pSR ) // // DONE // { NDIS_STATUS Status = NDIS_STATUS_FAILURE; O2* po2 = (O2*) RM_PARENT_OBJECT(pTask); ENTER("TaskO2", 0xe10fbc33) // Following are the list of pending states for this task. // enum { PEND_OnStart }; ASSERT(po2 == CONTAINING_RECORD(pTask, O2, O2Task)); switch(Code) { case RM_TASKOP_START: { printf("TaskO2: START called\n"); RmSuspendTask(pTask, PEND_OnStart, pSR); RM_ASSERT_NOLOCKS(pSR); Status = NDIS_STATUS_PENDING; } break; case RM_TASKOP_PENDCOMPLETE: { switch(RM_PEND_CODE(pTask)) { case PEND_OnStart: { printf("TaskO2: PEND_OnStart complete\n"); Status = (NDIS_STATUS) UserParam; // Status of the completed operation can't itself be pending! // ASSERT(Status != NDIS_STATUS_PENDING); } // end case PEND_OnStart break; default: { ASSERTEX(!"Unknown pend op", pTask); } break; } // end switch(RM_PEND_CODE(pTask)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { printf("TaskO2: END called\n"); Status = (NDIS_STATUS) UserParam; } break; default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RM_ASSERT_NOLOCKS(pSR); EXIT() return Status; } NDIS_STATUS TaskUnloadO2( IN struct _RM_TASK * pTask, IN RM_TASK_OPERATION Code, IN UINT_PTR UserParam, // Unused IN PRM_STACK_RECORD pSR ) // // DONE // { NDIS_STATUS Status = NDIS_STATUS_FAILURE; O2* po2 = (O2*) RM_PARENT_OBJECT(pTask); ENTER("TaskUnloadO2", 0xa15314da) // Following are the list of pending states for this task. // enum { PEND_OnStart }; switch(Code) { case RM_TASKOP_START: { printf("TaskTaskO2: START called\n"); RmPendTaskOnOtherTask(pTask, PEND_OnStart, &po2->O2Task, pSR); RmResumeTask(&po2->O2Task, 0, pSR); RM_ASSERT_NOLOCKS(pSR); Status = NDIS_STATUS_PENDING; } break; case RM_TASKOP_PENDCOMPLETE: { switch(RM_PEND_CODE(pTask)) { case PEND_OnStart: { printf("TaskUnloadO2: PEND_OnStart complete\n"); Status = (NDIS_STATUS) UserParam; // Status of the completed operation can't itself be pending! // ASSERT(Status != NDIS_STATUS_PENDING); } // end case PEND_OnStart break; default: { ASSERTEX(!"Unknown pend op", pTask); } break; } // end switch(RM_PEND_CODE(pTask)) } // case RM_TASKOP_PENDCOMPLETE break; case RM_TASKOP_END: { printf("TaskUnloadO2: END called\n"); // Actually free object po2 in group. // RmFreeObjectInGroup( &Globals.Group, &po2->Hdr, NULL, // pTask pSR ); Status = (NDIS_STATUS) UserParam; } break; default: { ASSERTEX(!"Unexpected task op", pTask); } break; } // switch (Code) RM_ASSERT_NOLOCKS(pSR); EXIT() return Status; } struct { BOOLEAN fInited; PRM_GROUP pGroup; // Following is a dummy stack record. It needs to be initialized before // it can be used. // struct { RM_LOCKING_INFO rm_lock_array[4]; RM_STACK_RECORD sr; RM_LOCK Lock; } SrInfo; } gDummys; void init_dummy_vars(void) { RM_STATUS Status; O2 * po2 = NULL; O2 * po2A = NULL; PRM_TASK pTask3a=NULL; PRM_TASK pTask3b=NULL; RM_DECLARE_STACK_RECORD(sr) printf("\nEnter init_dummy_vars\n\n");; // Must be done before any RM apis are used. // RmInitializeRm(); do { UINT Key = 1234; Status = init_globals(&sr); if (FAIL(Status)) break; gDummys.fInited = TRUE; // Initialize the dummy stack info and the lock for it to use. // { // True Init // gDummys.SrInfo.sr.TmpRefs = 0; gDummys.SrInfo.sr.LockInfo.CurrentLevel = 0; gDummys.SrInfo.sr.LockInfo.pFirst = rm_lock_array; gDummys.SrInfo.sr.LockInfo.pNextFree = rm_lock_array; gDummys.SrInfo.sr.LockInfo.pLast = rm_lock_array + sizeof(rm_lock_array)/sizeof(*rm_lock_array) - 1; RM_INIT_DBG_STACK_RECORD(gDummys.SrInfo.sr, 0); // Add some bogus temp refs. // gDummys.SrInfo.sr.TmpRefs = 0x123; // Now initialize the lock... RmInitializeLock( &gDummys.SrInfo.Lock, 0x345 // locklevel. ); // And lock // WARNING: we use the private function rmLock defined internal // to rm.c. // { VOID rmLock( PRM_LOCK pLock, #if RM_EXTRA_CHECKING UINT uLocID, PFNLOCKVERIFIER pfnVerifier, PVOID pVerifierContext, #endif //RM_EXTRA_CHECKING PRM_STACK_RECORD pSR ); rmLock( &gDummys.SrInfo.Lock, #if RM_EXTRA_CHECKING 0, // uLocID, NULL, // pfnVerifier, NULL, // pVerifierContext, #endif //RM_EXTRA_CHECKING &gDummys.SrInfo.sr ); } } RmInitializeGroup( &Globals.Hdr, &O2_StaticInfo, &Globals.Group, "O1 Group", &sr ); printf("Called RmInitializeGroup\n"); Status = RM_CREATE_AND_LOCK_OBJECT_IN_GROUP( &Globals.Group, &Key, // Key (PVOID)Key, // CreateParams (RM_OBJECT_HEADER**) &po2, NULL, // pfCreated &sr); if (FAIL(Status)) { printf("Create object in group failed!\n"); po2 = NULL; } else { UINT KeyA = 2345; printf("Create 1st object in group succeeded!\n"); UNLOCKOBJ(po2, &sr); // Now start the O2Task, which will pend ... // Status = RmStartTask( &po2->O2Task, 0, // UserParam (unused) &sr ); ASSERT(PEND(Status)); RmTmpDereferenceObject(&po2->Hdr, &sr); // Added in lookup. Status = RM_CREATE_AND_LOCK_OBJECT_IN_GROUP( &Globals.Group, &KeyA, // Key (PVOID)KeyA, // CreateParams (RM_OBJECT_HEADER**) &po2A, NULL, // pfCreated &sr); if (FAIL(Status)) { printf("Create 2nd object in group failed!\n"); po2A = NULL; } else { printf("Create 2nd object in group succeeded!\n"); UNLOCKOBJ(po2A, &sr); // Now start the O2Task, which will pend ... // Status = RmStartTask( &po2A->O2Task, 0, // UserParam (unused) &sr ); ASSERT(PEND(Status)); RmTmpDereferenceObject(&po2A->Hdr, &sr); } } // // Now let's start a couple of T3 tasks, to both pend on // &po2->O2Task. // if (po2 != NULL) { Status = AllocateTask( &po2->Hdr, // pParentObject Task3, // pfnHandler 0, // Timeout "Task3a", &pTask3a, &sr ); if (FAIL(Status)) { pTask3a = NULL; } else { Status = RmStartTask( pTask3a, (UINT_PTR) &po2->O2Task, // UserParam &sr ); ASSERT(Status == NDIS_STATUS_PENDING); } Status = AllocateTask( &po2->Hdr, // pParentObject Task3, // pfnHandler 0, // Timeout "Task3b", &pTask3b, &sr ); if (FAIL(Status)) { pTask3b = NULL; } else { Status = RmStartTask( pTask3b, (UINT_PTR) &po2->O2Task, // UserParam &sr ); ASSERT(Status == NDIS_STATUS_PENDING); } // Add some log entries. // RmDbgLogToObject( &po2->Hdr, NULL, // szPrefix "How now brown cow: pO2=%p, szDesc=%s\n", (UINT_PTR) po2, (UINT_PTR) po2->Hdr.szDescription, 0, 0, NULL, NULL ); RM_ASSERT_NOLOCKS(&sr); } printf( "DUMMY: pGroup=0x%p; po2=0x%p; po2A=0x%p\n", &Globals.Group, po2, po2A ); if (po2 && po2A) { printf( "DUMMY: po2->pTask=0x%p; po2A->pTask=0x%p\n", &po2->O2Task, &po2A->O2Task ); printf( "DUMMY: pTask3a=0x%p; pTask3b=0x%p; pSR=0x%p\n", pTask3a, pTask3b, &gDummys.SrInfo.sr ); } gDummys.pGroup = &Globals.Group; } while(FALSE); RM_ASSERT_CLEAR(&sr); printf("\nLeaving init_dummy_vars\n\n");; } void delete_dummy_vars(void) { RM_STATUS Status; O1 * po1; RM_DECLARE_STACK_RECORD(sr) printf("\nEnter delete_dummy_vars\n\n");; do { if (!gDummys.fInited) break; RmUnloadAllObjectsInGroup( gDummys.pGroup, AllocateTask, TaskUnloadO2, NULL, NULL, // pTask 0, // uTaskPendCode &sr ); RmDeinitializeGroup( gDummys.pGroup, &sr ); deinit_globals(&sr); } while(FALSE); // Must be done after all RM apis are complete. // RmDeinitializeRm(); RM_ASSERT_CLEAR(&sr); printf("\nLeaving delete_dummy_vars\n"); } VOID NdisInitializeWorkItem( IN PNDIS_WORK_ITEM pWorkItem, IN NDIS_PROC Routine, IN PVOID Context ) { ZeroMemory(pWorkItem, sizeof(*pWorkItem)); pWorkItem->Context = Context; pWorkItem->Routine = Routine; } VOID ApcProc_ScheduleWorkItem( ULONG_PTR Param ) { PNDIS_WORK_ITEM pWI = (PNDIS_WORK_ITEM) Param; pWI->Routine(pWI, pWI->Context); } NDIS_STATUS NdisScheduleWorkItem( IN PNDIS_WORK_ITEM WorkItem ) { DWORD dwRet = QueueUserAPC( ApcProc_ScheduleWorkItem, GetCurrentThread(), (UINT_PTR) WorkItem ); return dwRet ? NDIS_STATUS_SUCCESS: NDIS_STATUS_FAILURE; } VOID NdisInitializeTimer( IN OUT PNDIS_TIMER pTimer, IN PNDIS_TIMER_FUNCTION TimerFunction, IN PVOID FunctionContext ) { ZeroMemory(pTimer, sizeof(*pTimer)); pTimer->hTimer = CreateWaitableTimer( NULL, // lpTimerAttributes TRUE, // bManualReset NULL //lpTimerName ); ASSERT(pTimer->hTimer != NULL); pTimer->pfnHandler = TimerFunction; pTimer->Context = FunctionContext; } VOID CALLBACK TimerAPCProc_NdisSetTimer( LPVOID lpArgToCompletionRoutine, // data value DWORD dwTimerLowValue, // timer low value DWORD dwTimerHighValue // timer high value ) { PNDIS_TIMER pTimer = (PNDIS_TIMER) lpArgToCompletionRoutine; pTimer->pfnHandler( NULL, // SystemSpecific1 pTimer->Context, // FunctionContext NULL, // SystemSpecific2 NULL // SystemSpecific3 ); } VOID NdisSetTimer( IN PNDIS_TIMER pTimer, IN UINT MillisecondsToDelay ) { BOOL fRet; LARGE_INTEGER DueTime; DueTime.QuadPart = Int32x32To64( (INT) MillisecondsToDelay, -10000 // convert to 100-nanosec, specify relative time ); fRet = SetWaitableTimer( pTimer->hTimer, // handle to a timer object &DueTime, // when timer will become signaled 0, // periodic timer interval TimerAPCProc_NdisSetTimer, // completion routine pTimer, // data for completion routine FALSE // flag for resume state ); ASSERT(fRet); } VOID NdisCancelTimer( IN PNDIS_TIMER Timer, OUT PBOOLEAN TimerCancelled ) { ASSERT(FALSE); } #endif // TESTPROGRAM