test: handtabl.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# handtabl.c

Go to the documentation of this file.

    00001 /****************************** Module Header ******************************\
    00002 * Module Name: handtabl.c
    00003 *
    00004 * Copyright (c) 1985 - 1999, Microsoft Corporation
    00005 *
    00006 * Implements the USER handle table.
    00007 *
    00008 * 01-13-92 ScottLu      Created.
    00009 \***************************************************************************/
    00010
    00011 #include "precomp.h"
    00012 #pragma hdrstop
    00013
    00014 #pragma alloc_text(INIT, HMInitHandleTable)
    00015
    00016 #if DBG
    00017
    00018 #define HTIENTRY(szObjectType, structName, fnDestroy, dwAllocTag, bObjectCreateFlags) \
    00019     {szObjectType, sizeof(structName), (FnDestroyUserObject)fnDestroy, (CONST DWORD)dwAllocTag, (CONST BYTE)(bObjectCreateFlags)}
    00020
    00021 #else // DBG
    00022
    00023 #define HTIENTRY(szObjectType, structName, fnDestroy, dwAllocTag, bObjectCreateFlags) \
    00024     {(FnDestroyUserObject)fnDestroy, (CONST DWORD)dwAllocTag, (CONST BYTE)(bObjectCreateFlags)}
    00025
    00026 #endif // DBG
    00027
    00028 void HMNullFnDestroy(PVOID pobj)
    00029 {
    00030     RIPMSG1(RIP_WARNING, "HM: No clean up function for %#p", pobj);
    00031     HMDestroyObject(pobj);
    00032     return;
    00033 }
    00034 /***************************************************************************\
    00035 *
    00036 * Table of user objects statistics.  Used by userkdx.dumhmgr debugger extension
    00037 *
    00038 \***************************************************************************/
    00039
    00040 #if DBG
    00041
    00042 /*
    00043  * Note that we need to statically initialize gaPrevhti so that it is
    00044  * included during the link phase. It is not refered to anywher in win32k.sys,
    00045  * only in userkdx.dll, so it will be optimized out in the link phase otherwise.
    00046  * Marking it volatile did not seem to help.
    00047  */
    00048
    00049 PERFHANDLEINFO gaPerfhti[TYPE_CTYPES] = {0};  /* stores current counts */
    00050 PERFHANDLEINFO gaPrevhti[TYPE_CTYPES] = {0};  /* stores previous counts */
    00051
    00052 #endif // DBG
    00053
    00054 /***************************************************************************\
    00055 *
    00056 * Table of handle type information.
    00057 *
    00058 * Desktop and Shared Heap objects can't be tagged as yet
    00059 * (TAG_WINDOW is bogus for heap windows, but not for desktop and other
    00060 * windows allocated in pool).
    00061 *
    00062 * WARNING: Keep it in sync with aszTypeNames table from ntuser\kdexts\userexts.c
    00063 *
    00064 * All HM objects must start with a HEAD strucutre. In addition:
    00065 * (If you find these comments to be wrong, please fix them)
    00066 *
    00067 * OCF_PROCESSOWNED: Object must start with a PROC*HEAD structure
    00068 *                   A ptiOwner must be provided
    00069 *                   The object affects the handle quota (ppi->UserHandleCount)
    00070 *                   The object will be destroyed if the process goes away.
    00071 *
    00072 * OCF_MARKPROCESS:  Object must start with a PROCMARKHEAD structure
    00073 *                   A ptiOwner must be provided
    00074 *                   It must not use OCF_DESKTOPHEAP (implementation limitation)
    00075 *
    00076 * OCF_THREADOWNED:  Object must start with a THR*HEAD structure
    00077 *                   The object affects the handle quota (ppi->UserHandleCount)
    00078 *                   The object will be destroyed if the thread goes away.
    00079 *
    00080 * OCF_DESKTOPHEAP:  Object must start with a *DESKHEAD structure
    00081 *                   A pdeskSrc must be provided at allocation time
    00082 *                   It must not use OCF_MARKPROCESS (implementation limitation)
    00083 *
    00084 \***************************************************************************/
    00085
    00086 #if (TYPE_FREE != 0)
    00087 #error TYPE_FREE must be zero.
    00088 #endif
    00089
    00090 CONST HANDLETYPEINFO    gahti[TYPE_CTYPES] = {
    00091     /* TYPE_FREE - HEAD */
    00092     HTIENTRY("Free", HEAD,
    00093              NULL,
    00094              0,
    00095              0),
    00096
    00097     /* TYPE_WINDOW - WND(THRDESKHEAD) */
    00098     HTIENTRY("Window", WND,
    00099              xxxDestroyWindow,
    00100              TAG_WINDOW,
    00101              OCF_THREADOWNED | OCF_USEPOOLQUOTA | OCF_DESKTOPHEAP | OCF_USEPOOLIFNODESKTOP | OCF_VARIABLESIZE),
    00102
    00103     /* TYPE_MENU - MENU(PROCDESKHEAD) */
    00104     HTIENTRY("Menu", MENU,
    00105              _DestroyMenu,
    00106              0,
    00107              OCF_PROCESSOWNED | OCF_DESKTOPHEAP),
    00108
    00109     /* TYPE_CURSOR - CURSOR(PROCMARKHEAD) or ACON(PROCMARKHEAD) */
    00110     HTIENTRY("Icon/Cursor", CURSOR,
    00111              DestroyUnlockedCursor,
    00112              TAG_CURSOR,
    00113              OCF_PROCESSOWNED | OCF_MARKPROCESS | OCF_USEPOOLQUOTA),
    00114
    00115     /* TYPE_SETWINDOWPOS - SMWP(HEAD) */
    00116     HTIENTRY("WPI(SWP) structure", SMWP,
    00117              DestroySMWP,
    00118              TAG_SWP,
    00119              OCF_THREADOWNED | OCF_USEPOOLQUOTA),
    00120
    00121     /* TYPE_HOOK - HOOK(THRDESKHEAD) */
    00122     HTIENTRY("Hook", HOOK,
    00123              FreeHook,
    00124              0,
    00125              OCF_THREADOWNED | OCF_DESKTOPHEAP),
    00126
    00127     /* TYPE_CLIPDATA -  CLIPDATA(HEAD) */
    00128     HTIENTRY("Clipboard Data", CLIPDATA,
    00129              HMNullFnDestroy,
    00130              TAG_CLIPBOARD,
    00131              OCF_VARIABLESIZE),
    00132
    00133     /* TYPE_CALLPROC - CALLPROCDATA(THRDESKHEAD) */
    00134     HTIENTRY("CallProcData", CALLPROCDATA,
    00135              HMDestroyObject,
    00136              0,
    00137              OCF_PROCESSOWNED | OCF_DESKTOPHEAP),
    00138
    00139     /* TYPE_ACCELTABLE - ACCELTABLE(PROCOBJHEAD) */
    00140     HTIENTRY("Accelerator", ACCELTABLE,
    00141              HMDestroyObject,
    00142              TAG_ACCEL,
    00143              OCF_PROCESSOWNED | OCF_USEPOOLQUOTA | OCF_VARIABLESIZE),
    00144
    00145     /* TYPE_DDEACCESS - SVR_INSTANCE_INFO(THROBJHEAD) */
    00146     HTIENTRY("DDE access", SVR_INSTANCE_INFO,
    00147              HMNullFnDestroy,
    00148              TAG_DDE9,
    00149              OCF_THREADOWNED | OCF_USEPOOLQUOTA),
    00150
    00151     /* TYPE_DDECONV - DDECONV(THROBJHEAD) */
    00152     HTIENTRY("DDE conv", DDECONV,
    00153              FreeDdeConv,
    00154              TAG_DDEa,
    00155              OCF_THREADOWNED | OCF_USEPOOLQUOTA),
    00156
    00157     /* TYPE_DDEXACT - XSTATE(THROBJHEAD) */
    00158     HTIENTRY("DDE Transaction", XSTATE,
    00159              FreeDdeXact,
    00160              TAG_DDEb,
    00161              OCF_THREADOWNED | OCF_USEPOOLQUOTA),
    00162
    00163     /* TYPE_MONITOR - MONITOR(HEAD) */
    00164     HTIENTRY("Monitor", MONITOR,
    00165              DestroyMonitor,
    00166              TAG_DISPLAYINFO,
    00167              OCF_SHAREDHEAP),
    00168
    00169     /* TYPE_KBDLAYOUT - KL(HEAD) */
    00170     HTIENTRY("Keyboard Layout",  KL,
    00171              DestroyKL,
    00172              TAG_KBDLAYOUT,
    00173              0),
    00174
    00175     /* TYPE_KBDFILE - KBDFILE(HEAD) */
    00176     HTIENTRY("Keyboard File", KBDFILE,
    00177              DestroyKF,
    00178              TAG_KBDFILE,
    00179              0),
    00180
    00181     /* TYPE_WINEVENTHOOK - EVENTHOOK(THROBJHEAD) */
    00182     HTIENTRY("WinEvent hook", EVENTHOOK,
    00183              DestroyEventHook,
    00184              TAG_WINEVENT,
    00185              OCF_THREADOWNED),
    00186
    00187
    00188     /* TYPE_TIMER - TIMER(HEAD) */
    00189     HTIENTRY("Timer", TIMER,
    00190              FreeTimer,
    00191              TAG_TIMER,
    00192              0),
    00193
    00194     /* TYPE_INPUTCONTEXT - IMC(THRDESKHEAD) */
    00195     HTIENTRY("Input Context", IMC,
    00196              FreeInputContext,
    00197              0,
    00198              OCF_THREADOWNED | OCF_DESKTOPHEAP),
    00199 };
    00200
    00201 /*
    00202  * Handle table allocation globals.  The purpose of keeping per-page free
    00203  * lists is to keep the table as small as is practical and to minimize
    00204  * the number of pages touched while performing handle table operations.
    00205  */
    00206 #define CPAGEENTRIESINIT    4
    00207
    00208 DWORD gcHandlePages;
    00209 PHANDLEPAGE gpHandlePages;
    00210
    00211 #if DBG
    00212 PPAGED_LOOKASIDE_LIST LockRecordLookaside;
    00213
    00214 NTSTATUS InitLockRecordLookaside();
    00215 void FreeLockRecord(PLR plr);
    00216 void InitGlobalThreadLockArray(DWORD dwIndex);
    00217 #endif
    00218
    00219 void HMDestroyUnlockedObject(PHE phe);
    00220 void HMRecordLock(PVOID ppobj, PVOID pobj, DWORD cLockObj);
    00221 BOOL HMUnrecordLock(PVOID ppobj, PVOID pobj);
    00222 VOID ShowLocks(PHE);
    00223
    00224
    00225 /***************************************************************************\
    00226 * DBGValidateHandleQuota
    00227 *
    00228 * 11-19-97 GerardoB         Created.
    00229 \***************************************************************************/
    00230 #ifdef VALIDATEHANDLEQUOTA
    00231 void DBGValidateHandleQuota (void)
    00232 {
    00233     BYTE bCreateFlags;
    00234     DWORD dw;
    00235     HANDLEENTRY * phe;
    00236
    00237     PPROCESSINFO ppiT = gppiList;
    00238
    00239     while (ppiT != NULL) {
    00240         ppiT->lHandles = 0;
    00241         ppiT = ppiT->ppiNextRunning;
    00242     }
    00243
    00244     phe = gSharedInfo.aheList;
    00245     for (dw = 0; dw <= giheLast; dw++, phe++) {
    00246         if (phe->bType == TYPE_FREE) {
    00247             UserAssert(phe->pOwner == NULL);
    00248             continue;
    00249         }
    00250         bCreateFlags = gahti[phe->bType].bObjectCreateFlags;
    00251         if (bCreateFlags & OCF_PROCESSOWNED) {
    00252             ((PPROCESSINFO)phe->pOwner)->lHandles++;
    00253             continue;
    00254         }
    00255         if (bCreateFlags & OCF_THREADOWNED) {
    00256             ((PTHREADINFO)phe->pOwner)->ppi->lHandles++;
    00257             continue;
    00258         }
    00259         UserAssert(phe->pOwner == NULL);
    00260     }
    00261
    00262     ppiT = gppiList;
    00263     while (ppiT != NULL) {
    00264         UserAssert(ppiT->lHandles == ppiT->UserHandleCount);
    00265         ppiT = ppiT->ppiNextRunning;
    00266     }
    00267 }
    00268 #else
    00269 #define DBGValidateHandleQuota()
    00270 #endif
    00271 /***************************************************************************\
    00272 * DBGHMPheFromObject
    00273 *
    00274 * Validates and returns the HANDLEENTRY corresponding to a given object
    00275 *
    00276 * 09-23-97 GerardoB         Created.
    00277 \***************************************************************************/
    00278 #if DBG
    00279 PHE DBGHMPheFromObject (PVOID p)
    00280 {
    00281     PHE phe = _HMPheFromObject(p);
    00282
    00283     UserAssert(phe->phead == p);
    00284     UserAssert(_HMObjectFromHandle(phe->phead->h) == p);
    00285     UserAssert(phe->wUniq == HMUniqFromHandle(phe->phead->h));
    00286     UserAssert(phe->bType < TYPE_CTYPES);
    00287     UserAssert((phe->pOwner != NULL)
    00288                 || !(gahti[phe->bType].bObjectCreateFlags & (OCF_PROCESSOWNED | OCF_THREADOWNED)));
    00289     UserAssert(!(phe->bFlags & ~HANDLEF_VALID));
    00290
    00291     return phe;
    00292 }
    00293 #endif
    00294 /***************************************************************************\
    00295 * DBGHMPheFromObject
    00296 *
    00297 * Validates and returns the object corresponding to a given handle.
    00298 *
    00299 * 09-23-97 GerardoB         Created.
    00300 \***************************************************************************/
    00301 #if DBG
    00302 PVOID DBGHMObjectFromHandle (HANDLE h)
    00303 {
    00304     PVOID p = _HMObjectFromHandle(h);
    00305
    00306     UserAssert((h != NULL) ^ (p == NULL));
    00307     if (p != NULL) {
    00308         UserAssert(HMIndexFromHandle(((PHEAD)p)->h) == HMIndexFromHandle(h));
    00309         UserAssert(p == HMRevalidateCatHandle(h));
    00310     /*
    00311      * This routine, unlike Validation, should return a real pointer if
    00312      * the object exists, even if it is destroyed.  But we should still
    00313      * generate a warning.
    00314      */
    00315         if (HMPheFromObject(p)->bFlags & HANDLEF_DESTROY) {
    00316             RIPMSG1(RIP_WARNING, "HMObjectFromHandle: Object p %#p is destroyed",
    00317                     p);
    00318         }
    00319     }
    00320
    00321     return p;
    00322 }
    00323 PVOID DBGHMCatObjectFromHandle (HANDLE h)
    00324 {
    00325     /*
    00326      * Note -- at this point, _HMObjectFromHandle does not check
    00327      *   to see if an object is destroyed.
    00328      */
    00329     PVOID p = _HMObjectFromHandle(h);
    00330
    00331     UserAssert((h != NULL) ^ (p == NULL));
    00332     if (p != NULL) {
    00333         UserAssert(HMIndexFromHandle(((PHEAD)p)->h) == HMIndexFromHandle(h));
    00334         UserAssert(p == HMRevalidateCatHandle(h));
    00335     }
    00336
    00337     return p;
    00338 }
    00339 #endif
    00340 /***************************************************************************\
    00341 * DBGPtoH and DBGPtoHq
    00342 *
    00343 * Validates and returns the handle corresponding to a given object
    00344 *
    00345 * 09-23-97 GerardoB         Created.
    00346 \***************************************************************************/
    00347 #if DBG
    00348 void DBGValidatePtoH (PVOID p, HANDLE h)
    00349 {
    00350     UserAssert((h != NULL) ^ (p == NULL));
    00351     if (h != NULL) {
    00352         UserAssert(p == HMRevalidateCatHandle(h));
    00353     }
    00354 }
    00355 HANDLE DBGPtoH (PVOID p)
    00356 {
    00357     HANDLE h = _PtoH(p);
    00358     DBGValidatePtoH(p, h);
    00359     return h;
    00360 }
    00361 HANDLE DBGPtoHq (PVOID p)
    00362 {
    00363     HANDLE h;
    00364     UserAssert(p != NULL);
    00365     h = _PtoHq(p);
    00366     DBGValidatePtoH(p, h);
    00367     return h;
    00368 }
    00369 #endif
    00370 /***************************************************************************\
    00371 * DBGHW and DBGHWq
    00372 *
    00373 * Validates and returns the hwnd corresponding to a given pwnd
    00374 *
    00375 * 09-23-97 GerardoB         Created.
    00376 \***************************************************************************/
    00377 #if DBG
    00378 void DBGValidateHW(PWND pwnd, HWND hwnd)
    00379 {
    00380     UserAssert((hwnd != NULL) ^ (pwnd == NULL));
    00381     if (hwnd != NULL) {
    00382         UserAssert(pwnd == HMValidateCatHandleNoSecure(hwnd, TYPE_WINDOW));
    00383     }
    00384 }
    00385 void DBGValidateHWCCX(PWND ccxPwnd, HWND hwnd, PCLIENTINFO ccxPci)
    00386 {
    00387     UserAssert((hwnd != NULL) ^ (ccxPwnd == NULL));
    00388     if (hwnd != NULL) {
    00389         UserAssert(ccxPwnd == HMValidateCatHandleNoSecureCCX(hwnd, TYPE_WINDOW, ccxPci));
    00390     }
    00391 }
    00392 HWND DBGHW (PWND pwnd)
    00393 {
    00394     HWND hwnd = _HW(pwnd);
    00395     DBGValidateHW(pwnd, hwnd);
    00396     return hwnd;
    00397 }
    00398 HWND DBGHWCCX (PWND ccxPwnd)
    00399 {
    00400     HWND hwnd = _HWCCX(ccxPwnd);
    00401     PCLIENTINFO ccxPci = _GETPTI(ccxPwnd)->pClientInfo;
    00402     if (KeIsAttachedProcess()) {
    00403         UserAssert(KeGetCurrentThread()->ApcState.Process == &(_GETPTI(ccxPwnd)->ppi->Process->Pcb));
    00404     } else {
    00405         UserAssert(PpiCurrent() == _GETPTI(ccxPwnd)->ppi);
    00406     }
    00407     DBGValidateHWCCX(ccxPwnd, hwnd, ccxPci);
    00408     return hwnd;
    00409 }
    00410 HWND DBGHWq (PWND pwnd)
    00411 {
    00412     HWND hwnd;
    00413     UserAssert(pwnd != NULL);
    00414     hwnd = _HWq(pwnd);
    00415     DBGValidateHW(pwnd, hwnd);
    00416     return hwnd;
    00417 }
    00418 #endif
    00419 /***************************************************************************\
    00420 * DBGHMValidateFreeLists
    00421 *
    00422 * Walks all handle free lists to make sure all links are fine.
    00423 *
    00424 * 10/08/97  GerardoB    Created
    00425 \***************************************************************************/
    00426 #if DBG
    00427 void DBGHMValidateFreeList (ULONG_PTR iheFreeNext, BOOL fEven)
    00428 {
    00429     PHE phe;
    00430     do {
    00431         UserAssert(fEven ^ !!(iheFreeNext & 0x1));
    00432         UserAssert(iheFreeNext < gpsi->cHandleEntries);
    00433         phe = &gSharedInfo.aheList[iheFreeNext];
    00434         UserAssert(phe->bType == TYPE_FREE);
    00435         UserAssert(phe->pOwner == NULL);
    00436         UserAssert(phe->bFlags == 0);
    00437         iheFreeNext = (ULONG_PTR)phe->phead;
    00438     } while (iheFreeNext != 0);
    00439 }
    00440 void DBGHMValidateFreeLists (void)
    00441 {
    00442     DWORD dw;
    00443     PHANDLEPAGE php = gpHandlePages;
    00444
    00445     for (dw = 0; dw < gcHandlePages; ++dw, ++php) {
    00446         if (php->iheFreeEven != 0) {
    00447             DBGHMValidateFreeList(php->iheFreeEven, TRUE);
    00448         }
    00449         if (php->iheFreeOdd != 0) {
    00450             DBGHMValidateFreeList(php->iheFreeOdd, FALSE);
    00451         }
    00452     } /* for */
    00453 }
    00454 #else
    00455 #define DBGHMValidateFreeLists()
    00456 #endif
    00457
    00458 #if DBG
    00459
    00460 /***************************************************************************\
    00461 * DbgDumpHandleTable
    00462 *
    00463 \***************************************************************************/
    00464 DWORD DbgDumpHandleTable(
    00465     VOID)
    00466 {
    00467     DWORD dw;
    00468     PHE   phe;
    00469     DWORD dwHandles = 0;
    00470
    00471     phe = gSharedInfo.aheList;
    00472
    00473     if (phe == NULL) {
    00474         KdPrint(("\nTERMSRV\nEmpty handle table\n"));
    00475         return 0;
    00476     }
    00477
    00478     KdPrint(("\nTERMSRV\nDump the handle table\n"));
    00479     KdPrint(("---------------------------------------------------\n"));
    00480     KdPrint(("     phead    handle   lock     pOwner   type flags\n"));
    00481     KdPrint(("---------------------------------------------------\n"));
    00482
    00483     for (dw = 0; dw <= giheLast; dw++, phe++) {
    00484         if (phe->bType == TYPE_FREE) {
    00485             UserAssert(phe->pOwner == NULL);
    00486             continue;
    00487         }
    00488
    00489         KdPrint(("%04d %08x %08x %08d %08x %04x %05x\n",
    00490                  dwHandles++,
    00491                  phe->phead,
    00492                  phe->phead->h,
    00493                  phe->phead->cLockObj,
    00494                  phe->pOwner,
    00495                  phe->bType,
    00496                  phe->bFlags));
    00497     }
    00498
    00499     KdPrint(("----------------------------------------------\n"));
    00500     KdPrint(("Number of handles left: %d\n", dwHandles));
    00501     KdPrint(("End of handle table\n"));
    00502
    00503     UserAssert(dwHandles == 0);
    00504
    00505     return dwHandles;
    00506 }
    00507
    00508 /***************************************************************************\
    00509 * HMCleanUpHandleTable
    00510 *
    00511 \***************************************************************************/
    00512 VOID HMCleanUpHandleTable(
    00513     VOID)
    00514 {
    00515     DbgDumpHandleTable();
    00516
    00517     if (LockRecordLookaside != NULL) {
    00518         ExDeletePagedLookasideList(LockRecordLookaside);
    00519         UserFreePool(LockRecordLookaside);
    00520     }
    00521 }
    00522 #endif // DBG
    00523
    00524 /***************************************************************************\
    00525 * HMInitHandleEntries
    00526 *
    00527 * 10/10/97  GerardoB    Extracted from HMInitHandleTable and HMGrowHandleTable
    00528 \***************************************************************************/
    00529 void HMInitHandleEntries (ULONG_PTR iheFirstFree)
    00530 {
    00531     ULONG_PTR ihe;
    00532     PHE      pheT;
    00533     /*
    00534      * Zero out all the new entries
    00535      */
    00536     RtlZeroMemory (&gSharedInfo.aheList[iheFirstFree],
    00537                     (gpsi->cHandleEntries - iheFirstFree) * sizeof(HANDLEENTRY));
    00538     /*
    00539      * Link them together.
    00540      * Each free odd/even entry points to the next odd/even free entry.
    00541      */
    00542     ihe = iheFirstFree;
    00543     for (pheT = &gSharedInfo.aheList[ihe]; ihe < gpsi->cHandleEntries; ihe++, pheT++) {
    00544         pheT->phead = (PHEAD)(ihe + 2);
    00545         /* pheT->bType = TYPE_FREE; */
    00546         pheT->wUniq = 1;
    00547     }
    00548     /*
    00549      * Terminate the lists.
    00550      */
    00551     if (gpsi->cHandleEntries > iheFirstFree) {
    00552         UserAssert(pheT - 1 >= &gSharedInfo.aheList[iheFirstFree]);
    00553         (pheT - 1)->phead = NULL;
    00554     }
    00555     if (gpsi->cHandleEntries > iheFirstFree + 1) {
    00556         UserAssert(pheT - 2 >= &gSharedInfo.aheList[iheFirstFree]);
    00557         (pheT - 2)->phead = NULL;
    00558     }
    00559     /*
    00560      * Let's check that we got it right
    00561      */
    00562     DBGHMValidateFreeLists();
    00563 }
    00564 /***************************************************************************\
    00565 * HMInitHandleTable
    00566 *
    00567 * Initialize the handle table. Unused entries are linked together.
    00568 *
    00569 * 01-13-92 ScottLu      Created.
    00570 \***************************************************************************/
    00571
    00572 #define CHANDLEENTRIESINIT 200
    00573 #define CLOCKENTRIESINIT   100
    00574
    00575 BOOL HMInitHandleTable(
    00576     PVOID pReadOnlySharedSectionBase)
    00577 {
    00578     NTSTATUS Status;
    00579     SIZE_T   ulCommit;
    00580
    00581     /*
    00582      * Allocate the handle page array.  Make it big enough
    00583      * for 4 pages, which should be sufficient for nearly
    00584      * all instances.
    00585      */
    00586     gpHandlePages = UserAllocPool(
    00587             CPAGEENTRIESINIT * sizeof(HANDLEPAGE), TAG_SYSTEM);
    00588
    00589     if (gpHandlePages == NULL)
    00590         return FALSE;
    00591
    00592 #if DBG
    00593     if (!NT_SUCCESS(InitLockRecordLookaside()))
    00594         return FALSE;
    00595 #endif
    00596
    00597     /*
    00598      * Allocate the array.  We have the space from
    00599      * NtCurrentPeb()->ReadOnlySharedMemoryBase to
    00600      * NtCurrentPeb()->ReadOnlySharedMemoryHeap reserved for
    00601      * the handle table.  All we need to do is commit the pages.
    00602      *
    00603      * Compute the minimum size of the table.  The allocation will
    00604      * round this up to the next page size.
    00605      */
    00606     ulCommit = gpsi->cbHandleTable = PAGE_SIZE;
    00607     Status = CommitReadOnlyMemory(ghSectionShared, &ulCommit, 0, NULL);
    00608
    00609     if (!NT_SUCCESS(Status))
    00610         return FALSE;
    00611
    00612     gSharedInfo.aheList = pReadOnlySharedSectionBase;
    00613     gpsi->cHandleEntries = gpsi->cbHandleTable / sizeof(HANDLEENTRY);
    00614     gcHandlePages = 1;
    00615
    00616     /*
    00617      * Initialize the handlepage info. Handle 0 is reserved so even free list
    00618      *  starts at 2.
    00619      */
    00620     gpHandlePages[0].iheFreeOdd = 1;
    00621     gpHandlePages[0].iheFreeEven = 2;
    00622     gpHandlePages[0].iheLimit = gpsi->cHandleEntries;
    00623     /*
    00624      * Initialize the handle entries.
    00625      */
    00626     HMInitHandleEntries(0);
    00627     /*
    00628      * PW(NULL) (ie, handle 0) must map to a NULL pointer.
    00629      * Old comment:
    00630      * Reserve the first handle table entry so that PW(NULL) maps to a
    00631      * NULL pointer. Set it to TYPE_FREE so the cleanup code doesn't think
    00632      * it is allocated. Set wUniq to 1 so that RevalidateHandles on NULL
    00633      * will fail.
    00634      */
    00635     gSharedInfo.aheList[0].phead = NULL;
    00636     UserAssert(gSharedInfo.aheList[0].bType == TYPE_FREE);
    00637     UserAssert(gSharedInfo.aheList[0].wUniq == 1);
    00638
    00639 #if DBG
    00640     /*
    00641      * Make sure we don't need to add the special case to handle HMINDEXBITS in this function.
    00642      */
    00643     UserAssert(gpsi->cHandleEntries <= HMINDEXBITS);
    00644     /*
    00645      * PDESKOBJHEAD won't do the right casting unless these structs have
    00646      *  the same size.
    00647      */
    00648     UserAssert(sizeof(THROBJHEAD) == sizeof(PROCOBJHEAD));
    00649     UserAssert(sizeof(THRDESKHEAD) == sizeof(PROCDESKHEAD));
    00650     UserAssert(sizeof(THRDESKHEAD) == sizeof(DESKOBJHEAD));
    00651     /*
    00652      * Validate type flags to make sure that assumptions made
    00653      *  throughout HM code are OK.
    00654      */
    00655     {
    00656         HANDLETYPEINFO * pahti = (HANDLETYPEINFO *) gahti;
    00657         UINT uTypes = TYPE_CTYPES;
    00658         BYTE bObjectCreateFlags;
    00659         while (uTypes-- != 0) {
    00660             bObjectCreateFlags = pahti->bObjectCreateFlags;
    00661             /*
    00662              * Illegal flag combinations
    00663              */
    00664             UserAssert(!((bObjectCreateFlags & OCF_DESKTOPHEAP) && (bObjectCreateFlags & OCF_MARKPROCESS)));
    00665             /*
    00666              * Pointless (and probably illegal) flag combinations
    00667              */
    00668             UserAssert(!((bObjectCreateFlags & OCF_DESKTOPHEAP) && (bObjectCreateFlags & OCF_SHAREDHEAP)));
    00669             UserAssert(!((bObjectCreateFlags & OCF_USEPOOLQUOTA) && (bObjectCreateFlags & OCF_SHAREDHEAP)));
    00670             UserAssert(!((bObjectCreateFlags & OCF_THREADOWNED) && (bObjectCreateFlags & OCF_PROCESSOWNED)));
    00671             UserAssert(!(bObjectCreateFlags & OCF_USEPOOLQUOTA)
    00672                         || !(bObjectCreateFlags & OCF_DESKTOPHEAP)
    00673                         || (bObjectCreateFlags & OCF_USEPOOLIFNODESKTOP));
    00674
    00675             /*
    00676              * Required flag combinations
    00677              */
    00678             UserAssert(!(bObjectCreateFlags & OCF_DESKTOPHEAP)
    00679                         || (bObjectCreateFlags & (OCF_PROCESSOWNED | OCF_THREADOWNED)));
    00680
    00681             UserAssert(!(bObjectCreateFlags & OCF_MARKPROCESS)
    00682                         || (bObjectCreateFlags & OCF_PROCESSOWNED));
    00683
    00684             UserAssert(!(bObjectCreateFlags & OCF_USEPOOLIFNODESKTOP)
    00685                         || (bObjectCreateFlags & OCF_DESKTOPHEAP));
    00686
    00687
    00688             pahti++;
    00689         } /* while (uTypes-- != 0) */
    00690     }
    00691 #endif
    00692
    00693     return TRUE;
    00694 }
    00695
    00696 /***************************************************************************\
    00697 * HMGrowHandleTable
    00698 *
    00699 * Grows the handle table. Assumes the handle table already exists.
    00700 *
    00701 * 01-13-92 ScottLu      Created.
    00702 \***************************************************************************/
    00703
    00704 BOOL HMGrowHandleTable()
    00705 {
    00706     ULONG_PTR   i, iheFirstFree;
    00707     PHE         pheT;
    00708     PVOID       p;
    00709     PHANDLEPAGE phpNew;
    00710     DWORD       dwCommitOffset;
    00711     SIZE_T      ulCommit;
    00712     NTSTATUS    Status;
    00713
    00714     /*
    00715      * If we've run out of handle space, fail.
    00716      */
    00717     i = gpsi->cHandleEntries;
    00718     if (i & ~HMINDEXBITS)
    00719         return FALSE;
    00720
    00721     /*
    00722      * Grow the page table if need be.
    00723      */
    00724     i = gcHandlePages + 1;
    00725     if (i > CPAGEENTRIESINIT) {
    00726         DWORD dwSize = gcHandlePages * sizeof(HANDLEPAGE);
    00727
    00728         phpNew = UserReAllocPool(
    00729                 gpHandlePages, dwSize, dwSize + sizeof(HANDLEPAGE), TAG_SYSTEM);
    00730
    00731         if (phpNew == NULL)
    00732             return FALSE;
    00733
    00734         gpHandlePages = phpNew;
    00735     }
    00736
    00737     /*
    00738      * Commit some more pages to the table.  First find the
    00739      * address where the commitment needs to be.
    00740      */
    00741     p = (PBYTE)gSharedInfo.aheList + gpsi->cbHandleTable;
    00742
    00743     if (p >= Win32HeapGetHandle(gpvSharedAlloc)) {
    00744         return FALSE;
    00745     }
    00746
    00747     dwCommitOffset = (ULONG)((PBYTE)p - (PBYTE)gpvSharedBase);
    00748
    00749     ulCommit = PAGE_SIZE;
    00750
    00751     Status = CommitReadOnlyMemory(ghSectionShared, &ulCommit, dwCommitOffset, NULL);
    00752
    00753     if (!NT_SUCCESS(Status))
    00754         return FALSE;
    00755
    00756     phpNew = &gpHandlePages[gcHandlePages++];
    00757
    00758     /*
    00759      * Update the global information to include the new
    00760      * page.
    00761      */
    00762     iheFirstFree = gpsi->cHandleEntries;
    00763     if (gpsi->cHandleEntries & 0x1) {
    00764         phpNew->iheFreeOdd = gpsi->cHandleEntries;
    00765         phpNew->iheFreeEven = gpsi->cHandleEntries + 1;
    00766     } else {
    00767         phpNew->iheFreeEven = gpsi->cHandleEntries;
    00768         phpNew->iheFreeOdd = gpsi->cHandleEntries + 1;
    00769     }
    00770     gpsi->cbHandleTable += PAGE_SIZE;
    00771
    00772     /*
    00773      * Check for handle overflow
    00774      */
    00775     gpsi->cHandleEntries = gpsi->cbHandleTable / sizeof(HANDLEENTRY);
    00776     if (gpsi->cHandleEntries & ~HMINDEXBITS) {
    00777         gpsi->cHandleEntries = (HMINDEXBITS + 1);
    00778     }
    00779
    00780     phpNew->iheLimit = gpsi->cHandleEntries;
    00781     if (phpNew->iheFreeEven >= phpNew->iheLimit) {
    00782         phpNew->iheFreeEven = 0;
    00783     }
    00784     if (phpNew->iheFreeOdd >= phpNew->iheLimit) {
    00785         phpNew->iheFreeOdd = 0;
    00786     }
    00787
    00788     HMInitHandleEntries(iheFirstFree);
    00789
    00790     /*
    00791      * HMINDEXBITS has a special meaning. We used to handle this in HMAllocObject.
    00792      * Now we handle it here right after adding that handle to the table.
    00793      * Old Comment:
    00794      * Reserve this table entry so that PW(HMINDEXBITS) maps to a
    00795      * NULL pointer. Set it to TYPE_FREE so the cleanup code doesn't think
    00796      * it is allocated. Set wUniq to 1 so that RevalidateHandles on HMINDEXBITS
    00797      * will fail.
    00798      */
    00799     if ((gpsi->cHandleEntries > HMINDEXBITS)
    00800             && (phpNew->iheFreeOdd != 0)
    00801             && (phpNew->iheFreeOdd <= HMINDEXBITS)) {
    00802
    00803         pheT = &gSharedInfo.aheList[HMINDEXBITS];
    00804         if (phpNew->iheFreeOdd == HMINDEXBITS) {
    00805             phpNew->iheFreeOdd = (ULONG_PTR)pheT->phead;
    00806         } else {
    00807             UserAssert(pheT - 2 >= &gSharedInfo.aheList[iheFirstFree]);
    00808             UserAssert((pheT - 2)->phead == (PVOID)HMINDEXBITS);
    00809             (pheT - 2)->phead = pheT->phead;
    00810         }
    00811         pheT->phead = NULL;
    00812         UserAssert(pheT->bType == TYPE_FREE);
    00813         UserAssert(pheT->wUniq == 1);
    00814     }
    00815
    00816     return TRUE;
    00817 }
    00818
    00819 /***************************************************************************\
    00820 * HMAllocObject
    00821 *
    00822 * Allocs a non-secure object by allocating a handle and memory for
    00823 * the object.
    00824 *
    00825 * 01-13-92 ScottLu      Created.
    00826 \***************************************************************************/
    00827
    00828 PVOID HMAllocObject(
    00829     PTHREADINFO ptiOwner,
    00830     PDESKTOP pdeskSrc,
    00831     BYTE bType,
    00832     DWORD size)
    00833 {
    00834     DWORD       i;
    00835     PHEAD       phead;
    00836     PHE         pheT;
    00837     ULONG_PTR    iheFree, *piheFreeHead;
    00838     PHANDLEPAGE php;
    00839     BYTE        bCreateFlags;
    00840     PPROCESSINFO ppiQuotaCharge = NULL;
    00841     BOOL        fUsePoolIfNoDesktop;
    00842     BOOL        fEven;
    00843
    00844     CheckCritIn();
    00845     bCreateFlags = gahti[bType].bObjectCreateFlags;
    00846
    00847 #if DBG
    00848     /*
    00849      * Validate size
    00850      */
    00851     if (bCreateFlags & OCF_VARIABLESIZE) {
    00852         UserAssert(gahti[bType].uSize <= size);
    00853     } else {
    00854         UserAssert(gahti[bType].uSize == size);
    00855     }
    00856 #endif
    00857
    00858     /*
    00859      * Check for process handle quota
    00860      */
    00861     if (bCreateFlags & (OCF_PROCESSOWNED | OCF_THREADOWNED)) {
    00862         UserAssert(ptiOwner != NULL);
    00863         ppiQuotaCharge = ptiOwner->ppi;
    00864         if (ppiQuotaCharge->UserHandleCount >= gUserProcessHandleQuota) {
    00865             RIPERR0(ERROR_NO_MORE_USER_HANDLES,
    00866                    RIP_WARNING,
    00867                 "USER: HMAllocObject: out of handle quota\n");
    00868             return NULL;
    00869         }
    00870     }
    00871
    00872     /*
    00873      * Find the next free handle
    00874      * Window handles must be even; hence we try first to use odd handles
    00875      *  for all other objects.
    00876      * Old comment:
    00877      * Some wow apps, like WinProj, require even Window handles so we'll
    00878      * accomodate them; build a list of the odd handles so they won't get lost
    00879      * 10/13/97: WinProj never fixed this; even the 32 bit version has the problem.
    00880      */
    00881     fEven = (bType == TYPE_WINDOW);
    00882     piheFreeHead = NULL;
    00883     do {
    00884         php = gpHandlePages;
    00885         for (i = 0; i < gcHandlePages; ++i, ++php) {
    00886             if (fEven) {
    00887                 if (php->iheFreeEven != 0) {
    00888                     piheFreeHead = &php->iheFreeEven;
    00889                     break;
    00890                 }
    00891             } else {
    00892                 if (php->iheFreeOdd != 0) {
    00893                     piheFreeHead = &php->iheFreeOdd;
    00894                     break;
    00895                 }
    00896             }
    00897         } /* for */
    00898         /*
    00899          * If we couldn't find an odd handle, then search for an even one
    00900          */
    00901         fEven = ((piheFreeHead == NULL) && !fEven);
    00902     } while (fEven);
    00903     /*
    00904      * If there are no free handles we can use, grow the table
    00905      */
    00906     if (piheFreeHead == NULL) {
    00907         HMGrowHandleTable();
    00908         /*
    00909          * If the table didn't grow, get out.
    00910          */
    00911         if (i == gcHandlePages) {
    00912             RIPMSG0(RIP_WARNING, "HMAllocObject: could not grow handle space");
    00913             return NULL;
    00914         }
    00915         /*
    00916          * Because the handle page table may have moved,
    00917          * recalc the page entry pointer.
    00918          */
    00919         php = &gpHandlePages[i];
    00920         piheFreeHead = (bType == TYPE_WINDOW ? &php->iheFreeEven : &php->iheFreeOdd);
    00921         if (*piheFreeHead == 0) {
    00922             UserAssert(gpsi->cHandleEntries == (HMINDEXBITS + 1));
    00923             RIPMSG0(RIP_WARNING, "HMAllocObject: handle table is full");
    00924             return NULL;
    00925         }
    00926     }
    00927     /*
    00928      * HMINDEXBITS is a reserved value that should never be in the free lists
    00929      *  (see HMGrowHandleTable());
    00930      */
    00931     UserAssert(HMIndexFromHandle(*piheFreeHead) != HMINDEXBITS);
    00932     /*
    00933      * Try to allocate the object. If this fails, bail out.
    00934      */
    00935     if ((bCreateFlags & OCF_DESKTOPHEAP) && pdeskSrc) {
    00936         phead = (PHEAD)DesktopAlloc(pdeskSrc, size, DTAG_HANDTABL);
    00937         if (phead) {
    00938             LockDesktop(&((PDESKOBJHEAD)phead)->rpdesk, pdeskSrc, LDL_OBJ_DESK, (ULONG_PTR)phead);
    00939             ((PDESKOBJHEAD)phead)->pSelf = (PBYTE)phead;
    00940         }
    00941     } else if (bCreateFlags & OCF_SHAREDHEAP) {
    00942         UserAssert(!pdeskSrc);
    00943         phead = (PHEAD)SharedAlloc(size);
    00944     } else {
    00945         fUsePoolIfNoDesktop = !pdeskSrc && (bCreateFlags & OCF_USEPOOLIFNODESKTOP);
    00946         UserAssert(!(bCreateFlags & OCF_DESKTOPHEAP) || fUsePoolIfNoDesktop);
    00947
    00948         if ((bCreateFlags & OCF_USEPOOLQUOTA) && !fUsePoolIfNoDesktop) {
    00949             phead = (PHEAD)UserAllocPoolWithQuotaZInit(size, gahti[bType].dwAllocTag);
    00950         } else {
    00951             phead = (PHEAD)UserAllocPoolZInit(size, gahti[bType].dwAllocTag);
    00952         }
    00953     }
    00954
    00955     if (phead == NULL) {
    00956         RIPERR0(ERROR_NOT_ENOUGH_MEMORY,
    00957                 RIP_WARNING,
    00958                 "USER: HMAllocObject: out of memory");
    00959         return NULL;
    00960     }
    00961     /*
    00962      * We're going to use this handle so get it off its free list.
    00963      * The free handle phead points to the next free handle.
    00964      */
    00965     iheFree = *piheFreeHead;
    00966     pheT = &gSharedInfo.aheList[iheFree];
    00967     *piheFreeHead = (ULONG_PTR)pheT->phead;
    00968     DBGHMValidateFreeLists();
    00969     /*
    00970      * Track high water mark for handle allocation.
    00971      */
    00972     if ((DWORD)iheFree > giheLast) {
    00973         giheLast = (DWORD)iheFree;
    00974     }
    00975     /*
    00976      * Setup the handle contents, plus initialize the object header.
    00977      */
    00978     pheT->bType = bType;
    00979     pheT->phead = phead;
    00980     UserAssert(pheT->bFlags == 0);
    00981     if (bCreateFlags & OCF_PROCESSOWNED) {
    00982         if ((ptiOwner->TIF_flags & TIF_16BIT) && (ptiOwner->ptdb)) {
    00983             ((PPROCOBJHEAD)phead)->hTaskWow = ptiOwner->ptdb->hTaskWow;
    00984         } else {
    00985             ((PPROCOBJHEAD)phead)->hTaskWow = 0;
    00986         }
    00987         pheT->pOwner = ptiOwner->ppi;
    00988         if (bCreateFlags & OCF_MARKPROCESS) {
    00989             ((PPROCMARKHEAD)phead)->ppi = ptiOwner->ppi;
    00990         }
    00991     } else if (bCreateFlags & OCF_THREADOWNED) {
    00992         ((PTHROBJHEAD)phead)->pti = pheT->pOwner = ptiOwner;
    00993     } else {
    00994         /*
    00995          * The caller is wasting time if ptiOwner != NULL
    00996          * The handle entry must already have pOwner == NULL.
    00997          */
    00998         UserAssert(ptiOwner == NULL);
    00999         UserAssert(pheT->pOwner == NULL);
    01000     }
    01001
    01002     phead->h = HMHandleFromIndex(iheFree);
    01003
    01004     if (ppiQuotaCharge) {
    01005         ppiQuotaCharge->UserHandleCount++;
    01006         DBGValidateHandleQuota();
    01007     }
    01008
    01009 #if DBG
    01010     /*
    01011      *   performance counter dumphmgr
    01012      *   dwPrevCount is used for the snapshot option
    01013      */
    01014
    01015     gaPerfhti[bType].lTotalCount++;
    01016     gaPerfhti[bType].lCount++;
    01017     if (gaPerfhti[bType].lCount > gaPerfhti[bType].lMaxCount) {
    01018         gaPerfhti[bType].lMaxCount = gaPerfhti[bType].lCount;
    01019     }
    01020     if ((bCreateFlags & OCF_DESKTOPHEAP) && (pdeskSrc != NULL)) {
    01021         gaPerfhti[bType].lSize += RtlSizeHeap(Win32HeapGetHandle(pdeskSrc->pheapDesktop), 0, phead);
    01022     } else if (bCreateFlags & OCF_SHAREDHEAP) {
    01023         gaPerfhti[bType].lSize += RtlSizeHeap(Win32HeapGetHandle(gpvSharedAlloc), 0, phead);
    01024     } else {
    01025         unsigned char  notUsed;
    01026         gaPerfhti[bType].lSize += ExQueryPoolBlockSize(phead, &notUsed);
    01027     }
    01028
    01029 #endif // DBG
    01030
    01031     /*
    01032      * Return a handle entry pointer.
    01033      */
    01034     return pheT->phead;
    01035 }
    01036
    01037
    01038
    01039 #if 0
    01040 #define HANDLEF_FREECHECK 0x80
    01041 VOID CheckHMTable(
    01042     PVOID pobj)
    01043 {
    01044     PHE pheT, pheMax;
    01045
    01046     if (giheLast) {
    01047         pheMax = &gSharedInfo.aheList[giheLast];
    01048         for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) {
    01049             if (pheT->bType == TYPE_FREE) {
    01050                 continue;
    01051             }
    01052             if (pheT->phead == pobj && !(pheT->bFlags & HANDLEF_FREECHECK)) {
    01053                 UserAssert(FALSE);
    01054             }
    01055         }
    01056     }
    01057 }
    01058 #endif
    01059
    01060
    01061 /***************************************************************************\
    01062 * HMFreeObject
    01063 *
    01064 * Frees an object - the handle and the referenced memory.
    01065 *
    01066 * 01-13-92 ScottLu      Created.
    01067 \***************************************************************************/
    01068
    01069 BOOL HMFreeObject(
    01070     PVOID pobj)
    01071 {
    01072     PHE         pheT;
    01073     WORD        wUniqT;
    01074     PHANDLEPAGE php;
    01075     DWORD       i;
    01076     ULONG_PTR    iheCurrent, *piheCurrentHead;
    01077     BYTE        bCreateFlags;
    01078     PDESKTOP    pdesk;
    01079     PPROCESSINFO ppiQuotaCharge = NULL;
    01080 #if DBG
    01081     PLR         plrT, plrNextT;
    01082     unsigned char  notUsed;
    01083 #endif
    01084
    01085     UserAssert(((PHEAD)pobj)->cLockObj == 0);
    01086     UserAssert(pobj == HtoPqCat(PtoHq(pobj)));
    01087     /*
    01088      * Free the object first.
    01089      */
    01090     pheT = HMPheFromObject(pobj);
    01091     bCreateFlags = gahti[pheT->bType].bObjectCreateFlags;
    01092
    01093     UserAssertMsg1(pheT->bType != TYPE_FREE,
    01094                    "Object already marked as freed!!! %#p", pobj);
    01095
    01096     /*
    01097      * decr process handle use
    01098      */
    01099     if (bCreateFlags & OCF_PROCESSOWNED) {
    01100         ppiQuotaCharge = (PPROCESSINFO)pheT->pOwner;
    01101         UserAssert(ppiQuotaCharge != NULL);
    01102     } else if (bCreateFlags & OCF_THREADOWNED) {
    01103         ppiQuotaCharge = (PPROCESSINFO)(((PTHREADINFO)(pheT->pOwner))->ppi);
    01104         UserAssert(ppiQuotaCharge != NULL);
    01105     } else {
    01106         ppiQuotaCharge = NULL;
    01107     }
    01108
    01109     if (ppiQuotaCharge != NULL) {
    01110         ppiQuotaCharge->UserHandleCount--;
    01111     }
    01112
    01113     if (pheT->bFlags & HANDLEF_GRANTED) {
    01114         HMCleanupGrantedHandle(pheT->phead->h);
    01115         pheT->bFlags &= ~HANDLEF_GRANTED;
    01116     }
    01117
    01118 #if DBG
    01119     /*
    01120      *   performance counters
    01121      */
    01122     gaPerfhti[pheT->bType].lCount--;
    01123
    01124     if ((bCreateFlags & OCF_DESKTOPHEAP) && ((PDESKOBJHEAD)pobj)->rpdesk) {
    01125         pdesk = ((PDESKOBJHEAD)pobj)->rpdesk;
    01126         gaPerfhti[pheT->bType].lSize -= RtlSizeHeap(Win32HeapGetHandle(pdesk->pheapDesktop), 0, pobj);
    01127     } else if (bCreateFlags & OCF_SHAREDHEAP) {
    01128         gaPerfhti[pheT->bType].lSize -= RtlSizeHeap(Win32HeapGetHandle(gpvSharedAlloc), 0, pobj);
    01129     } else {
    01130         gaPerfhti[pheT->bType].lSize -= ExQueryPoolBlockSize(pobj, &notUsed);
    01131     }
    01132
    01133 #endif // DBG
    01134
    01135     if ((bCreateFlags & OCF_DESKTOPHEAP)) {
    01136 #if DBG
    01137         BOOL bSuccess;
    01138 #endif
    01139         UserAssert(((PDESKOBJHEAD)pobj)->rpdesk != NULL);
    01140
    01141         pdesk = ((PDESKOBJHEAD)pobj)->rpdesk;
    01142         UnlockDesktop(&((PDESKOBJHEAD)pobj)->rpdesk, LDU_OBJ_DESK, (ULONG_PTR)pobj);
    01143
    01144         if (pheT->bFlags & HANDLEF_POOL) {
    01145             UserFreePool(pobj);
    01146         } else {
    01147
    01148 #if DBG
    01149             bSuccess =
    01150 #endif
    01151             DesktopFree(pdesk, pobj);
    01152 #if DBG
    01153             if (!bSuccess) {
    01154                 /*
    01155                  * We would hit this assert in HYDRA trying to free the
    01156                  * mother desktop window which was allocated out of pool
    01157                  */
    01158                 RIPMSG1(RIP_ERROR, "Object already freed from desktop heap! %#p", pobj);
    01159             }
    01160 #endif
    01161         }
    01162
    01163     } else if (bCreateFlags & OCF_SHAREDHEAP) {
    01164         SharedFree(pobj);
    01165     } else {
    01166         UserFreePool(pobj);
    01167     }
    01168
    01169 #if DBG
    01170     /*
    01171      * Go through and delete the lock records, if they exist.
    01172      */
    01173     for (plrT = pheT->plr; plrT != NULL; plrT = plrNextT) {
    01174
    01175         /*
    01176          * Remember the next one before freeing this one.
    01177          */
    01178         plrNextT = plrT->plrNext;
    01179         FreeLockRecord((HANDLE)plrT);
    01180     }
    01181 #endif
    01182
    01183     /*
    01184      * Clear the handle contents. Need to remember the uniqueness across
    01185      * the clear. Also, advance uniqueness on free so that uniqueness checking
    01186      * against old handles also fails.
    01187      */
    01188     wUniqT = (WORD)((pheT->wUniq + 1) & HMUNIQBITS);
    01189     RtlZeroMemory(pheT, sizeof(HANDLEENTRY));
    01190     pheT->wUniq = wUniqT;
    01191
    01192     /*
    01193      * Change the handle type to TYPE_FREE so we know what type this handle
    01194      * is. (TYPE_FREE is defined as zero)
    01195      */
    01196     /* pheT->bType = TYPE_FREE; */
    01197     UserAssert(pheT->bType == TYPE_FREE);
    01198
    01199     /*
    01200      * Put the handle on the free list of the appropriate page.
    01201      */
    01202     php = gpHandlePages;
    01203     iheCurrent = pheT - gSharedInfo.aheList;
    01204     for (i = 0; i < gcHandlePages; ++i, ++php) {
    01205         if (iheCurrent < php->iheLimit) {
    01206             piheCurrentHead = (iheCurrent & 0x1 ? &php->iheFreeOdd : &php->iheFreeEven);
    01207             pheT->phead = (PHEAD)*piheCurrentHead;
    01208             *piheCurrentHead = iheCurrent;
    01209             DBGHMValidateFreeLists();
    01210             break;
    01211         }
    01212     }
    01213     /*
    01214      * We must have found it.
    01215      */
    01216     UserAssert(i < gcHandlePages);
    01217
    01218     UserAssert(pheT->pOwner == NULL);
    01219
    01220     DBGValidateHandleQuota();
    01221
    01222     return TRUE;
    01223 }
    01224
    01225
    01226 /***************************************************************************\
    01227 * HMMarkObjectDestroy
    01228 *
    01229 * Marks an object for destruction.
    01230 *
    01231 * Returns TRUE if the object can be destroyed; that is, if it's
    01232 * lock count is 0.
    01233 *
    01234 * 02-10-92 ScottLu      Created.
    01235 \***************************************************************************/
    01236
    01237 BOOL HMMarkObjectDestroy(
    01238     PVOID pobj)
    01239 {
    01240     PHE phe;
    01241
    01242     phe = HMPheFromObject(pobj);
    01243
    01244 #if DEBUGTAGS
    01245     /*
    01246      * Record where the object was marked for destruction.
    01247      */
    01248     if (IsDbgTagEnabled(DBGTAG_TrackLocks)) {
    01249         if (!(phe->bFlags & HANDLEF_DESTROY)) {
    01250             HMRecordLock(LOCKRECORD_MARKDESTROY, pobj, ((PHEAD)pobj)->cLockObj);
    01251         }
    01252     }
    01253 #endif
    01254
    01255     /*
    01256      * Set the destroy flag so our unlock code will know we're trying to
    01257      * destroy this object.
    01258      */
    01259     phe->bFlags |= HANDLEF_DESTROY;
    01260
    01261     /*
    01262      * If this object can't be destroyed, then CLEAR the HANDLEF_INDESTROY
    01263      * flag - because this object won't be currently "in destruction"!
    01264      * (if we didn't clear it, when it was unlocked it wouldn't get destroyed).
    01265      */
    01266     if (((PHEAD)pobj)->cLockObj != 0) {
    01267         phe->bFlags &= ~HANDLEF_INDESTROY;
    01268
    01269         /*
    01270          * Return FALSE because we can't destroy this object.
    01271          */
    01272         return FALSE;
    01273     }
    01274
    01275 #if DBG
    01276     /*
    01277      * Ensure that this function only returns TRUE once.
    01278      */
    01279     UserAssert(!(phe->bFlags & HANDLEF_MARKED_OK));
    01280     phe->bFlags |= HANDLEF_MARKED_OK;
    01281 #endif
    01282
    01283     /*
    01284      * Return TRUE because Lock count is zero - ok to destroy this object.
    01285      */
    01286     return TRUE;
    01287 }
    01288
    01289
    01290 /***************************************************************************\
    01291 * HMDestroyObject
    01292 *
    01293 * This routine marks an object for destruction, and frees it if
    01294 * it is unlocked.
    01295 *
    01296 * 10-13-94 JimA         Created.
    01297 \***************************************************************************/
    01298
    01299 BOOL HMDestroyObject(
    01300     PVOID pobj)
    01301 {
    01302     /*
    01303      * First mark the object for destruction.  This tells the locking code
    01304      * that we want to destroy this object when the lock count goes to 0.
    01305      * If this returns FALSE, we can't destroy the object yet (and can't get
    01306      * rid of security yet either.)
    01307      */
    01308
    01309     if (!HMMarkObjectDestroy(pobj))
    01310         return FALSE;
    01311
    01312     /*
    01313      * Ok to destroy...  Free the handle (which will free the object
    01314      * and the handle).
    01315      */
    01316     HMFreeObject(pobj);
    01317     return TRUE;
    01318 }
    01319
    01320 #if DBG
    01321
    01322 NTSTATUS
    01323 InitLockRecordLookaside()
    01324 {
    01325     LockRecordLookaside = UserAllocPoolNonPaged(sizeof(PAGED_LOOKASIDE_LIST),
    01326                                                 TAG_LOOKASIDE);
    01327     if (LockRecordLookaside == NULL) {
    01328         return STATUS_NO_MEMORY;
    01329     }
    01330
    01331     ExInitializePagedLookasideList(LockRecordLookaside,
    01332                                    NULL,
    01333                                    NULL,
    01334                                    SESSION_POOL_MASK,
    01335                                    sizeof(LOCKRECORD),
    01336                                    TAG_LOCKRECORD,
    01337                                    1000);
    01338     return STATUS_SUCCESS;
    01339 }
    01340
    01341 PLR AllocLockRecord()
    01342 {
    01343     PLR plr;
    01344
    01345     /*
    01346      * Allocate a LOCKRECORD structure.
    01347      */
    01348     if ((plr = ExAllocateFromPagedLookasideList(LockRecordLookaside)) == NULL) {
    01349         return NULL;
    01350     }
    01351
    01352     RtlZeroMemory(plr, sizeof(*plr));
    01353
    01354     return plr;
    01355 }
    01356
    01357
    01358 void FreeLockRecord(
    01359     PLR plr)
    01360 {
    01361     ExFreeToPagedLookasideList(LockRecordLookaside, plr);
    01362 }
    01363
    01364
    01365 /***************************************************************************\
    01366 * HMRecordLock
    01367 *
    01368 * This routine records a lock on a "lock list", so that locks and unlocks
    01369 * can be tracked in the debugger. Only called if DBGTAG_TrackLocks is enabled.
    01370 *
    01371 * 02-27-92 ScottLu      Created.
    01372 \***************************************************************************/
    01373 void HMRecordLock(
    01374     PVOID ppobj,
    01375     PVOID pobj,
    01376     DWORD cLockObj)
    01377 {
    01378     PHE   phe;
    01379     PLR   plr;
    01380     int   i;
    01381     ULONG hash;
    01382
    01383     phe = HMPheFromObject(pobj);
    01384
    01385     if ((plr = AllocLockRecord()) == NULL) {
    01386         RIPMSG0(RIP_ERROR, "HMRecordLock failed to allocate memory");
    01387         return;
    01388     }
    01389
    01390     /*
    01391      * Link it in front of the list
    01392      */
    01393     plr->plrNext = phe->plr;
    01394     phe->plr = plr;
    01395
    01396     /*
    01397      * This propably happens only for unmatched locks
    01398      */
    01399     if (((PHEAD)pobj)->cLockObj > cLockObj) {
    01400
    01401         RIPMSG3(RIP_WARNING, "Unmatched lock. ppobj %#p pobj %#p cLockObj %d",
    01402                ppobj, pobj, cLockObj);
    01403
    01404         i = (int)cLockObj;
    01405         i = -i;
    01406         cLockObj = (DWORD)i;
    01407     }
    01408
    01409     plr->ppobj    = ppobj;
    01410     plr->cLockObj = cLockObj;
    01411
    01412     GetStackTrace(1,
    01413                   LOCKRECORD_STACK,
    01414                   plr->trace,
    01415                   &hash);
    01416     return;
    01417 }
    01418 #endif // DBG
    01419
    01420
    01421 /***************************************************************************\
    01422 * HMLockObject
    01423 *
    01424 * This routine locks an object. This is a macro in retail systems.
    01425 *
    01426 * 02-24-92 ScottLu      Created.
    01427 \***************************************************************************/
    01428
    01429 #if DBG
    01430 void HMLockObject(
    01431     PVOID pobj)
    01432 {
    01433     HANDLE h;
    01434     PVOID  pobjValidate;
    01435
    01436     /*
    01437      * Validate by going through the handle entry so that we make sure pobj
    01438      * is not just pointing off into space. This may GP fault, but that's
    01439      * ok: this case should not ever happen if we're bug free.
    01440      */
    01441
    01442     h = HMPheFromObject(pobj)->phead->h;
    01443     pobjValidate = HMRevalidateCatHandle(h);
    01444     if (!pobj || pobj != pobjValidate) {
    01445         RIPMSG2(RIP_ERROR,
    01446                 "HMLockObject invalid object %#p, handle %#p",
    01447                 pobj, h);
    01448         return;
    01449     }
    01450
    01451     /*
    01452      * Inc the reference count.
    01453      */
    01454     ((PHEAD)pobj)->cLockObj++;
    01455
    01456     if (((PHEAD)pobj)->cLockObj == 0)
    01457         RIPMSG1(RIP_ERROR, "Object lock count has overflowed: %#p", pobj);
    01458 }
    01459 #endif // DBG
    01460
    01461
    01462 /***************************************************************************\
    01463 * HMUnlockObjectInternal
    01464 *
    01465 * This routine is called from the macro HMUnlockObject when an object's
    01466 * reference count drops to zero. This routine will destroy an object
    01467 * if is has been marked for destruction.
    01468 *
    01469 * 01-21-92 ScottLu      Created.
    01470 \***************************************************************************/
    01471
    01472 PVOID HMUnlockObjectInternal(
    01473     PVOID pobj)
    01474 {
    01475     PHE phe;
    01476
    01477     /*
    01478      * The object is not reference counted. If the object is not a zombie,
    01479      * return success because the object is still around.
    01480      */
    01481     phe = HMPheFromObject(pobj);
    01482     if (!(phe->bFlags & HANDLEF_DESTROY))
    01483         return pobj;
    01484
    01485     /*
    01486      * We're destroying the object based on an unlock... Make sure it isn't
    01487      * currently being destroyed! (It is valid to have lock counts go from
    01488      * 0 to != 0 to 0 during destruction... don't want recursion into
    01489      * the destroy routine.
    01490      */
    01491     if (phe->bFlags & HANDLEF_INDESTROY)
    01492         return pobj;
    01493
    01494     HMDestroyUnlockedObject(phe);
    01495     return NULL;
    01496 }
    01497
    01498
    01499 /***************************************************************************\
    01500 * HMAssignmentLock
    01501 *
    01502 * This api is used for structure and global variable assignment.
    01503 * Returns pobjOld if the object was *not* destroyed. Means the object is
    01504 * still valid.
    01505 *
    01506 * 02-24-92 ScottLu      Created.
    01507 \***************************************************************************/
    01508
    01509 PVOID FASTCALL HMAssignmentLock(
    01510     PVOID *ppobj,
    01511     PVOID pobj)
    01512 {
    01513     PVOID pobjOld;
    01514
    01515     pobjOld = *ppobj;
    01516     *ppobj = pobj;
    01517
    01518     /*
    01519      * Unlocks the old, locks the new.
    01520      */
    01521     if (pobjOld != NULL) {
    01522
    01523         /*
    01524          * if we are locking in the same object that is there then
    01525          * it is a no-op but we don't want to do the Unlock and the Lock
    01526          * because the unlock could free object and the lock would lock
    01527          * in a freed pointer; 6410.
    01528          */
    01529         if (pobjOld == pobj) {
    01530             return pobjOld;
    01531         }
    01532
    01533 #if DEBUGTAGS
    01534
    01535         /*
    01536          * Track assignment locks.
    01537          */
    01538         if (IsDbgTagEnabled(DBGTAG_TrackLocks)) {
    01539             if (!HMUnrecordLock(ppobj, pobjOld)) {
    01540                 HMRecordLock(ppobj, pobjOld, ((PHEAD)pobjOld)->cLockObj - 1);
    01541             }
    01542         }
    01543 #endif
    01544
    01545     }
    01546
    01547
    01548     if (pobj != NULL) {
    01549         UserAssert(pobj == HMValidateCatHandleNoSecure(((PHEAD)pobj)->h, TYPE_GENERIC));
    01550         if (HMIsMarkDestroy(pobj)) {
    01551             RIPERR2(ERROR_INVALID_PARAMETER,
    01552                     RIP_WARNING,
    01553                     "HMAssignmentLock, locking object %#p marked for destruction at %#p\n",
    01554                     pobj, ppobj);
    01555         }
    01556 #if DEBUGTAGS
    01557
    01558         /*
    01559          * Track assignment locks.
    01560          */
    01561         if (IsDbgTagEnabled(DBGTAG_TrackLocks)) {
    01562             HMRecordLock(ppobj, pobj, ((PHEAD)pobj)->cLockObj + 1);
    01563             if (HMIsMarkDestroy(pobj)) {
    01564
    01565                 RIPMSG2(RIP_WARNING,
    01566                         "Locking object %#p marked for destruction at %#p",
    01567                         pobj, ppobj);
    01568             }
    01569         }
    01570 #endif
    01571         HMLockObject(pobj);
    01572     }
    01573
    01574 /*
    01575  * This unlock has been moved from up above, so that we implement a
    01576  * "lock before unlock" strategy.  Just in case pobjOld was the
    01577  * only object referencing pobj, pobj won't go away when we unlock
    01578  * pobjNew -- it will have been locked above.
    01579  */
    01580
    01581     if (pobjOld) {
    01582         pobjOld = HMUnlockObject(pobjOld);
    01583     }
    01584
    01585     return pobjOld;
    01586 }
    01587
    01588
    01589 /***************************************************************************\
    01590 * HMAssignmentLock
    01591 *
    01592 * This api is used for structure and global variable assignment.
    01593 * Returns pobjOld if the object was *not* destroyed. Means the object is
    01594 * still valid.
    01595 *
    01596 * 02-24-92 ScottLu      Created.
    01597 \***************************************************************************/
    01598
    01599 PVOID FASTCALL HMAssignmentUnlock(
    01600     PVOID *ppobj)
    01601 {
    01602     PVOID pobjOld;
    01603
    01604     pobjOld = *ppobj;
    01605     *ppobj = NULL;
    01606
    01607     /*
    01608      * Unlocks the old, locks the new.
    01609      */
    01610     if (pobjOld != NULL) {
    01611
    01612 #if DEBUGTAGS
    01613
    01614         /*
    01615          * Track assignment locks.
    01616          */
    01617         if (IsDbgTagEnabled(DBGTAG_TrackLocks)) {
    01618             if (!HMUnrecordLock(ppobj, pobjOld)) {
    01619                 HMRecordLock(ppobj, pobjOld, ((PHEAD)pobjOld)->cLockObj - 1);
    01620             }
    01621         }
    01622 #endif
    01623         pobjOld = HMUnlockObject(pobjOld);
    01624     }
    01625
    01626     return pobjOld;
    01627 }
    01628
    01629
    01630 /***************************************************************************\
    01631 * IsValidThreadLock
    01632 *
    01633 * This routine checks to make sure that the thread lock structures passed
    01634 * in are valid.
    01635 *
    01636 * 03-17-92 ScottLu      Created.
    01637 * 02-22-99 MCostea      Also validate the shadow of the stack TL
    01638 *                       from gThreadLocksArray
    01639 \***************************************************************************/
    01640 #if DBG
    01641 VOID IsValidThreadLock(PTHREADINFO pti, PTL ptl, ULONG_PTR dwLimit, BOOLEAN fHM)
    01642 {
    01643     /*
    01644      * Check that ptl is a valid stack address
    01645      * Allow (ULONG_PTR)ptl == dwLimit so we can call ValidateThreadLocks passing
    01646      *  the address of the last thing we locked.
    01647      */
    01648     UserAssert((ULONG_PTR)ptl >= dwLimit);
    01649     UserAssert((ULONG_PTR)ptl < (ULONG_PTR)KeGetCurrentThread()->StackBase);
    01650     /*
    01651      * Check ptl owner.
    01652      */
    01653     UserAssert(ptl->pW32Thread == (PW32THREAD)pti);
    01654     /*
    01655      * If this is an HM object, verify handle and lock count (guess max value)
    01656      */
    01657     if (fHM && (ptl->pobj != NULL)) {
    01658         /*
    01659          * The locked object could be a destroyed object.
    01660          */
    01661         UserAssert(ptl->pobj == HtoPqCat(PtoHq(ptl->pobj)));
    01662         if (((PHEAD)ptl->pobj)->cLockObj >= 32000) {
    01663             RIPMSG2(RIP_WARNING, "IsValidThreadLock: Object %#p has %d locks", ptl->pobj, ((PHEAD)ptl->pobj)->cLockObj);
    01664         }
    01665     }
    01666     /*
    01667      * Make sure the shadow in gThreadLocksArray is doing fine
    01668      */
    01669     UserAssert(ptl->ptl->ptl == ptl);
    01670 }
    01671 #endif
    01672
    01673 /***************************************************************************\
    01674 * ValidateThreadLocks
    01675 *
    01676 * This routine validates the thread lock list of a thread.
    01677 *
    01678 * 03-10-92 ScottLu      Created.
    01679 \***************************************************************************/
    01680
    01681 #if DBG
    01682 ULONG ValidateThreadLocks(PTL NewLock, PTL OldLock, ULONG_PTR dwLimit, BOOLEAN fHM)
    01683 {
    01684     UINT uTLCount = 0;
    01685     PTL ptlTopLock = OldLock;
    01686     PTHREADINFO ptiCurrent;
    01687
    01688     BEGIN_REENTERCRIT();
    01689
    01690     ptiCurrent = PtiCurrent();
    01691
    01692     /*
    01693      * Validate the new thread lock.
    01694      */
    01695     if (NewLock != NULL) {
    01696         UserAssert(NewLock->next == OldLock);
    01697         IsValidThreadLock(ptiCurrent, NewLock, dwLimit, fHM);
    01698         uTLCount++;
    01699     }
    01700
    01701     /*
    01702      * Loop through the list of thread locks and check to make sure the
    01703      * new lock is not in the list and that list is valid.
    01704      */
    01705     while (OldLock != NULL) {
    01706         /*
    01707          * The new lock must not be the same as the old lock.
    01708          */
    01709         UserAssert(NewLock != OldLock);
    01710         /*
    01711          * Validate the old thread lock.
    01712          */
    01713         IsValidThreadLock(ptiCurrent, OldLock, dwLimit, fHM);
    01714         uTLCount++;
    01715         OldLock = OldLock->next;
    01716     }
    01717     /*
    01718      * If this is thread lock, set uTLCount, else verify it
    01719      */
    01720     if (NewLock != NULL) {
    01721         NewLock->uTLCount = uTLCount;
    01722     } else {
    01723         if (ptlTopLock == NULL) {
    01724             RIPMSG0(RIP_WARNING, "ptlTopLock is NULL, the system will AV now");
    01725         }
    01726         UserAssert(uTLCount == ptlTopLock->uTLCount);
    01727     }
    01728
    01729     END_REENTERCRIT();
    01730
    01731     return uTLCount;
    01732 }
    01733 #endif
    01734
    01735
    01736 /***************************************************************************\
    01737 * CreateShadowTL
    01738 *
    01739 * This function creates a shaddow for the stack allocated ptl parameter
    01740 * in the global thread locks arrays
    01741 *
    01742 * 08-04-99 MCostea      Created.
    01743 \***************************************************************************/
    01744
    01745 #if DBG
    01746 void
    01747 CreateShadowTL(PTL ptl)
    01748 {
    01749     PTL pTLNextFree;
    01750     if (gFreeTLList->next == NULL) {
    01751         UserAssert(gcThreadLocksArraysAllocated < MAX_THREAD_LOCKS_ARRAYS &&
    01752                    "No more room in gpaThreadLocksArrays!  The system will bugcheck.");
    01753         gFreeTLList->next = gpaThreadLocksArrays[gcThreadLocksArraysAllocated] =
    01754             UserAllocPoolZInit(sizeof(TL)*MAX_THREAD_LOCKS, TAG_GLOBALTHREADLOCK);
    01755         if (gFreeTLList->next == NULL) {
    01756             UserAssert("Can't allocate memory for gpaThreadLocksArrays: the system will bugcheck soon!");
    01757         }
    01758         InitGlobalThreadLockArray(gcThreadLocksArraysAllocated);
    01759         gcThreadLocksArraysAllocated++;
    01760     }
    01761     pTLNextFree = gFreeTLList->next;
    01762     RtlCopyMemory(gFreeTLList, ptl, sizeof(TL));
    01763     gFreeTLList->ptl = ptl;
    01764     ptl->ptl = gFreeTLList;
    01765     gFreeTLList = pTLNextFree;
    01766 }
    01767 #endif // DBG
    01768
    01769 /***************************************************************************\
    01770 * ThreadLock
    01771 *
    01772 * This api is used for locking objects across callbacks, so they are still
    01773 * there when the callback returns.
    01774 *
    01775 * 03-04-92 ScottLu      Created.
    01776 \***************************************************************************/
    01777
    01778 #if DBG
    01779 void
    01780 ThreadLock(
    01781     PVOID pobj,
    01782     PTL ptl)
    01783
    01784 {
    01785
    01786     PTHREADINFO ptiCurrent;
    01787     PVOID pfnT;
    01788
    01789
    01790     /*
    01791      * This is a handy place, because it is called so often, to see if User is
    01792      * eating up too much stack.
    01793      */
    01794     UserAssert(((ULONG_PTR)&pfnT - (ULONG_PTR)KeGetCurrentThread()->StackLimit) > KERNEL_STACK_MINIMUM_RESERVE);
    01795
    01796     /*
    01797      * Store the address of the object in the thread lock structure and
    01798      * link the structure into the thread lock list.
    01799      *
    01800      * N.B. The lock structure is always linked into the thread lock list
    01801      *      regardless of whether the object address is NULL. The reason
    01802      *      this is done is so the lock address does not need to be passed
    01803      *      to the unlock function since the first entry in the lock list
    01804      *      is always the entry to be unlocked.
    01805      */
    01806
    01807     UserAssert(!(PpiCurrent()->W32PF_Flags & W32PF_TERMINATED));
    01808     ptiCurrent = PtiCurrent();
    01809     UserAssert(ptiCurrent);
    01810
    01811     /*
    01812      * Get the callers address and validate the thread lock list.
    01813      */
    01814     RtlGetCallersAddress(&ptl->pfnCaller, &pfnT);
    01815     ptl->pW32Thread = (PW32THREAD)ptiCurrent;
    01816
    01817     ptl->next = ptiCurrent->ptl;
    01818     ptiCurrent->ptl = ptl;
    01819     ptl->pobj = pobj;
    01820     if (pobj != NULL) {
    01821         HMLockObject(pobj);
    01822     }
    01823     CreateShadowTL(ptl);
    01824     ValidateThreadLocks(ptl, ptl->next, (ULONG_PTR)&pobj, TRUE);
    01825     return;
    01826 }
    01827 #endif
    01828
    01829
    01830 /***************************************************************************\
    01831 * ThreadLockExchange
    01832 *
    01833 * Reuses a TL structure by locking the new object and unlocking
    01834 * the old one. This is used where you enumerate a list of
    01835 * structure locked objects, e.g. the window list.
    01836 *
    01837 * History:
    01838 * 05-Mar-1997 adams     Created.
    01839 \***************************************************************************/
    01840
    01841 #if DBG
    01842 PVOID
    01843 ThreadLockExchange(PVOID pobj, PTL ptl)
    01844 {
    01845     PTHREADINFO ptiCurrent;
    01846     PVOID       pobjOld;
    01847     PVOID       pfnT;
    01848
    01849     /*
    01850      * This is a handy place, because it is called so often, to see if User is
    01851      * eating up too much stack.
    01852      */
    01853     UserAssert((ULONG_PTR)&pfnT - (ULONG_PTR)KeGetCurrentThread()->StackLimit > KERNEL_STACK_MINIMUM_RESERVE);
    01854
    01855     /*
    01856      * Store the address of the object in the thread lock structure and
    01857      * link the structure into the thread lock list.
    01858      *
    01859      * N.B. The lock structure is always linked into the thread lock list
    01860      *      regardless of whether the object address is NULL. The reason
    01861      *      this is done is so the lock address does not need to be passed
    01862      *      to the unlock function since the first entry in the lock list
    01863      *      is always the entry to be unlocked.
    01864      */
    01865
    01866     UserAssert(!(PpiCurrent()->W32PF_Flags & W32PF_TERMINATED));
    01867     ptiCurrent = PtiCurrent();
    01868     UserAssert(ptiCurrent);
    01869
    01870     /*
    01871      * Get the callers address.
    01872      */
    01873     RtlGetCallersAddress(&ptl->pfnCaller, &pfnT);
    01874     UserAssert(ptl->pW32Thread == (PW32THREAD)ptiCurrent);
    01875
    01876     /*
    01877      * Remember the old object.
    01878      */
    01879     pobjOld = ptl->pobj;
    01880
    01881     /*
    01882      * Store and lock the new object. It is important to do this step
    01883      * before unlocking the old object, since the new object might be
    01884      * structure locked by the old object.
    01885      */
    01886     ptl->pobj = pobj;
    01887     if (pobj != NULL) {
    01888         HMLockObject(pobj);
    01889     }
    01890
    01891     /*
    01892      * Unlock the old object.
    01893      */
    01894     if (pobjOld) {
    01895         pobjOld = HMUnlockObject((PHEAD)pobjOld);
    01896     }
    01897     /*
    01898      * Validate the entire thread lock list.
    01899      */
    01900     ValidateThreadLocks(NULL, ptiCurrent->ptl, (ULONG_PTR)&pobj, TRUE);
    01901     {
    01902         /*
    01903          * Maintain gFreeTLList
    01904          */
    01905         UserAssert(ptl->ptl->ptl == ptl);
    01906         UserAssert(ptl->ptl->pobj == pobjOld);
    01907         ptl->ptl->pobj = pobj;
    01908         ptl->ptl->pfnCaller = ptl->pfnCaller;
    01909     }
    01910
    01911     return pobjOld;
    01912 }
    01913 #endif
    01914
    01915
    01916 /*
    01917  * The thread locking routines should be optimized for time, not size,
    01918  * since they get called so often.
    01919  */
    01920 #pragma optimize("t", on)
    01921
    01922 /***************************************************************************\
    01923 * ThreadUnlock1
    01924 *
    01925 * This api unlocks a thread locked object. Returns pobj if the object
    01926 * was *not* destroyed (meaning the pointer is still valid).
    01927 *
    01928 * N.B. In a free build the first entry in the thread lock list is unlocked.
    01929 *
    01930 * 03-04-92 ScottLu      Created.
    01931 \***************************************************************************/
    01932
    01933 #if DBG
    01934 PVOID
    01935 ThreadUnlock1(
    01936     PTL ptlIn)
    01937 #else
    01938 PVOID
    01939 ThreadUnlock1(
    01940     VOID)
    01941 #endif
    01942 {
    01943     PHEAD phead;
    01944     PTHREADINFO ptiCurrent;
    01945     PTL ptl;
    01946
    01947     ptiCurrent = PtiCurrent();
    01948     ptl = ptiCurrent->ptl;
    01949     UserAssert(ptl != NULL);
    01950      /*
    01951       * Validate the thread lock list.
    01952       */
    01953      ValidateThreadLocks(NULL, ptl, (ULONG_PTR)&ptlIn, TRUE);
    01954     /*
    01955      * Make sure the caller wants to unlock the top lock.
    01956      */
    01957     UserAssert(ptlIn == ptl);
    01958     ptiCurrent->ptl = ptl->next;
    01959     /*
    01960      * If the object address is not NULL, then unlock the object.
    01961      */
    01962     phead = (PHEAD)(ptl->pobj);
    01963     if (phead != NULL) {
    01964
    01965         /*
    01966          * Unlock the object.
    01967          */
    01968
    01969         phead = (PHEAD)HMUnlockObject(phead);
    01970     }
    01971 #if DBG
    01972     {
    01973         /*
    01974          * Remove the corresponding element from gFreeTLList
    01975          */
    01976         ptl->ptl->next = gFreeTLList;
    01977         ptl->ptl->uTLCount += TL_FREED_PATTERN;
    01978         gFreeTLList = ptl->ptl;
    01979     }
    01980 #endif
    01981     return (PVOID)phead;
    01982 }
    01983
    01984 /*
    01985  * Switch back to default optimization.
    01986  */
    01987 #pragma optimize("", on)
    01988
    01989 /***************************************************************************\
    01990 * CheckLock
    01991 *
    01992 * This routine only exists in DBG builds - it checks to make sure objects
    01993 * are thread locked.
    01994 *
    01995 * 03-09-92 ScottLu      Created.
    01996 \***************************************************************************/
    01997
    01998 #if DBG
    01999 void CheckLock(
    02000     PVOID pobj)
    02001 {
    02002     PTHREADINFO ptiCurrent = PtiCurrentShared();
    02003     PTL ptl;
    02004
    02005     if (pobj == NULL) {
    02006         return;
    02007     }
    02008
    02009     /*
    02010      * Validate all locks first
    02011      */
    02012     UserAssert(ptiCurrent != NULL);
    02013     ValidateThreadLocks(NULL, ptiCurrent->ptl, (ULONG_PTR)&pobj, TRUE);
    02014
    02015     for (ptl = ptiCurrent->ptl; ptl != NULL; ptl=ptl->next) {
    02016         if (ptl->pobj == pobj)
    02017             return;
    02018     }
    02019
    02020     /*
    02021      * WM_FINALDESTROY messages get sent without thread locking, so if
    02022      * marked for destruction, don't print the message.
    02023      */
    02024     if (HMPheFromObject(pobj)->bFlags & HANDLEF_DESTROY)
    02025         return;
    02026
    02027     RIPMSG1(RIP_ERROR, "Object not thread locked! %#p", pobj);
    02028 }
    02029 #endif
    02030
    02031
    02032 /***************************************************************************\
    02033 * HMDestroyUnlockedObject
    02034 *
    02035 * Destroy an object based on an unlock or cleanup from thread or
    02036 * process termination.
    02037 *
    02038 * The functions called to destroy a particular object can be called
    02039 * directly from code as well as the result of an unlock. Destroy
    02040 * functions have the following 4 sections.
    02041 *
    02042 *     (1) Remove the object from a list or other global
    02043 *     context. If the destroy function has to leave the
    02044 *     critical section (e.g. make an xxx call), it must
    02045 *     do so in this step.
    02046 *
    02047 *     (2) Call HMMarkDestroy, and return if HMMarkDestroy
    02048 *     returns FALSE. This is required.
    02049 *
    02050 *     (3) Destroy resources held by the objects - locks to
    02051 *     other objects, alloc'd memory, etc. This is required.
    02052 *
    02053 *     (4) Free the memory of the object and its handle by calling
    02054 *     HMFreeObject. This is required.
    02055 *
    02056 * Note that if the object is locked when it's destroy function
    02057 * is called directly, step (1) will be repeated when the object is
    02058 * unlocked. We should probably check for this in the destroy functions,
    02059 * which we currently do not do.
    02060 *
    02061 * Note that we could be destroying this object in a context different
    02062 * than the one that created it. This is very important to understand
    02063 * since in lots of code the "current thread" is referenced and assumed
    02064 * as the creator.
    02065 *
    02066 * 02-10-92 ScottLu      Created.
    02067 \***************************************************************************/
    02068
    02069 void HMDestroyUnlockedObject(
    02070     PHE phe)
    02071 {
    02072     BEGINATOMICCHECK();
    02073
    02074     /*
    02075      * Remember that we're destroying this object so we don't try to destroy
    02076      * it again when the lock count goes from != 0 to 0 (especially true
    02077      * for thread locks).
    02078      */
    02079     phe->bFlags |= HANDLEF_INDESTROY;
    02080
    02081     /*
    02082      * This'll call the destroy handler for this object type.
    02083      */
    02084     (*gahti[phe->bType].fnDestroy)(phe->phead);
    02085
    02086     /*
    02087      * HANDLEF_INDESTROY is supposed to be cleared either by HMMarkObjectDestroy
    02088      *  or by HMFreeObject; the destroy handler was supposed to call at least
    02089      *  the former.
    02090      */
    02091     UserAssert(!(phe->bFlags & HANDLEF_INDESTROY));
    02092
    02093     /*
    02094      * If the object wasn't freed, it must be marked as destroyed
    02095      *  and must have a lock count
    02096      */
    02097     UserAssert((phe->bType == TYPE_FREE)
    02098                 || ((phe->bFlags & HANDLEF_DESTROY) && (phe->phead->cLockObj > 0)));
    02099
    02100     ENDATOMICCHECK();
    02101 }
    02102
    02103
    02104 /***************************************************************************\
    02105 * HMChangeOwnerThread
    02106 *
    02107 * Changes the owning thread of an object.
    02108 *
    02109 * 09-13-93 JimA         Created.
    02110 \***************************************************************************/
    02111
    02112 VOID HMChangeOwnerThread(
    02113     PVOID pobj,
    02114     PTHREADINFO pti)
    02115 {
    02116     PHE phe = HMPheFromObject(pobj);
    02117     PTHREADINFO ptiOld = ((PTHROBJHEAD)(pobj))->pti;
    02118     PWND pwnd;
    02119     PPCLS ppcls;
    02120     PPROCESSINFO   ppi;
    02121
    02122     UserAssert(HMObjectFlags(pobj) & OCF_THREADOWNED);
    02123     UserAssert(pti != NULL);
    02124
    02125     ((PTHREADINFO)phe->pOwner)->ppi->UserHandleCount--;
    02126
    02127     ((PTHROBJHEAD)pobj)->pti = phe->pOwner = pti;
    02128
    02129     ((PTHREADINFO)phe->pOwner)->ppi->UserHandleCount++;
    02130
    02131     DBGValidateHandleQuota();
    02132
    02133     /*
    02134      * If this is a window, update the window counts.
    02135      */
    02136     switch (phe->bType) {
    02137     case TYPE_WINDOW:
    02138         /*
    02139          * Desktop thread used to hit this assert in HYDRA
    02140          * because pti == ptiOld
    02141          */
    02142         UserAssert(ptiOld->cWindows > 0 || ptiOld == pti);
    02143         pti->cWindows++;
    02144         ptiOld->cWindows--;
    02145
    02146         pwnd = (PWND)pobj;
    02147
    02148         /*
    02149          * Make sure thread visible window count is properly updated.
    02150          */
    02151         if (TestWF(pwnd, WFVISIBLE) && FVisCountable(pwnd)) {
    02152             pti->cVisWindows++;
    02153             ptiOld->cVisWindows--;
    02154         }
    02155
    02156         /*
    02157          * If the owning process is changing, fix up
    02158          * the window class.
    02159          */
    02160         if (pti->ppi != ptiOld->ppi) {
    02161
    02162             ppcls = GetClassPtr(pwnd->pcls->atomClassName, pti->ppi, hModuleWin);
    02163
    02164             if (ppcls == NULL) {
    02165                 if (pwnd->head.rpdesk)
    02166                     ppi = pwnd->head.rpdesk->rpwinstaParent->pTerm->ptiDesktop->ppi;
    02167                 else
    02168                     ppi = PpiCurrent();
    02169                 ppcls = GetClassPtr(gpsi->atomSysClass[ICLS_ICONTITLE], ppi, hModuleWin);
    02170             }
    02171             UserAssert(ppcls);
    02172
    02173             /*
    02174              * The window is either destroyed or the desktop of the class is
    02175              * the same as the window's desktop
    02176              */
    02177             UserAssert((*ppcls)->rpdeskParent == pwnd->head.rpdesk ||
    02178                        TestWF(pwnd, WFDESTROYED));
    02179
    02180             DereferenceClass(pwnd);
    02181             pwnd->pcls = *ppcls;
    02182             pwnd->pcls->cWndReferenceCount++;
    02183         }
    02184         break;
    02185
    02186     case TYPE_HOOK:
    02187         /*
    02188          * If this is a global hook, remember this hook's desktop so we'll be
    02189          * able to unlink it later (gptiRit might switch to a different desktop
    02190          * at any time).
    02191          */
    02192         UserAssert(!!(((PHOOK)pobj)->flags & HF_GLOBAL) ^ (((PHOOK)pobj)->ptiHooked != NULL));
    02193         if (((PHOOK)pobj)->flags & HF_GLOBAL) {
    02194             UserAssert(pti == gptiRit);
    02195             LockDesktop(&((PHOOK)pobj)->rpdesk, ptiOld->rpdesk, LDL_HOOK_DESK, 0);
    02196         } else {
    02197             /*
    02198              * This must be a hook on another thread or it was supposed to be
    02199              *  gone by now.
    02200              */
    02201             UserAssert(((PHOOK)pobj)->ptiHooked != ptiOld);
    02202         }
    02203         break;
    02204
    02205     default:
    02206         break;
    02207     }
    02208 }
    02209
    02210 /***************************************************************************\
    02211 * HMChangeOwnerProcess
    02212 *
    02213 * Changes the owning process of an object.
    02214 *
    02215 * 04-15-97 JerrySh      Created.
    02216 * 09-23-97 GerardoB     Changed parameters (and name) so HMDestroyUnlockedObject
    02217 *                        could use this function (instead of duplicating the code there)
    02218 \***************************************************************************/
    02219
    02220 VOID HMChangeOwnerPheProcess(
    02221     PHE phe,
    02222     PTHREADINFO pti)
    02223 {
    02224     PPROCESSINFO ppiOwner = (PPROCESSINFO)(phe->pOwner);
    02225     PVOID pobj = phe->phead;
    02226
    02227     UserAssert(HMObjectFlags(pobj) & OCF_PROCESSOWNED);
    02228     UserAssert(pti != NULL);
    02229     /*
    02230      * Dec current owner handle count
    02231      */
    02232     ppiOwner->UserHandleCount--;
    02233     /*
    02234      * hTaskWow
    02235      */
    02236     if ((pti->TIF_flags & TIF_16BIT) && (pti->ptdb)) {
    02237         ((PPROCOBJHEAD)pobj)->hTaskWow = pti->ptdb->hTaskWow;
    02238     } else {
    02239         ((PPROCOBJHEAD)pobj)->hTaskWow = 0;
    02240     }
    02241     /*
    02242      * ppi
    02243      */
    02244     if (gahti[phe->bType].bObjectCreateFlags & OCF_MARKPROCESS) {
    02245         ((PPROCMARKHEAD)pobj)->ppi = pti->ppi;
    02246     }
    02247     /*
    02248      * Set new owner in handle entry
    02249      */
    02250     phe->pOwner = pti->ppi;
    02251     /*
    02252      * Inc new owner handle count
    02253      */
    02254     ((PPROCESSINFO)(phe->pOwner))->UserHandleCount++;
    02255     /*
    02256      * If the handle is a cursor, adjust GDI cursor handle count
    02257      */
    02258     if (phe->bType == TYPE_CURSOR) {
    02259         GreDecQuotaCount((PW32PROCESS)ppiOwner);
    02260         GreIncQuotaCount((PW32PROCESS)phe->pOwner);
    02261
    02262         if (((PCURSOR)pobj)->hbmColor) {
    02263             GreDecQuotaCount((PW32PROCESS)ppiOwner);
    02264             GreIncQuotaCount((PW32PROCESS)phe->pOwner);
    02265         }
    02266     }
    02267
    02268     DBGValidateHandleQuota();
    02269 }
    02270
    02271 /***************************************************************************\
    02272 * DestroyThreadsObjects
    02273 *
    02274 * Goes through the handle table list and destroy all objects owned by this
    02275 * thread, because the thread is going away (either nicely, it faulted, or
    02276 * was terminated). It is ok to destroy the objects in any order, because
    02277 * object locking will ensure that they get destroyed in the right order.
    02278 *
    02279 * This routine gets called in the context of the thread that is exiting.
    02280 *
    02281 * 02-08-92 ScottLu      Created.
    02282 \***************************************************************************/
    02283
    02284 VOID DestroyThreadsObjects()
    02285 {
    02286     PTHREADINFO ptiCurrent;
    02287     HANDLEENTRY volatile * (*pphe);
    02288     PHE pheT;
    02289     DWORD i;
    02290
    02291     ptiCurrent = PtiCurrent();
    02292     DBGValidateHandleQuota();
    02293
    02294     /*
    02295      * Before any window destruction occurs, we need to destroy any dcs
    02296      * in use in the dc cache. When a dc is checked out, it is marked owned,
    02297      * which makes gdi's process cleanup code delete it when a process
    02298      * goes away. We need to similarly destroy the cache entry of any dcs
    02299      * in use by the exiting process.
    02300      */
    02301     DestroyCacheDCEntries(ptiCurrent);
    02302
    02303     /*
    02304      * Remove any thread locks that may exist for this thread.
    02305      */
    02306     while (ptiCurrent->ptl != NULL) {
    02307
    02308         UserAssert((ULONG_PTR)ptiCurrent->ptl > (ULONG_PTR)&i);
    02309         UserAssert((ULONG_PTR)ptiCurrent->ptl < (ULONG_PTR)KeGetCurrentThread()->StackBase);
    02310         ThreadUnlock(ptiCurrent->ptl);
    02311     }
    02312
    02313     /*
    02314      * CleanupPool stuff must happen before handle table clean up (as it always has been).
    02315      * This is because SMWPs can be HM objects and still be locked in ptlPool.
    02316      * If the handle is destroyed first (and it's not locked) we would end up with a
    02317      *  bogus pointer in ptlPool. If ptlPool is cleaned up first, the handle will be freed
    02318      *  or properly preserved if locked.
    02319      */
    02320     CleanupW32ThreadLocks((PW32THREAD)ptiCurrent);
    02321
    02322     /*
    02323      * Eventhough HMDestroyUnlockedObject might call xxxDestroyWindow, the
    02324      *  following loop is not supposed to leave the critical section. We must
    02325      *  have called PatchThreadWindows before coming here.
    02326      */
    02327     BEGINATOMICCHECK();
    02328
    02329     /*
    02330      * Loop through the table destroying all objects created by the current
    02331      * thread. All objects will get destroyed in their proper order simply
    02332      * because of the object locking.
    02333      */
    02334     pphe = &gSharedInfo.aheList;
    02335     for (i = 0; i <= giheLast; i++) {
    02336         /*
    02337          * This pointer is done this way because it can change when we leave
    02338          * the critical section below.  The above volatile ensures that we
    02339          * always use the most current value
    02340          */
    02341         pheT = (PHE)((*pphe) + i);
    02342
    02343         /*
    02344          * Check against free before we look at pti... because pq is stored
    02345          * in the object itself, which won't be there if TYPE_FREE.
    02346          */
    02347         if (pheT->bType == TYPE_FREE)
    02348             continue;
    02349
    02350         /*
    02351          * If a menu refererences a window owned by this thread, unlock
    02352          * the window.  This is done to prevent calling xxxDestroyWindow
    02353          * during process cleanup.
    02354          */
    02355         if (gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED) {
    02356             if (pheT->bType == TYPE_MENU) {
    02357                 PWND pwnd = ((PMENU)pheT->phead)->spwndNotify;
    02358
    02359                 if (pwnd != NULL && GETPTI(pwnd) == ptiCurrent)
    02360                     Unlock(&((PMENU)pheT->phead)->spwndNotify);
    02361             }
    02362             continue;
    02363         }
    02364
    02365         /*
    02366          * Destroy those objects created by this queue.
    02367          */
    02368         if ((PTHREADINFO)pheT->pOwner != ptiCurrent)
    02369             continue;
    02370
    02371         UserAssert(gahti[pheT->bType].bObjectCreateFlags & OCF_THREADOWNED);
    02372
    02373         /*
    02374          * Make sure this object isn't already marked to be destroyed - we'll
    02375          * do no good if we try to destroy it now since it is locked.
    02376          */
    02377         if (pheT->bFlags & HANDLEF_DESTROY) {
    02378             continue;
    02379         }
    02380
    02381         /*
    02382          * Destroy this object.
    02383          */
    02384         HMDestroyUnlockedObject(pheT);
    02385     }
    02386
    02387     ENDATOMICCHECK();
    02388     DBGValidateHandleQuota();
    02389 }
    02390
    02391 #if DBG
    02392 VOID ShowLocks(
    02393     PHE phe)
    02394 {
    02395     PLR plr = phe->plr;
    02396     INT c;
    02397
    02398     RIPMSG2(RIP_WARNING | RIP_THERESMORE,
    02399             "Lock records for %s %#p:",
    02400             gahti[phe->bType].szObjectType, phe->phead->h);
    02401     /*
    02402      * We have the handle entry: 'head' and 'he' are both filled in. Dump
    02403      * the lock records. Remember the first record is the last transaction!!
    02404      */
    02405     c = 0;
    02406     while (plr != NULL) {
    02407         char achPrint[80];
    02408
    02409         if (plr->ppobj == LOCKRECORD_MARKDESTROY) {
    02410             strcpy(achPrint, "Destroyed with");
    02411         } else if ((int)plr->cLockObj <= 0) {
    02412             strcpy(achPrint, "        Unlock");
    02413         } else {
    02414             /*
    02415              * Find corresponding unlock;
    02416              */
    02417             {
    02418                PLR plrUnlock;
    02419                DWORD cT;
    02420                DWORD cUnlock;
    02421
    02422                plrUnlock = phe->plr;
    02423                cT =  0;
    02424                cUnlock = (DWORD)-1;
    02425
    02426                while (plrUnlock != plr) {
    02427                    if (plrUnlock->ppobj == plr->ppobj) {
    02428                        if ((int)plrUnlock->cLockObj <= 0) {
    02429                            // a matching unlock found
    02430                            cUnlock = cT;
    02431                        } else {
    02432                            // the unlock #cUnlock matches this lock #cT, thus
    02433                            // #cUnlock is not the unlock we were looking for.
    02434                            cUnlock = (DWORD)-1;
    02435                        }
    02436                    }
    02437                    plrUnlock = plrUnlock->plrNext;
    02438                    cT++;
    02439                }
    02440                if (cUnlock == (DWORD)-1) {
    02441                    /*
    02442                     * Corresponding unlock not found!
    02443                     * This may not mean something is wrong: the structure
    02444                     * containing the pointer to the object may have moved
    02445                     * during a reallocation.  This can cause ppobj at Unlock
    02446                     * time to differ from that recorded at Lock time.
    02447                     * (Warning: moving structures like this may cause a Lock
    02448                     * and an Unlock to be misidentified as a pair, if by a
    02449                     * stroke of incredibly bad luck, the new location of a
    02450                     * pointer to an object is now where an old pointer to the
    02451                     * same object used to be)
    02452                     */
    02453                    sprintf(achPrint, "Unmatched Lock");
    02454                } else {
    02455                    sprintf(achPrint, "lock   #%ld", cUnlock);
    02456                }
    02457             }
    02458         }
    02459
    02460         RIPMSG4(RIP_WARNING | RIP_NONAME | RIP_THERESMORE,
    02461                 "        %s cLock=%d, pobj at %#p, code at %#p",
    02462                 achPrint,
    02463                 abs((int)plr->cLockObj),
    02464                 plr->ppobj,
    02465                 plr->trace[0]);
    02466
    02467         plr = plr->plrNext;
    02468         c++;
    02469     }
    02470
    02471     RIPMSG1(RIP_WARNING | RIP_NONAME, "        0x%lx records", c);
    02472 }
    02473 #endif
    02474
    02475 void FixupCursor(
    02476     PCURSOR      pcur,
    02477     PPROCESSINFO ppi)
    02478 {
    02479     int   i;
    02480     PACON pacon = (PACON)pcur;
    02481
    02482     if (pcur->head.ppi == NULL) {
    02483         pcur->head.ppi = ppi;
    02484     }
    02485
    02486     if (pacon->CURSORF_flags & CURSORF_ACON) {
    02487         for (i = 0; i < pacon->cpcur; i++) {
    02488
    02489             UserAssert(pacon->aspcur[i]->CURSORF_flags & CURSORF_ACONFRAME);
    02490
    02491             if (pacon->aspcur[i]->head.ppi == NULL) {
    02492                 pacon->aspcur[i]->head.ppi = ppi;
    02493             }
    02494         }
    02495     }
    02496 }
    02497
    02498 /***************************************************************************\
    02499 * DestroyProcessesObjects
    02500 *
    02501 * Goes through the handle table list and destroy all objects owned by this
    02502 * process, because the process is going away (either nicely, it faulted, or
    02503 * was terminated). It is ok to destroy the objects in any order, because
    02504 * object locking will ensure that they get destroyed in the right order.
    02505 *
    02506 * This routine gets called in the context of the last thread in the process.
    02507 *
    02508 * 08-17-92 JimA         Created.
    02509 \***************************************************************************/
    02510
    02511 VOID DestroyProcessesObjects(
    02512     PPROCESSINFO ppi)
    02513 {
    02514     PHE  pheT, pheMax;
    02515     BOOL bGlobal = (ISTS() && ppi->Process == gpepCSRSS);
    02516
    02517     /*
    02518      * Loop through the table destroying all objects created by the current
    02519      * process. All objects will get destroyed in their proper order simply
    02520      * because of the object locking.
    02521      */
    02522     DBGValidateHandleQuota();
    02523     pheMax = &gSharedInfo.aheList[giheLast];
    02524
    02525     for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) {
    02526
    02527         /*
    02528          * Check against free before we look at ppi... because pq is stored
    02529          * in the object itself, which won't be there if TYPE_FREE.
    02530          */
    02531         if (pheT->bType == TYPE_FREE)
    02532             continue;
    02533
    02534         /*
    02535          * Destroy those objects created by this queue.
    02536          */
    02537         if (!(gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED) ||
    02538                 (PPROCESSINFO)pheT->pOwner != ppi)
    02539             continue;
    02540
    02541         /*
    02542          * Make sure this object isn't already marked to be destroyed - we'll
    02543          * do no good if we try to destroy it now since it is locked.
    02544          * Change the owner since the process is going away
    02545          */
    02546         if (pheT->bFlags & HANDLEF_DESTROY) {
    02547             HMChangeOwnerPheProcess(pheT, gptiRit);
    02548             continue;
    02549         }
    02550
    02551         if (bGlobal) {
    02552
    02553             /*
    02554              * For global cursors set the ppi in the pcur
    02555              * to be CSRSS
    02556              */
    02557             if (pheT->bType == TYPE_CURSOR) {
    02558                 FixupCursor((PCURSOR)pheT->phead, ppi);
    02559             }
    02560         }
    02561
    02562         /*
    02563          * Destroy this object.
    02564          */
    02565         HMDestroyUnlockedObject(pheT);
    02566
    02567         /*
    02568          * When the object is freed, the handle type is set to TYPE_FREE.
    02569          * Zombie this object, since its process is going away and it couldn't
    02570          * be freed. This may include unlinking it and resetting the owner.
    02571          */
    02572         if (pheT->bType != TYPE_FREE) {
    02573             if (pheT->bType == TYPE_CURSOR) {
    02574                 RIPMSG1(RIP_WARNING, "About to zombie pcur %#p\n",
    02575                         pheT->phead);
    02576
    02577                 ZombieCursor((PCURSOR)pheT->phead);
    02578             } else {
    02579                 HMChangeOwnerPheProcess(pheT, gptiRit);
    02580             }
    02581         }
    02582     } /* for loop */
    02583     DBGValidateHandleQuota();
    02584 }
    02585
    02586 /***************************************************************************\
    02587 * MarkThreadsObjects
    02588 *
    02589 * This is called for the *final* exiting condition when a thread
    02590 * may have objects still around... in which case their owner must
    02591 * be changed to something "safe" that won't be going away.
    02592 *
    02593 * 03-02-92 ScottLu      Created.
    02594 \***************************************************************************/
    02595 void MarkThreadsObjects(
    02596     PTHREADINFO pti)
    02597 {
    02598     PHE pheT, pheMax;
    02599
    02600     pheMax = &gSharedInfo.aheList[giheLast];
    02601     for (pheT = gSharedInfo.aheList; pheT <= pheMax; pheT++) {
    02602         /*
    02603          * Check against free before we look at pti... because pti is stored
    02604          * in the object itself, which won't be there if TYPE_FREE.
    02605          */
    02606         if (pheT->bType == TYPE_FREE)
    02607             continue;
    02608
    02609         /*
    02610          * Change ownership!
    02611          */
    02612         if (gahti[pheT->bType].bObjectCreateFlags & OCF_PROCESSOWNED ||
    02613                 (PTHREADINFO)pheT->pOwner != pti)
    02614             continue;
    02615
    02616 #if DBG
    02617         /*
    02618          * This is just to make sure that RIT or DT never get here
    02619          */
    02620         if (ISTS() && (pti == gptiRit || pti == gTermIO.ptiDesktop)) {
    02621             RIPMSG2(RIP_ERROR, "pti %#p is RIT or DT. phe %#p\n", pti, pheT);
    02622         }
    02623 #endif
    02624
    02625         HMChangeOwnerThread(pheT->phead, gptiRit);
    02626
    02627 #if DEBUGTAGS
    02628
    02629         if (IsDbgTagEnabled(DBGTAG_TrackLocks)) {
    02630             /*
    02631              * Object still around: print warning message.
    02632              */
    02633             if (pheT->bFlags & HANDLEF_DESTROY) {
    02634                     TAGMSG2(DBGTAG_TrackLocks,
    02635                           "Zombie %s %#p still locked",
    02636                            gahti[pheT->bType].szObjectType, pheT->phead->h);
    02637             } else {
    02638                 TAGMSG1(DBGTAG_TrackLocks,
    02639                         "Thread object %#p not destroyed.\n",
    02640                         pheT->phead->h);
    02641             }
    02642
    02643             ShowLocks(pheT);
    02644         }
    02645
    02646 #endif // DEBUGTAGS
    02647     }
    02648 }
    02649
    02650 /***************************************************************************\
    02651 * HMRelocateLockRecord
    02652 *
    02653 * If a pointer to a locked object has been relocated, then this routine will
    02654 * adjust the lock record accordingly.  Must be called after the relocation.
    02655 *
    02656 * The arguments are:
    02657 *   ppobjNew - the address of the new pointer
    02658 *              MUST already contain the pointer to the object!!
    02659 *   cbDelta  - the amount by which this pointer was moved.
    02660 *
    02661 * Using this routine appropriately will prevent spurious "unmatched lock"
    02662 * reports.  See mnchange.c for an example.
    02663 *
    02664 *
    02665 * 03-18-93 IanJa        Created.
    02666 \***************************************************************************/
    02667
    02668 #if DBG
    02669
    02670 BOOL HMRelocateLockRecord(
    02671     PVOID ppobjNew,
    02672     LONG_PTR cbDelta)
    02673 {
    02674     PHE phe;
    02675     PVOID ppobjOld = (PBYTE)ppobjNew - cbDelta;
    02676     PHEAD pobj;
    02677     PLR plr;
    02678
    02679     if (ppobjNew == NULL) {
    02680         return FALSE;
    02681     }
    02682
    02683     pobj = *(PHEAD *)ppobjNew;
    02684
    02685     if (pobj == NULL) {
    02686         return FALSE;
    02687     }
    02688
    02689     phe = HMPheFromObject(pobj);
    02690     if (phe->phead != pobj) {
    02691         RIPMSG3(RIP_WARNING,
    02692                 "HmRelocateLockRecord(%#p, %lx) - %#p is bad pobj\n",
    02693                 ppobjNew, cbDelta, pobj);
    02694
    02695         return FALSE;
    02696     }
    02697
    02698     plr = phe->plr;
    02699
    02700     while (plr != NULL) {
    02701         if (plr->ppobj == ppobjOld) {
    02702             (PBYTE)(plr->ppobj) += cbDelta;
    02703             return TRUE;
    02704         }
    02705         plr = plr->plrNext;
    02706     }
    02707
    02708     RIPMSG2(RIP_WARNING,
    02709             "HmRelocateLockRecord(%#p, %lx) - couldn't find lock record\n",
    02710             ppobjNew, cbDelta);
    02711
    02712     ShowLocks(phe);
    02713     return FALSE;
    02714 }
    02715
    02716
    02717 BOOL HMUnrecordLock(
    02718     PVOID ppobj,
    02719     PVOID pobj)
    02720 {
    02721     PHE phe;
    02722     PLR plr;
    02723     PLR *pplr;
    02724
    02725     phe = HMPheFromObject(pobj);
    02726
    02727     pplr = &(phe->plr);
    02728     plr = *pplr;
    02729
    02730     /*
    02731      * Find corresponding lock;
    02732      */
    02733     while (plr != NULL) {
    02734         if (plr->ppobj == ppobj) {
    02735             /*
    02736              * Remove the lock from the list...
    02737              */
    02738             *pplr = plr->plrNext;   // unlink it
    02739             plr->plrNext = NULL;    // make the dead entry safe (?)
    02740
    02741             /*
    02742              * ...and free it.
    02743              */
    02744             FreeLockRecord(plr);
    02745             return TRUE;
    02746         }
    02747         pplr = &(plr->plrNext);
    02748         plr = *pplr;
    02749     }
    02750
    02751     RIPMSG2(RIP_WARNING, "Could not find lock for ppobj %#p pobj %#p",
    02752             ppobj, pobj);
    02753
    02754     return FALSE;
    02755 }
    02756
    02757 #endif // DBG
    02758
    02759 /***************************************************************************\
    02760 * _QueryUserHandles
    02761 *
    02762 * This function retrieves the USER handle counters for all processes
    02763 * specified by their client ID in the paPids array
    02764 * Specify QUC_PID_TOTAL to retrieve totals for all processes in the system
    02765 *
    02766 * Parameters:
    02767 *    paPids   - pointer to an array of pids (DWORDS) that we're interested in
    02768 *    dwNumInstances - number of DWORDS in paPids
    02769 *    pdwResult - will receive TYPES_CTYPESxdwNumInstances counters
    02770 *
    02771 * returns: none
    02772 *
    02773 * 07-25-97 mcostea        Created
    02774 \***************************************************************************/
    02775
    02776 VOID _QueryUserHandles(
    02777     LPDWORD  paPids,
    02778     DWORD    dwNumInstances,
    02779     DWORD    dwResult[][TYPE_CTYPES])
    02780 {
    02781     PHE         pheCurPos;                 // Current position in the table
    02782     PHE         pheMax;                    // address of last table entry
    02783     DWORD       index;
    02784     DWORD       pid;
    02785     DWORD       dwTotalCounters[TYPE_CTYPES]; // system wide counters
    02786
    02787     RtlZeroMemory(dwTotalCounters, TYPE_CTYPES*sizeof(DWORD));
    02788     RtlZeroMemory(dwResult, dwNumInstances*TYPE_CTYPES*sizeof(DWORD));
    02789     /*
    02790      * Walk the handle table and update the counters
    02791      */
    02792     pheMax = &gSharedInfo.aheList[giheLast];
    02793     for(pheCurPos = gSharedInfo.aheList; pheCurPos <= pheMax; pheCurPos++) {
    02794
    02795         UserAssert(pheCurPos->bType < TYPE_CTYPES);
    02796
    02797         pid = 0;
    02798
    02799         if (pheCurPos->pOwner) {
    02800
    02801             if (gahti[pheCurPos->bType].bObjectCreateFlags & OCF_PROCESSOWNED) {
    02802                 /*
    02803                  * Object is owned by process
    02804                  * some objects may not have an owner
    02805                  */
    02806                     pid = HandleToUlong(((PPROCESSINFO)pheCurPos->pOwner)->Process->UniqueProcessId);
    02807                 }
    02808             else if (gahti[pheCurPos->bType].bObjectCreateFlags & OCF_THREADOWNED) {
    02809                 /*
    02810                  * Object owned by thread
    02811                  */
    02812                     pid = HandleToUlong(((PTHREADINFO)pheCurPos->pOwner)->pEThread->ThreadsProcess->UniqueProcessId);
    02813                 }
    02814         }
    02815         /*
    02816          * search to see if we are interested in this process
    02817          * unowned handles are reported for the "System" process whose pid is 0
    02818          */
    02819         for (index = 0; index < dwNumInstances; index++) {
    02820
    02821             if (paPids[index] == pid) {
    02822                 dwResult[index][pheCurPos->bType]++;
    02823             }
    02824         }
    02825         /*
    02826          *  update the totals
    02827          */
    02828          dwTotalCounters[pheCurPos->bType]++;
    02829     }
    02830
    02831     /*
    02832      * search to see if we are interested in the totals
    02833      */
    02834     for (index = 0; index < dwNumInstances; index++) {
    02835
    02836         if (paPids[index] == QUC_PID_TOTAL) {
    02837
    02838             RtlMoveMemory(dwResult[index], dwTotalCounters, sizeof(dwTotalCounters));
    02839         }
    02840     }
    02841
    02842 }
    02843
    02844 /***************************************************************************\
    02845 * HMCleanupGrantedHandle
    02846 *
    02847 * This function is called to cleanup this handle from pW32Job->pgh arrays.
    02848 * It walks the job list to find jobs that have the handle granted.
    02849 *
    02850 * HISTORY:
    02851 * 22 Jul 97      CLupu            Created
    02852 \***************************************************************************/
    02853 void HMCleanupGrantedHandle(
    02854     HANDLE h)
    02855 {
    02856     PW32JOB pW32Job;
    02857
    02858     pW32Job = gpJobsList;
    02859
    02860     while (pW32Job != NULL) {
    02861         PULONG_PTR pgh;
    02862         DWORD  dw;
    02863
    02864         pgh = pW32Job->pgh;
    02865
    02866         /*
    02867          * search for the handle in the array.
    02868          */
    02869         for (dw = 0; dw < pW32Job->ughCrt; dw++) {
    02870             if (*(pgh + dw) == (ULONG_PTR)h) {
    02871
    02872                 /*
    02873                  * found the handle granted to this process
    02874                  */
    02875                 RtlMoveMemory(pgh + dw,
    02876                               pgh + dw + 1,
    02877                               (pW32Job->ughCrt - dw - 1) * sizeof(*pgh));
    02878
    02879                 (pW32Job->ughCrt)--;
    02880
    02881                 /*
    02882                  * we should shrink the array also
    02883                  */
    02884
    02885                 break;
    02886             }
    02887         }
    02888
    02889         pW32Job = pW32Job->pNext;
    02890     }
    02891 }