1595 lines
24 KiB
C
1595 lines
24 KiB
C
/*++
|
|
|
|
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
|