Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

604 lines
17 KiB

  1. //============================================================================
  2. // Copyright (c) 2000, Microsoft Corporation
  3. //
  4. // File: mapper.c
  5. //
  6. // History:
  7. // Yi Sun June-27-2000 Created
  8. //
  9. // Abstract:
  10. // We implement a locking system with read and write locks. Callers
  11. // can simply acquire a read lock to the obj to prevent the obj
  12. // from being released since whoever doing the release is supposed
  13. // acquire the write lock first. Routines for mapping between
  14. // obj pointers and handles are also provided.
  15. //============================================================================
  16. #include "nt.h"
  17. #include "ntrtl.h"
  18. #include "nturtl.h"
  19. #include "windows.h"
  20. #include "tapi.h"
  21. #include "ndptsp.h"
  22. typedef struct _RW_LOCK
  23. {
  24. CRITICAL_SECTION critSec; // critical section
  25. HANDLE hEvent; // no-one-holds-any-lock event
  26. DWORD dwRefCt; // number of threads holding locks
  27. } RW_LOCK, *PRW_LOCK;
  28. typedef struct _MAPPER_ENTRY
  29. {
  30. // DEF: a free entry is one that no obj is associated with
  31. RW_LOCK rwLock; // a lock for each entry to ensure thread-safe
  32. PVOID pObjPtr; // point to the mem block of the associated obj
  33. // NULL when the entry is free
  34. FREEOBJPROC pfnFreeProc; // function to call to free the obj
  35. WORD wID; // id used for detecting bad handles
  36. // valid value range: 1 - 0x7FFF
  37. WORD wIndexNextFree; // index of the next free entry in the global
  38. // mapper array, invalid when the entry is busy
  39. } MAPPER_ENTRY, *PMAPPER_ENTRY;
  40. typedef struct _HANDLE_OBJECT_MAPPER
  41. {
  42. RW_LOCK rwLock; // a global lock for the whole mapper
  43. WORD wNextID; // a global id counter incremented
  44. // after each handle mapping
  45. WORD wIndexFreeHead; // index of head of free entry list
  46. DWORD dwCapacity; // total number of entries in the array
  47. DWORD dwFree; // total number of free entries left
  48. PMAPPER_ENTRY pArray; // the global array that keeps all the mapping
  49. } HANDLE_OBJECT_MAPPER;
  50. // the capacity to begin with, can be read from registry
  51. #define INITIAL_MAPPER_SIZE 32
  52. #define MAXIMUM_MAPPER_SIZE (64 * 1024) // 16-bit index limitation
  53. // the global mapper object
  54. static HANDLE_OBJECT_MAPPER gMapper;
  55. BOOL
  56. InitializeRWLock(
  57. IN PRW_LOCK pLock
  58. )
  59. {
  60. // create an autoreset event, non-signaled initially
  61. pLock->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  62. if (NULL == pLock->hEvent)
  63. {
  64. return FALSE;
  65. }
  66. InitializeCriticalSection(&pLock->critSec);
  67. pLock->dwRefCt = 0;
  68. return TRUE;
  69. }
  70. BOOL
  71. UninitializeRWLock(
  72. IN PRW_LOCK pLock
  73. )
  74. {
  75. pLock->dwRefCt = 0;
  76. DeleteCriticalSection(&pLock->critSec);
  77. return CloseHandle(pLock->hEvent);
  78. }
  79. //
  80. // NOTE: due to the limitation of the current
  81. // implementation, calling AcquireWriteLock()
  82. // while holding a read lock of the same
  83. // RW_LOCK will result in a DEADLOCK!!!
  84. // Be sure to release the read lock before
  85. // attempting to acquire the write lock.
  86. // This limitation can be lifted by implementing
  87. // lock upgrade (from read to write) which
  88. // requires RW_LOCK to remember ids of all
  89. // owning threads.
  90. //
  91. VOID
  92. AcquireReadLock(
  93. IN PRW_LOCK pLock
  94. )
  95. {
  96. //
  97. // increase the ref count, then leave
  98. // the critical section to allow others
  99. // to enter
  100. //
  101. EnterCriticalSection(&pLock->critSec);
  102. ++pLock->dwRefCt;
  103. LeaveCriticalSection(&pLock->critSec);
  104. }
  105. VOID
  106. ReleaseReadLock(
  107. IN PRW_LOCK pLock
  108. )
  109. {
  110. //
  111. // decrease the ref count, check whether
  112. // the new ref count is 0 (meaning no one
  113. // else holds any lock), if yes, signal
  114. // the event to allow others waiting to
  115. // acquire write locks to continue
  116. //
  117. EnterCriticalSection(&pLock->critSec);
  118. if (0 == --pLock->dwRefCt)
  119. {
  120. SetEvent(pLock->hEvent);
  121. }
  122. LeaveCriticalSection(&pLock->critSec);
  123. }
  124. VOID
  125. AcquireWriteLock(
  126. IN PRW_LOCK pLock
  127. )
  128. {
  129. //
  130. // enter critical section, check whether
  131. // the ref count is 0: if yes, return
  132. // without leaving the critical section
  133. // to block others from entering; if no,
  134. // leave the section before wait for others
  135. // to release locks then reenter the section
  136. //
  137. try_entering_crit_sec:
  138. EnterCriticalSection(&pLock->critSec);
  139. if (pLock->dwRefCt > 0)
  140. {
  141. // make sure leaving critSec before waiting
  142. LeaveCriticalSection(&pLock->critSec);
  143. WaitForSingleObject(pLock->hEvent, INFINITE);
  144. goto try_entering_crit_sec;
  145. }
  146. pLock->dwRefCt = 1;
  147. }
  148. VOID
  149. ReleaseWriteLock(
  150. IN PRW_LOCK pLock
  151. )
  152. {
  153. //
  154. // reset the ref count to 0, signal
  155. // the event, leave the critical section
  156. //
  157. pLock->dwRefCt = 0;
  158. SetEvent(pLock->hEvent);
  159. LeaveCriticalSection(&pLock->critSec);
  160. }
  161. LONG
  162. InitializeMapper(
  163. )
  164. {
  165. DWORD dwIndex;
  166. TspLog(DL_TRACE, "InitializeMapper: entering...");
  167. // alloc and zeroinit the array
  168. gMapper.pArray = (PMAPPER_ENTRY)
  169. MALLOC(INITIAL_MAPPER_SIZE * sizeof(MAPPER_ENTRY));
  170. if (NULL == gMapper.pArray)
  171. {
  172. TspLog(DL_ERROR,
  173. "InitializeMapper: failed to alloc(1) mapper array");
  174. return LINEERR_NOMEM;
  175. }
  176. // init the global lock for the mapper
  177. InitializeRWLock(&gMapper.rwLock);
  178. gMapper.wNextID = 1;
  179. gMapper.wIndexFreeHead = 0;
  180. gMapper.dwCapacity = INITIAL_MAPPER_SIZE;
  181. gMapper.dwFree = INITIAL_MAPPER_SIZE;
  182. // init the lock for each mapper entry and link the free entry list
  183. for (dwIndex = 0; dwIndex < INITIAL_MAPPER_SIZE - 1; dwIndex++)
  184. {
  185. InitializeRWLock(&(gMapper.pArray[dwIndex].rwLock));
  186. gMapper.pArray[dwIndex].wIndexNextFree = (WORD)(dwIndex + 1);
  187. }
  188. InitializeRWLock(&(gMapper.pArray[INITIAL_MAPPER_SIZE - 1].rwLock));
  189. return TAPI_SUCCESS;
  190. }
  191. VOID
  192. UninitializeMapper()
  193. {
  194. DWORD dwIndex;
  195. for (dwIndex = 0; dwIndex < gMapper.dwCapacity; dwIndex++)
  196. {
  197. UninitializeRWLock(&(gMapper.pArray[dwIndex].rwLock));
  198. }
  199. UninitializeRWLock(&gMapper.rwLock);
  200. FREE(gMapper.pArray);
  201. TspLog(DL_TRACE, "UninitializeMapper: exited");
  202. }
  203. //
  204. // NOTE: both OpenObjHandle() and CloseObjHandle() acquire write lock of
  205. // gMapper.rwLock at the beginning and release it at the end;
  206. // but that's not the case for AcquireObjReadLock(), GetObjWithReadLock(),
  207. // AcquireObjWriteLock() and GetObjWithWriteLock(): they acquire read
  208. // lock of gMapper.rwLock at the beginning and never release it before
  209. // exit, the lock is actually released in either ReleaseObjReadLock()
  210. // or ReleaseObjWriteLock(), which means the caller thread of these
  211. // four lock-acquiring functions actually not only holds the lock
  212. // it intends to acquire but also holds the read lock of gMapper.rwLock
  213. // as a by-product. The reason for that is preventing CloseObjHandle()
  214. // from getting the write lock of gMapper.rwLock while waiting for the
  215. // write lock for a mapper entry -- that sure will result in a DEADLOCK
  216. // because if another thread has the read lock for that entry, for it to
  217. // release the lock, it needs to acquire the read lock of gMapper.rwLock.
  218. // The consequence of keeping the read lock of gMapper.rwLock is that
  219. // the caller thread has to call ReleaseObjXXXLock() to release it
  220. // before calling OpenObjHandle() or CloseObjHandle() to avoid another
  221. // kind of DEADLOCK (see previous NOTE).
  222. //
  223. LONG
  224. OpenObjHandle(
  225. IN PVOID pObjPtr,
  226. IN FREEOBJPROC pfnFreeProc,
  227. OUT HANDLE *phObj
  228. )
  229. {
  230. WORD wIndex;
  231. PMAPPER_ENTRY pEntry;
  232. DWORD dwHandle;
  233. AcquireWriteLock(&gMapper.rwLock);
  234. if (0 == gMapper.dwFree)
  235. {
  236. DWORD dwIndex;
  237. DWORD dwOldSize = gMapper.dwCapacity;
  238. PMAPPER_ENTRY pOldArray = gMapper.pArray;
  239. if (MAXIMUM_MAPPER_SIZE == gMapper.dwCapacity)
  240. {
  241. TspLog(DL_ERROR,
  242. "OpenObjHandle: failed to grow mapper array");
  243. ReleaseWriteLock(&gMapper.rwLock);
  244. return LINEERR_OPERATIONFAILED;
  245. }
  246. // increase the capacity by a factor of two
  247. gMapper.dwCapacity <<= 1;
  248. // allocate a new array twice the old size, then zeroinit it
  249. gMapper.pArray = (PMAPPER_ENTRY)
  250. MALLOC(gMapper.dwCapacity * sizeof(MAPPER_ENTRY));
  251. if (NULL == gMapper.pArray)
  252. {
  253. TspLog(DL_ERROR,
  254. "OpenObjHandle: failed to alloc(2) mapper array");
  255. ReleaseWriteLock(&gMapper.rwLock);
  256. return LINEERR_NOMEM;
  257. }
  258. TspLog(DL_INFO, "OpenObjHandle: the mapper array has grown to %d",
  259. gMapper.dwCapacity);
  260. // copy the old array over
  261. for (dwIndex = 0; dwIndex < dwOldSize; dwIndex++)
  262. {
  263. CopyMemory(&(gMapper.pArray[dwIndex].rwLock),
  264. &(pOldArray[dwIndex].rwLock),
  265. sizeof(RW_LOCK));
  266. //
  267. // Delete the lock from the old table and initialize
  268. // the cs in the new table. Otherwise pageheap will
  269. // assert when oldtable is being freed - and its not
  270. // a good thing anyway. Note that since the global
  271. // lock is held across all Acquire/Get/Release functions
  272. // for the lock, this is a safe operation to do here -
  273. // no object would be holding the lock when this is
  274. // being done since we are holding the write lock
  275. // for the gmapper.
  276. //
  277. DeleteCriticalSection(&pOldArray[dwIndex].rwLock.critSec);
  278. InitializeCriticalSection(&gMapper.pArray[dwIndex].rwLock.critSec);
  279. gMapper.pArray[dwIndex].pObjPtr = pOldArray[dwIndex].pObjPtr;
  280. gMapper.pArray[dwIndex].pfnFreeProc =
  281. pOldArray[dwIndex].pfnFreeProc;
  282. gMapper.pArray[dwIndex].wID = pOldArray[dwIndex].wID;
  283. }
  284. // init locks for new entries and link them
  285. for (dwIndex = dwOldSize; dwIndex < gMapper.dwCapacity - 1; dwIndex++)
  286. {
  287. InitializeRWLock(&(gMapper.pArray[dwIndex].rwLock));
  288. gMapper.pArray[dwIndex].wIndexNextFree = (WORD)(dwIndex + 1);
  289. }
  290. InitializeRWLock(&(gMapper.pArray[gMapper.dwCapacity - 1].rwLock));
  291. // reset the globals
  292. gMapper.dwFree = dwOldSize;
  293. gMapper.wIndexFreeHead = (WORD)dwOldSize;
  294. // free the old array
  295. FREE(pOldArray);
  296. }
  297. ASSERT(gMapper.dwFree != 0);
  298. wIndex = gMapper.wIndexFreeHead;
  299. pEntry = gMapper.pArray + wIndex;
  300. gMapper.wIndexFreeHead = pEntry->wIndexNextFree;
  301. gMapper.dwFree--;
  302. pEntry->pObjPtr = pObjPtr;
  303. pEntry->pfnFreeProc = pfnFreeProc;
  304. pEntry->wID = gMapper.wNextID++;
  305. // make sure wNextID is within range
  306. if (gMapper.wNextID & 0x8000)
  307. {
  308. gMapper.wNextID = 1;
  309. }
  310. pEntry->wIndexNextFree = 0; // it's always 0 when the entry is not free
  311. //
  312. // bit 0 is always 0
  313. // bits 1-16 contains the index into pArray
  314. // bits 17-31 contains the id
  315. //
  316. // this enables us to differentiate the TSP handles
  317. // created here for outgoing calls and the pseudo handles
  318. // created in NDPROXY for incoming calls which always
  319. // has the lower bit set
  320. //
  321. dwHandle = (((pEntry->wID) << 16) | wIndex) << 1;
  322. // a handle is a ptr, so on 64-bit platform, dwHandle needs to be extended
  323. *phObj = (HANDLE)UlongToPtr(dwHandle);
  324. ReleaseWriteLock(&gMapper.rwLock);
  325. return TAPI_SUCCESS;
  326. }
  327. LONG
  328. CloseObjHandle(
  329. IN HANDLE hObj
  330. )
  331. {
  332. DWORD dwHandle = PtrToUlong(hObj) >> 1;
  333. WORD wIndex = (WORD)(dwHandle & 0xFFFF);
  334. WORD wID = (WORD)(dwHandle >> 16);
  335. AcquireWriteLock(&gMapper.rwLock);
  336. if ((wIndex >= gMapper.dwCapacity) ||
  337. (wID != gMapper.pArray[wIndex].wID) ||
  338. (NULL == gMapper.pArray[wIndex].pObjPtr))
  339. {
  340. TspLog(DL_WARNING, "CloseObjHandle: bad handle(%p)", hObj);
  341. ReleaseWriteLock(&gMapper.rwLock);
  342. return LINEERR_OPERATIONFAILED;
  343. }
  344. AcquireWriteLock(&gMapper.pArray[wIndex].rwLock);
  345. #if DBG
  346. TspLog(DL_TRACE, "CloseObjHandle: closing handle(%p)", hObj);
  347. #endif //DBG
  348. // free the obj
  349. (*(gMapper.pArray[wIndex].pfnFreeProc))(gMapper.pArray[wIndex].pObjPtr);
  350. // close obj handle
  351. gMapper.pArray[wIndex].pObjPtr = NULL;
  352. gMapper.pArray[wIndex].pfnFreeProc = NULL;
  353. gMapper.pArray[wIndex].wID = 0;
  354. // insert the entry into the free list as the head
  355. gMapper.pArray[wIndex].wIndexNextFree = gMapper.wIndexFreeHead;
  356. gMapper.wIndexFreeHead = wIndex;
  357. // update the free total
  358. gMapper.dwFree++;
  359. ReleaseWriteLock(&gMapper.pArray[wIndex].rwLock);
  360. ReleaseWriteLock(&gMapper.rwLock);
  361. return TAPI_SUCCESS;
  362. }
  363. LONG
  364. AcquireObjReadLock(
  365. IN HANDLE hObj
  366. )
  367. {
  368. DWORD dwHandle = PtrToUlong(hObj) >> 1;
  369. WORD wIndex = (WORD)(dwHandle & 0xFFFF);
  370. WORD wID = (WORD)(dwHandle >> 16);
  371. AcquireReadLock(&gMapper.rwLock);
  372. if ((wIndex >= gMapper.dwCapacity) ||
  373. (wID != gMapper.pArray[wIndex].wID) ||
  374. (NULL == gMapper.pArray[wIndex].pObjPtr))
  375. {
  376. TspLog(DL_WARNING, "AcquireObjReadLock: bad handle(%p)", hObj);
  377. ReleaseReadLock(&gMapper.rwLock);
  378. return LINEERR_OPERATIONFAILED;
  379. }
  380. AcquireReadLock(&gMapper.pArray[wIndex].rwLock);
  381. #if DBG
  382. TspLog(DL_TRACE, "AcquireObjReadLock: RefCt(%p, %d)",
  383. hObj, gMapper.pArray[wIndex].rwLock.dwRefCt);
  384. #endif //DBG
  385. return TAPI_SUCCESS;
  386. }
  387. LONG
  388. GetObjWithReadLock(
  389. IN HANDLE hObj,
  390. OUT PVOID *ppObjPtr
  391. )
  392. {
  393. DWORD dwHandle = PtrToUlong(hObj) >> 1;
  394. WORD wIndex = (WORD)(dwHandle & 0xFFFF);
  395. WORD wID = (WORD)(dwHandle >> 16);
  396. AcquireReadLock(&gMapper.rwLock);
  397. if ((wIndex >= gMapper.dwCapacity) ||
  398. (wID != gMapper.pArray[wIndex].wID) ||
  399. (NULL == gMapper.pArray[wIndex].pObjPtr))
  400. {
  401. TspLog(DL_WARNING, "GetObjWithReadLock: bad handle(%p)", hObj);
  402. ReleaseReadLock(&gMapper.rwLock);
  403. return LINEERR_OPERATIONFAILED;
  404. }
  405. AcquireReadLock(&gMapper.pArray[wIndex].rwLock);
  406. #if DBG
  407. TspLog(DL_TRACE, "GetObjWithReadLock: RefCt(%p, %d)",
  408. hObj, gMapper.pArray[wIndex].rwLock.dwRefCt);
  409. #endif //DBG
  410. *ppObjPtr = gMapper.pArray[wIndex].pObjPtr;
  411. return TAPI_SUCCESS;
  412. }
  413. LONG
  414. ReleaseObjReadLock(
  415. IN HANDLE hObj
  416. )
  417. {
  418. DWORD dwHandle = PtrToUlong(hObj) >> 1;
  419. WORD wIndex = (WORD)(dwHandle & 0xFFFF);
  420. WORD wID = (WORD)(dwHandle >> 16);
  421. if ((wIndex >= gMapper.dwCapacity) ||
  422. (wID != gMapper.pArray[wIndex].wID) ||
  423. (NULL == gMapper.pArray[wIndex].pObjPtr))
  424. {
  425. TspLog(DL_WARNING, "ReleaseObjReadLock: bad handle(%p)", hObj);
  426. return LINEERR_OPERATIONFAILED;
  427. }
  428. ReleaseReadLock(&gMapper.pArray[wIndex].rwLock);
  429. #if DBG
  430. TspLog(DL_TRACE, "ReleaseObjReadLock: RefCt(%p, %d)",
  431. hObj, gMapper.pArray[wIndex].rwLock.dwRefCt);
  432. #endif //DBG
  433. ReleaseReadLock(&gMapper.rwLock);
  434. return TAPI_SUCCESS;
  435. }
  436. LONG
  437. AcquireObjWriteLock(
  438. IN HANDLE hObj
  439. )
  440. {
  441. DWORD dwHandle = PtrToUlong(hObj) >> 1;
  442. WORD wIndex = (WORD)(dwHandle & 0xFFFF);
  443. WORD wID = (WORD)(dwHandle >> 16);
  444. AcquireReadLock(&gMapper.rwLock);
  445. if ((wIndex >= gMapper.dwCapacity) ||
  446. (wID != gMapper.pArray[wIndex].wID) ||
  447. (NULL == gMapper.pArray[wIndex].pObjPtr))
  448. {
  449. TspLog(DL_WARNING, "AcquireObjWriteLock: bad handle(%p)", hObj);
  450. ReleaseReadLock(&gMapper.rwLock);
  451. return LINEERR_OPERATIONFAILED;
  452. }
  453. AcquireWriteLock(&gMapper.pArray[wIndex].rwLock);
  454. #if DBG
  455. TspLog(DL_TRACE, "AcquireObjWriteLock: RefCt(%p, %d)",
  456. hObj, gMapper.pArray[wIndex].rwLock.dwRefCt);
  457. #endif //DBG
  458. return TAPI_SUCCESS;
  459. }
  460. LONG
  461. GetObjWithWriteLock(
  462. IN HANDLE hObj,
  463. OUT PVOID *ppObjPtr
  464. )
  465. {
  466. DWORD dwHandle = PtrToUlong(hObj) >> 1;
  467. WORD wIndex = (WORD)(dwHandle & 0xFFFF);
  468. WORD wID = (WORD)(dwHandle >> 16);
  469. AcquireReadLock(&gMapper.rwLock);
  470. if ((wIndex >= gMapper.dwCapacity) ||
  471. (wID != gMapper.pArray[wIndex].wID) ||
  472. (NULL == gMapper.pArray[wIndex].pObjPtr))
  473. {
  474. TspLog(DL_WARNING, "GetObjWithWriteLock: bad handle(%p)", hObj);
  475. ReleaseReadLock(&gMapper.rwLock);
  476. return LINEERR_OPERATIONFAILED;
  477. }
  478. AcquireWriteLock(&gMapper.pArray[wIndex].rwLock);
  479. #if DBG
  480. TspLog(DL_TRACE, "GetObjWithWriteLock: RefCt(%p, %d)",
  481. hObj, gMapper.pArray[wIndex].rwLock.dwRefCt);
  482. #endif //DBG
  483. *ppObjPtr = gMapper.pArray[wIndex].pObjPtr;
  484. return TAPI_SUCCESS;
  485. }
  486. LONG
  487. ReleaseObjWriteLock(
  488. IN HANDLE hObj
  489. )
  490. {
  491. DWORD dwHandle = PtrToUlong(hObj) >> 1;
  492. WORD wIndex = (WORD)(dwHandle & 0xFFFF);
  493. WORD wID = (WORD)(dwHandle >> 16);
  494. if ((wIndex >= gMapper.dwCapacity) ||
  495. (wID != gMapper.pArray[wIndex].wID) ||
  496. (NULL == gMapper.pArray[wIndex].pObjPtr))
  497. {
  498. TspLog(DL_WARNING, "ReleaseObjWriteLock: bad handle(%p)", hObj);
  499. return LINEERR_OPERATIONFAILED;
  500. }
  501. ReleaseWriteLock(&gMapper.pArray[wIndex].rwLock);
  502. #if DBG
  503. TspLog(DL_TRACE, "ReleaseObjWriteLock: RefCt(%p, %d)",
  504. hObj, gMapper.pArray[wIndex].rwLock.dwRefCt);
  505. #endif //DBG
  506. ReleaseReadLock(&gMapper.rwLock);
  507. return TAPI_SUCCESS;
  508. }