📄 objdisp.c
字号:
/* Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved. */
/*+
objdisp.c - object call dispatch routines.
This file contains the routines for dispatching method calls to objects
implemented by protected system libraries, direct kernel functions,
and kernel mode threads.
*/
#include "kernel.h"
#include "xtime.h"
#include "winsock.h"
#ifdef XTIME //XTIME
void SyscallTime(DWORD); //XTIME record exception elapsed time
#endif //XTIME
void SC_CloseAPISet(HANDLE hSet);
BOOL SC_RegisterAPISet(HANDLE hSet, DWORD dwSetID);
LPVOID SC_VerifyAPIHandle(HANDLE hSet, HANDLE h);
void GoToUserTime(void);
void GoToKernTime(void);
extern CRITICAL_SECTION LLcs;
const PFNVOID APISetMethods[] = {
(PFNVOID)SC_CloseAPISet,
(PFNVOID)SC_NotSupported,
(PFNVOID)SC_RegisterAPISet,
(PFNVOID)SC_CreateAPIHandle,
(PFNVOID)SC_VerifyAPIHandle,
};
const CINFO cinfAPISet = {
"APIS",
DISPATCH_KERNEL_PSL,
HT_APISET,
sizeof(APISetMethods)/sizeof(APISetMethods[0]),
APISetMethods,
};
// Head of double linked list of active handles in the system.
DList HandleList = { &HandleList, &HandleList };
// Serial # for handle values.
unsigned int HandleSerial;
// Array of pointers to system api sets.
const CINFO *SystemAPISets[NUM_SYSTEM_SETS];
// Find a process index from an access lock.
int IndexFromLock(ulong lock)
{
ulong mask;
int inxRet;
int inx;
mask = 0x0000FFFFul;
for (inxRet = 0, inx = 16 ; inx ; inx >>= 1, mask >>= inx) {
if ((lock & mask) == 0) {
inxRet += inx;
lock >>= inx;
}
}
return inxRet;
}
// Insert an item into a double linked list
void AddToDList(DList *head, DList *item)
{
item->back = head;
item->fwd = head->fwd;
head->fwd->back = item;
head->fwd = item;
}
// Remove an item from a double linked list
void RemoveDList(DList *item)
{
item->fwd->back = item->back;
item->back->fwd = item->fwd;
}
// Convert a HANDLE to an HDATA pointer.
//
// HandleToPointer() is a function which can be used by other kernel modules.
//
// h2p() is an private macro used to speed up the internal processing of
// ObjectCall() and the various GetXXX/SetXXX functions.
#define h2p(h, phdRet) \
do { \
if ((ulong)h < NUM_SYS_HANDLES+SYS_HANDLE_BASE && (ulong)h >= SYS_HANDLE_BASE) \
h = KData.ahSys[(uint)h-SYS_HANDLE_BASE]; \
if (h) { \
phdRet = (PHDATA)(((ulong)h & HANDLE_ADDRESS_MASK) + KData.handleBase); \
if (!IsValidKPtr(phdRet) || phdRet->hValue != h) \
phdRet = 0; \
} else \
phdRet = 0; \
} while (0)
PHDATA HandleToPointer(HANDLE h)
{
PHDATA phdRet;
h2p(h, phdRet);
return phdRet;
}
// Return the next handle to close.
//
// The active handle list is scanned for a handle which is referenced by the process
// whose procnum is (id). (hLast) is the previous return value from this
// routine. If a handle is found, its reference count for the process is forced
// to 1 so that it will be closed by a single call to CloseHandle(). To speed up the
// iterative process of scanning the entire table, a pointer to the next handle in
// the list is retained. The next call will use that value if the list is unchanged,
// except for the possible freeing of the handle previously returned. If the list
// has changed, the scan will restart at the beginning of the list.
//
//NOTE: This function is called via KCall().
PHDATA PhdPrevReturn, PhdNext;
PHDATA NextCloseHandle(PHDATA *phdLast, int ixProc) {
PHDATA phd;
KCALLPROFON(7);
if (!PhdPrevReturn || !PhdNext || (*phdLast != PhdNext))
phd = (PHDATA)HandleList.fwd;
else
phd = (PHDATA)PhdNext->linkage.fwd;
DEBUGCHK(phd != 0);
if (&phd->linkage == &HandleList) {
PhdPrevReturn = 0;
KCALLPROFOFF(7);
return 0;
}
PhdPrevReturn = phd;
if ((phd->lock & (1<<ixProc)) && (phd->hValue != hCurThread) && (phd->hValue != hCurProc)) {
// Force handle reference count for this process to one.
if (phd->ref.count < 0x10000)
phd->ref.count = 1;
else
phd->ref.pFr->usRefs[ixProc] = 1;
} else {
PhdNext = *phdLast = phd;
phd = (PHDATA)((ulong)phd | 1);
}
KCALLPROFOFF(7);
return phd;
}
void SC_CloseAllHandles(void) {
PHDATA phd, next;
int ixProc;
next = 0;
ixProc = pCurProc->procnum;
while (phd = (PHDATA)KCall((PKFN)NextCloseHandle, &next, ixProc))
if (!((DWORD)phd & 1))
CloseHandle(phd->hValue);
}
// Non-preemtible handle setup for AllocHandle().
BOOL SetupHandle(PHDATA phdNew, PPROCESS pprc) {
KCALLPROFON(8);
phdNew->hValue = (HANDLE)(((ulong)phdNew & HANDLE_ADDRESS_MASK) | 2 | ((ulong)phdNew->hValue & 0xE0000000));
LockFromKey(&phdNew->lock, &pprc->aky);
// Zap PhdPrevReturn so to force a restart the next time
// NextCloseHandle() is called.
PhdPrevReturn = 0;
AddToDList(&HandleList, &phdNew->linkage);
KCALLPROFOFF(8);
return TRUE;
}
// Non-preemtible handle cleanup for FreeHandle().
PHDATA ZapHandle(HANDLE h) {
PHDATA phd;
KCALLPROFON(9);
h2p(h, phd);
if (phd) {
phd->lock = 0;
// make it so that the handle no longer matches existing handles given out
DEBUGCHK(((DWORD)phd->hValue & 0x1fffffff) == (((ulong)phd & HANDLE_ADDRESS_MASK) | 2));
phd->hValue = (HANDLE)((DWORD)phd->hValue+0x20000000);
// If freeing a handle other than the last one returned by
// NextCloseHandle(), then zap PhdPrevReturn so to force
// a restart the next time NextCloseHandle() is called.
if (phd != PhdPrevReturn)
PhdPrevReturn = 0;
if (phd == PhdNext)
PhdNext = 0;
RemoveDList(&phd->linkage);
}
KCALLPROFOFF(9);
return phd;
}
// Create a new handle.
HANDLE AllocHandle(const CINFO *pci, PVOID pvObj, PPROCESS pprc)
{
PHDATA phdNew;
DEBUGMSG(ZONE_MEMORY, (TEXT("AllocHandle: pci=%8.8lx pvObj=%8.8lx pprc=%8.8lx\r\n"),
pci, pvObj, pprc));
if ((phdNew = AllocMem(HEAP_HDATA)) != 0) {
phdNew->pci = pci;
phdNew->pvObj = pvObj;
phdNew->dwInfo = 0;
phdNew->ref.count = 1;
if (KCall((PKFN)SetupHandle, phdNew, pprc)) {
DEBUGMSG(ZONE_MEMORY, (TEXT("AllocHandle: phd=%8.8lx hValue=%8.8lx\r\n"),
phdNew, phdNew->hValue));
return phdNew->hValue;
}
DEBUGMSG(ZONE_MEMORY, (TEXT("AllocHandle: SetupHandle Failed!\r\n")));
FreeMem(phdNew, HEAP_HDATA);
} else
DEBUGMSG(ZONE_MEMORY, (TEXT("AllocHandle: AllocMem Failed!\r\n")));
return 0;
}
// Destroy a handle.
BOOL FreeHandle(HANDLE h)
{
PHDATA phd;
if ((phd = (PHDATA)KCall((PKFN)ZapHandle, h)) != 0) {
if (phd->ref.count >= 0x10000)
FreeMem(phd->ref.pFr, HEAP_FULLREF);
FreeMem(phd, HEAP_HDATA);
return TRUE;
}
return FALSE;
}
// Non-preemtible: copies single refcount to FULLREF.
BOOL CopyRefs(HANDLE h, FULLREF *pFr) {
PHDATA phd;
int inx;
KCALLPROFON(12);
h2p(h, phd);
if (phd && phd->ref.count < 0x10000) {
inx = IndexFromLock(phd->lock);
pFr->usRefs[inx] = (ushort)phd->ref.count;
phd->ref.pFr = pFr;
KCALLPROFOFF(12);
return FALSE;
}
KCALLPROFOFF(12);
return TRUE;
}
// Non-preemtible worker for IncRef().
int DoIncRef(HANDLE h, PPROCESS pprc) {
PHDATA phd;
ACCESSKEY aky;
int inx;
KCALLPROFON(11);
aky = pprc->aky;
inx = pprc->procnum;
h2p(h, phd);
if (phd && phd->lock != 0) {
if (phd->ref.count < 0x10000) {
if (TestAccess(&phd->lock, &aky)) {
++phd->ref.count;
KCALLPROFOFF(11);
return 1;
}
KCALLPROFOFF(11);
return 2; // Tell IncRef to allocate a FULLREF.
}
// There is a FULLREF structure. Increment the entry for this
// process and add it to the access key.
AddAccess(&phd->lock, aky);
++phd->ref.pFr->usRefs[inx];
KCALLPROFOFF(11);
return 1;
}
KCALLPROFOFF(11);
return 0;
}
// Returns FALSE if handle not valid or refcnt==0.
BOOL IncRef(HANDLE h, PPROCESS pprc)
{
FULLREF *pFr;
int ret;
while ((ret = KCall(DoIncRef, h, pprc)) == 2) {
// Second process referencing handle. Must allocate
// a FULLREF structure to track references from
// multiple processes.
if ((pFr = AllocMem(HEAP_FULLREF)) == 0)
return FALSE;
memset(pFr,0,sizeof(FULLREF));
if (KCall(CopyRefs, h, pFr)) {
// Another thread already allocated a FULLREF for this handle.
FreeMem(pFr, HEAP_FULLREF);
}
}
return ret;
}
// Non-preemtible worker for DecRef().
BOOL DoDecRef(HANDLE h, PPROCESS pprc, BOOL fAll) {
PHDATA phd;
ACCESSKEY aky;
int inx;
KCALLPROFON(30);
aky = pprc->aky;
inx = pprc->procnum;
h2p(h, phd);
if (phd && TestAccess(&phd->lock, &aky)) {
if (phd->ref.count < 0x10000) {
if (fAll || phd->ref.count == 1) {
phd->lock = 0;
phd->ref.count = 0;
KCALLPROFOFF(30);
return TRUE;
}
--phd->ref.count;
} else {
// There is a FULLREF structure. Decrement the entry for this
// process. If the last reference for this process is removed,
// remove its permission to access the handle.
if (fAll || phd->ref.pFr->usRefs[inx] == 1) {
phd->ref.pFr->usRefs[inx] = 0;
if (RemoveAccess(&phd->lock, aky) == 0) {
KCALLPROFOFF(30);
return TRUE;
}
} else
--phd->ref.pFr->usRefs[inx];
}
}
KCALLPROFOFF(30);
return FALSE;
}
// Returns TRUE if all references removed.
BOOL DecRef(HANDLE h, PPROCESS pprc, BOOL fAll)
{
return KCall(DoDecRef, h, pprc, fAll);
}
BOOL CheckLastRef(HANDLE hTh) {
PHDATA phd;
BOOL bRet;
KCALLPROFON(49);
bRet = TRUE;
h2p(hTh,phd);
if (phd && phd->pvObj && (phd->pci->type==SH_CURTHREAD) && ((THREAD *)(phd->pvObj))->pOwnerProc == pCurProc) {
if (phd->ref.count < 0x10000) {
if (phd->ref.count == 1)
bRet = FALSE;
} else {
if (phd->ref.pFr->usRefs[pCurProc->procnum] == 1)
bRet = FALSE;
}
}
KCALLPROFOFF(49);
return bRet;
}
// Returns 0 if handle is not valid.
DWORD GetUserInfo(HANDLE h)
{
PHDATA phd;
h2p(h, phd);
return phd ? phd->dwInfo : 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -