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.

563 lines
14 KiB

  1. /*++ BUILD Version: 0000 // Increment this if a change has global effects
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. handle.c
  5. Abstract:
  6. Handle table library. Handles are generated as follows :
  7. handle =
  8. Base value +
  9. (Table entry index << 4) +
  10. (Handle usage instance & 0xf)
  11. A free list is kept in the handle table header, with the oldest free
  12. entry being at the head of the list & the youngest at the tail.
  13. The low four bits of the handle values are used for a usage instance
  14. count, which gets incremented every time a handle is freed (to
  15. prevent immediate re-use of the same handle value).
  16. Author:
  17. Dan Knudson (DanKn) 15-Sep-1998
  18. Revision History:
  19. --*/
  20. #include "windows.h"
  21. #include "assert.h"
  22. #include "tlnklist.h"
  23. #include "tapihndl.h"
  24. #define TABLE_DELTA 64
  25. BOOL
  26. GrowTable(
  27. PHANDLETABLEHEADER Header
  28. )
  29. /*++
  30. Returns: Index of next free table entry if success, -1 if error
  31. --*/
  32. {
  33. DWORD numEntries = Header->NumEntries, i, numAdditionalEntries;
  34. PHANDLETABLEENTRY newTable;
  35. // First, we need to compute how many entries we can still alloc.
  36. // To do this, we need to now how many entries can the table accommodate,
  37. // so that the largest handle value will not exceed MAXDWORD. We get
  38. // this by reversing the algorithm used to compute handle values based
  39. // on the table entry's index.
  40. numAdditionalEntries = (MAXDWORD - Header->HandleBase) >> 4; // This is the maximum number of entries in the table,
  41. // so that handle values do not overflow DWORDs.
  42. numAdditionalEntries -= numEntries; // This is how many entries we can still alloc;
  43. if (0 == numAdditionalEntries)
  44. {
  45. // The table is already as big as it can be...
  46. return FALSE;
  47. }
  48. if (numAdditionalEntries > TABLE_DELTA)
  49. {
  50. numAdditionalEntries = TABLE_DELTA; // We only grow the handle table in TABLE_DELTA or
  51. } // or smaller increments.
  52. if (!(newTable = HeapAlloc(
  53. Header->Heap,
  54. 0,
  55. (numEntries + numAdditionalEntries) * sizeof (*newTable)
  56. )))
  57. {
  58. return FALSE;
  59. }
  60. CopyMemory(
  61. newTable,
  62. Header->Table,
  63. numEntries * sizeof(*newTable)
  64. );
  65. for (i = numEntries; i < numEntries + TABLE_DELTA; i++)
  66. {
  67. //
  68. // Init this entry. Note that we set "Instance = i" to stagger
  69. // the handle values, because we know tapisrv queues events &
  70. // completion msgs to a specific SPEVentHandlerThread based on
  71. // handle values.
  72. //
  73. PHANDLETABLEENTRY entry = newTable + i;
  74. InsertHeadList (&Header->FreeList, &entry->ListEntry);
  75. entry->Handle = 0;
  76. entry->Instance = i;
  77. }
  78. if (Header->Table)
  79. {
  80. HeapFree (Header->Heap, 0, Header->Table);
  81. }
  82. Header->Table = newTable;
  83. Header->NumEntries += TABLE_DELTA;
  84. return TRUE;
  85. }
  86. HANDLE
  87. CreateHandleTable(
  88. HANDLE Heap,
  89. FREECONTEXTCALLBACK FreeContextCallback,
  90. DWORD MinHandleValue,
  91. DWORD MaxHandleValue
  92. /* Right now, MaxHandleValue is not used. If we find that we
  93. need to use it however, store it in the table header and
  94. replace MAXDWORD with it in the code at the beginning of
  95. GrowTable */
  96. )
  97. /*++
  98. --*/
  99. {
  100. PHANDLETABLEHEADER header;
  101. if (!(header = HeapAlloc (Heap, HEAP_ZERO_MEMORY, sizeof (*header))))
  102. {
  103. return NULL;
  104. }
  105. header->Heap = Heap;
  106. header->HandleBase = MinHandleValue;
  107. header->FreeContextCallback = FreeContextCallback;
  108. InitializeListHead (&header->FreeList);
  109. InitializeCriticalSectionAndSpinCount (&header->Lock, 0x80001000);
  110. if (!GrowTable (header))
  111. {
  112. DeleteCriticalSection (&header->Lock);
  113. HeapFree (Heap, 0, header);
  114. return NULL;
  115. }
  116. return ((HANDLE) header);
  117. }
  118. VOID
  119. DeleteHandleTable(
  120. HANDLE HandleTable
  121. )
  122. /*++
  123. --*/
  124. {
  125. PHANDLETABLEHEADER header = (PHANDLETABLEHEADER) HandleTable;
  126. HeapFree (header->Heap, 0, header->Table);
  127. DeleteCriticalSection (&header->Lock);
  128. HeapFree (header->Heap, 0, header);
  129. }
  130. //
  131. // Distinct calls of NewObject and NewObjectEx in the same handle table always return distinct handles.
  132. // All NewObject calls in tapisrv use the same handle table, so the handles are known to be distinct,
  133. // even between different types of objects (i.e. HCALL vs. HLINE)
  134. // This will need to remain true if the NewObject() implementation changes in the future,
  135. // as various TAPI operations use this assumption.
  136. //
  137. DWORD
  138. NewObject(
  139. HANDLE HandleTable,
  140. LPVOID Context,
  141. LPVOID Context2
  142. )
  143. /*++
  144. --*/
  145. {
  146. DWORD handle;
  147. PHANDLETABLEENTRY entry;
  148. PHANDLETABLEHEADER header = (PHANDLETABLEHEADER) HandleTable;
  149. if (header && Context)
  150. {
  151. EnterCriticalSection (&header->Lock);
  152. if (IsListEmpty (&header->FreeList))
  153. {
  154. if (!GrowTable (header))
  155. {
  156. LeaveCriticalSection (&header->Lock);
  157. return 0;
  158. }
  159. }
  160. entry = (PHANDLETABLEENTRY) RemoveHeadList (&header->FreeList);
  161. entry->Context.C = Context;
  162. entry->Context.C2 = Context2;
  163. entry->Handle =
  164. header->HandleBase +
  165. (((DWORD)(entry - header->Table)) << 4) + // (entry_index << 4) is guraranteed
  166. // to fit in a DWORD (see comments at the
  167. // start of GrowTable).
  168. (entry->Instance & 0xf);
  169. entry->ReferenceCount = 1;
  170. handle = entry->Handle;
  171. LeaveCriticalSection (&header->Lock);
  172. }
  173. else
  174. {
  175. handle = 0;
  176. }
  177. return handle;
  178. }
  179. DWORD
  180. NewObjectEx(
  181. HANDLE HandleTable,
  182. LPVOID Context,
  183. LPVOID Context2,
  184. DWORD ModBase,
  185. DWORD Remainder
  186. )
  187. /*++
  188. The purpose of this func is to support the consult call hack in
  189. tapisrv!LSetupConference, where we need to make sure that the
  190. handle we give back will map to the same SPEventThread (queue) ID
  191. that specified by the ModBase/Remainder params.
  192. --*/
  193. {
  194. BOOL growTableCount = 0;
  195. DWORD handle;
  196. PHANDLETABLEENTRY entry;
  197. PHANDLETABLEHEADER header = (PHANDLETABLEHEADER) HandleTable;
  198. if (header && Context)
  199. {
  200. EnterCriticalSection (&header->Lock);
  201. findEntry:
  202. for(
  203. entry = (PHANDLETABLEENTRY) header->FreeList.Flink;
  204. entry != (PHANDLETABLEENTRY) &header->FreeList;
  205. entry = (PHANDLETABLEENTRY) entry->ListEntry.Flink
  206. )
  207. {
  208. handle =
  209. header->HandleBase +
  210. (((DWORD)(entry - header->Table)) << 4) + // (entry_index << 4) is guraranteed
  211. // to fit in a DWORD (see comments at the
  212. // start of GrowTable).
  213. (entry->Instance & 0xf);
  214. // TODO: possible optimization is that if following
  215. // evaluates to FALSE try (handle % ModBase)+1, +2, ...
  216. // but don't go too far, don't want immediate handle reuse
  217. if ((handle % ModBase) == Remainder)
  218. {
  219. break;
  220. }
  221. }
  222. if (entry != (PHANDLETABLEENTRY) &(header->FreeList))
  223. {
  224. RemoveEntryList (&entry->ListEntry);
  225. }
  226. else
  227. {
  228. //
  229. // Couldn't find a free entry that works, try growing the table
  230. //
  231. if (growTableCount > 3)
  232. {
  233. LeaveCriticalSection (&header->Lock);
  234. return 0;
  235. }
  236. if (!GrowTable (HandleTable))
  237. {
  238. LeaveCriticalSection (&header->Lock);
  239. return 0;
  240. }
  241. growTableCount++;
  242. goto findEntry;
  243. }
  244. entry->Context.C = Context;
  245. entry->Context.C2 = Context2;
  246. entry->Handle = handle;
  247. entry->ReferenceCount = 1;
  248. LeaveCriticalSection (&header->Lock);
  249. }
  250. else
  251. {
  252. handle = 0;
  253. }
  254. return handle;
  255. }
  256. LPVOID
  257. ReferenceObject(
  258. HANDLE HandleTable,
  259. DWORD Handle,
  260. DWORD Key
  261. )
  262. /*++
  263. --*/
  264. {
  265. LPVOID context = 0;
  266. DWORD index;
  267. PHANDLETABLEENTRY entry;
  268. PHANDLETABLEHEADER header = (PHANDLETABLEHEADER) HandleTable;
  269. if (header && Handle >= header->HandleBase)
  270. {
  271. index = (Handle - header->HandleBase) >> 4;
  272. if (index < header->NumEntries)
  273. {
  274. EnterCriticalSection (&header->Lock);
  275. entry = header->Table + index;
  276. if (entry->Handle == Handle && entry->ReferenceCount != 0)
  277. {
  278. context = entry->Context.C;
  279. if (Key)
  280. {
  281. try
  282. {
  283. if (*((LPDWORD) context) == Key)
  284. {
  285. entry->ReferenceCount++;
  286. }
  287. else
  288. {
  289. context = 0;
  290. }
  291. }
  292. except (EXCEPTION_EXECUTE_HANDLER)
  293. {
  294. context = 0;
  295. }
  296. }
  297. else
  298. {
  299. entry->ReferenceCount++;
  300. }
  301. }
  302. LeaveCriticalSection (&header->Lock);
  303. }
  304. }
  305. return context;
  306. }
  307. LPVOID
  308. ReferenceObjectEx(
  309. HANDLE HandleTable,
  310. DWORD Handle,
  311. DWORD Key,
  312. LPVOID *Context2
  313. )
  314. /*++
  315. --*/
  316. {
  317. LPVOID context = 0;
  318. DWORD index;
  319. PHANDLETABLEENTRY entry;
  320. PHANDLETABLEHEADER header = (PHANDLETABLEHEADER) HandleTable;
  321. if (header && Handle >= header->HandleBase)
  322. {
  323. index = (Handle - header->HandleBase) >> 4;
  324. if (index < header->NumEntries)
  325. {
  326. EnterCriticalSection (&header->Lock);
  327. entry = header->Table + index;
  328. if (entry->Handle == Handle && entry->ReferenceCount != 0)
  329. {
  330. context = entry->Context.C;
  331. *Context2 = entry->Context.C2;
  332. if (Key)
  333. {
  334. try
  335. {
  336. if (*((LPDWORD) context) == Key)
  337. {
  338. entry->ReferenceCount++;
  339. }
  340. else
  341. {
  342. context = 0;
  343. }
  344. }
  345. except (EXCEPTION_EXECUTE_HANDLER)
  346. {
  347. context = 0;
  348. }
  349. }
  350. else
  351. {
  352. entry->ReferenceCount++;
  353. }
  354. }
  355. LeaveCriticalSection (&header->Lock);
  356. }
  357. }
  358. return context;
  359. }
  360. VOID
  361. DereferenceObject(
  362. HANDLE HandleTable,
  363. DWORD Handle,
  364. DWORD DereferenceCount
  365. )
  366. /*++
  367. --*/
  368. {
  369. LPVOID context, context2;
  370. DWORD index;
  371. PHANDLETABLEENTRY entry;
  372. PHANDLETABLEHEADER header = (PHANDLETABLEHEADER) HandleTable;
  373. if (header && Handle >= header->HandleBase)
  374. {
  375. index = (Handle - header->HandleBase) >> 4;
  376. if (index < header->NumEntries)
  377. {
  378. EnterCriticalSection (&header->Lock);
  379. entry = header->Table + index;
  380. if (entry->Handle == Handle && entry->ReferenceCount != 0)
  381. {
  382. assert (DereferenceCount >= entry->ReferenceCount);
  383. entry->ReferenceCount -= DereferenceCount;
  384. if (entry->ReferenceCount == 0)
  385. {
  386. entry->Instance = entry->Handle + 1;
  387. entry->Handle = 0;
  388. context = entry->Context.C;
  389. context2 = entry->Context.C2;
  390. InsertTailList (&header->FreeList, &entry->ListEntry);
  391. LeaveCriticalSection (&header->Lock);
  392. (*header->FreeContextCallback)(context, context2);
  393. return;
  394. }
  395. }
  396. else
  397. {
  398. // assert
  399. }
  400. LeaveCriticalSection (&header->Lock);
  401. }
  402. else
  403. {
  404. // assert
  405. }
  406. }
  407. }
  408. void
  409. ReleaseAllHandles(
  410. HANDLE HandleTable,
  411. PVOID Context2
  412. )
  413. {
  414. DWORD index;
  415. LPVOID context, context2;
  416. PHANDLETABLEENTRY entry;
  417. PHANDLETABLEHEADER header = (PHANDLETABLEHEADER) HandleTable;
  418. if (header && NULL != Context2)
  419. {
  420. EnterCriticalSection (&header->Lock);
  421. for (index = 0, entry = header->Table;
  422. index < header->NumEntries;
  423. index++, entry++)
  424. {
  425. if (0 != entry->Handle &&
  426. entry->Context.C2 == Context2)
  427. {
  428. entry->Instance = entry->Handle + 1;
  429. entry->Handle = 0;
  430. context = entry->Context.C;
  431. context2 = entry->Context.C2;
  432. InsertTailList (&header->FreeList, &entry->ListEntry);
  433. (*header->FreeContextCallback)(context, context2);
  434. }
  435. }
  436. LeaveCriticalSection (&header->Lock);
  437. }
  438. }