handles.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909
  1. /*++
  2. Copyright (c) 2013 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. handles.c
  9. Abstract:
  10. This module implements support for handles and handle tables.
  11. Author:
  12. Evan Green 16-Feb-2013
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/kernel.h>
  20. //
  21. // ---------------------------------------------------------------- Definitions
  22. //
  23. #define HANDLE_TABLE_ALLOCATION_TAG 0x646E6148 // 'dnaH'
  24. //
  25. // Define the initial size of the handle table, in entries.
  26. //
  27. #define HANDLE_TABLE_INITIAL_SIZE 16
  28. //
  29. // Define handle flags.
  30. //
  31. //
  32. // This flag is set when a handle table entry is allocated.
  33. //
  34. #define HANDLE_FLAG_ALLOCATED 0x80000000
  35. //
  36. // --------------------------------------------------------------------- Macros
  37. //
  38. //
  39. // These macros acquire and release the handle table locks if they exist.
  40. //
  41. #define OB_ACQUIRE_HANDLE_TABLE_LOCK(_Table) \
  42. if ((_Table)->Lock != NULL) { \
  43. KeAcquireQueuedLock((_Table)->Lock); \
  44. }
  45. #define OB_RELEASE_HANDLE_TABLE_LOCK(_Table) \
  46. if ((_Table)->Lock != NULL) { \
  47. KeReleaseQueuedLock((_Table)->Lock); \
  48. }
  49. //
  50. // ------------------------------------------------------ Data Type Definitions
  51. //
  52. /*++
  53. Structure Description:
  54. This structure defines a handle table entry.
  55. Members:
  56. Flags - Stores a bitfield of flags associated with this handle. Most of
  57. these flags are available for the user. A couple of the high ones are
  58. reserved.
  59. HandleValue - Stores the actual value of the handle.
  60. --*/
  61. typedef struct _HANDLE_TABLE_ENTRY {
  62. ULONG Flags;
  63. PVOID HandleValue;
  64. } HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
  65. /*++
  66. Structure Description:
  67. This structure defines a handle table.
  68. Members:
  69. Process - Stores a pointer to the process that owns the handle table.
  70. NextDescriptor - Stores the first free descriptor number.
  71. MaxDescriptor - Stores the maximum valid descriptor number.
  72. Entries - Stores the actual array of handles.
  73. ArraySize - Stores the number of elements in the array.
  74. Lock - Stores a pointer to a lock protecting access to the handle table.
  75. LookupCallback - Stores an optional pointer to a routine that is called
  76. whenever a handle is looked up.
  77. --*/
  78. struct _HANDLE_TABLE {
  79. PKPROCESS Process;
  80. ULONG NextDescriptor;
  81. ULONG MaxDescriptor;
  82. PHANDLE_TABLE_ENTRY Entries;
  83. ULONG ArraySize;
  84. PQUEUED_LOCK Lock;
  85. PHANDLE_TABLE_LOOKUP_CALLBACK LookupCallback;
  86. };
  87. //
  88. // ----------------------------------------------- Internal Function Prototypes
  89. //
  90. KSTATUS
  91. ObpExpandHandleTable (
  92. PHANDLE_TABLE Table,
  93. ULONG Descriptor
  94. );
  95. //
  96. // -------------------------------------------------------------------- Globals
  97. //
  98. //
  99. // ------------------------------------------------------------------ Functions
  100. //
  101. PHANDLE_TABLE
  102. ObCreateHandleTable (
  103. PVOID Process,
  104. PHANDLE_TABLE_LOOKUP_CALLBACK LookupCallbackRoutine
  105. )
  106. /*++
  107. Routine Description:
  108. This routine creates a new handle table. This routine must be called at low
  109. level.
  110. Arguments:
  111. Process - Supplies an optional pointer to the process that owns the handle
  112. table. When in doubt, supply NULL.
  113. LookupCallbackRoutine - Supplies an optional pointer that if supplied
  114. points to a function that will get called whenever a handle value is
  115. looked up (but not on iterates).
  116. Return Value:
  117. Returns a pointer to the new handle table on success.
  118. NULL on insufficient resource conditions.
  119. --*/
  120. {
  121. UINTN AllocationSize;
  122. PHANDLE_TABLE HandleTable;
  123. KSTATUS Status;
  124. ASSERT(KeGetRunLevel() == RunLevelLow);
  125. HandleTable = MmAllocatePagedPool(sizeof(HANDLE_TABLE),
  126. HANDLE_TABLE_ALLOCATION_TAG);
  127. if (HandleTable == NULL) {
  128. Status = STATUS_INSUFFICIENT_RESOURCES;
  129. goto CreateHandleTableEnd;
  130. }
  131. if (Process != NULL) {
  132. ObAddReference(Process);
  133. }
  134. HandleTable->Process = Process;
  135. HandleTable->Lock = NULL;
  136. HandleTable->NextDescriptor = 0;
  137. HandleTable->MaxDescriptor = 0;
  138. HandleTable->LookupCallback = LookupCallbackRoutine;
  139. AllocationSize = HANDLE_TABLE_INITIAL_SIZE * sizeof(HANDLE_TABLE_ENTRY);
  140. HandleTable->Entries = MmAllocatePagedPool(AllocationSize,
  141. HANDLE_TABLE_ALLOCATION_TAG);
  142. if (HandleTable->Entries == NULL) {
  143. Status = STATUS_INSUFFICIENT_RESOURCES;
  144. goto CreateHandleTableEnd;
  145. }
  146. RtlZeroMemory(HandleTable->Entries, AllocationSize);
  147. HandleTable->ArraySize = HANDLE_TABLE_INITIAL_SIZE;
  148. Status = STATUS_SUCCESS;
  149. CreateHandleTableEnd:
  150. if (!KSUCCESS(Status)) {
  151. if (HandleTable != NULL) {
  152. if (HandleTable->Entries != NULL) {
  153. MmFreePagedPool(HandleTable->Entries);
  154. }
  155. MmFreePagedPool(HandleTable);
  156. HandleTable = NULL;
  157. }
  158. }
  159. return HandleTable;
  160. }
  161. VOID
  162. ObDestroyHandleTable (
  163. PHANDLE_TABLE HandleTable
  164. )
  165. /*++
  166. Routine Description:
  167. This routine destroys a handle table. This routine must be called at low
  168. level.
  169. Arguments:
  170. HandleTable - Supplies a pointer to the handle table to destroy.
  171. Return Value:
  172. None.
  173. --*/
  174. {
  175. ASSERT(KeGetRunLevel() == RunLevelLow);
  176. if (HandleTable->Lock != NULL) {
  177. KeDestroyQueuedLock(HandleTable->Lock);
  178. }
  179. if (HandleTable->Entries != NULL) {
  180. MmFreePagedPool(HandleTable->Entries);
  181. }
  182. if (HandleTable->Process != NULL) {
  183. ObReleaseReference(HandleTable->Process);
  184. }
  185. MmFreePagedPool(HandleTable);
  186. return;
  187. }
  188. KSTATUS
  189. ObEnableHandleTableLocking (
  190. PHANDLE_TABLE HandleTable
  191. )
  192. /*++
  193. Routine Description:
  194. This routine enables locking on the given handle table.
  195. Arguments:
  196. HandleTable - Supplies a pointer to the handle table to enable locking for.
  197. Return Value:
  198. Status code.
  199. --*/
  200. {
  201. if (HandleTable->Lock == NULL) {
  202. HandleTable->Lock = KeCreateQueuedLock();
  203. if (HandleTable->Lock == NULL) {
  204. return STATUS_INSUFFICIENT_RESOURCES;
  205. }
  206. }
  207. return STATUS_SUCCESS;
  208. }
  209. KSTATUS
  210. ObCreateHandle (
  211. PHANDLE_TABLE Table,
  212. PVOID HandleValue,
  213. ULONG Flags,
  214. PHANDLE NewHandle
  215. )
  216. /*++
  217. Routine Description:
  218. This routine creates a new handle table entry. This routine must be called
  219. at low level.
  220. Arguments:
  221. Table - Supplies a pointer to the handle table.
  222. HandleValue - Supplies the value to be associated with the handle.
  223. Flags - Supplies a bitfield of flags to set with the handle. This value
  224. will be ANDed with HANDLE_FLAG_MASK, so bits set outside of that range
  225. will not stick.
  226. NewHandle - Supplies a pointer where the handle will be returned. On input,
  227. contains the minimum required value for the handle. Supply
  228. INVALID_HANDLE as the initial contents to let the system decide (which
  229. should be almost always).
  230. Return Value:
  231. STATUS_SUCCESS on success.
  232. STATUS_INSUFFICIENT_RESOURCES if memory could not be allocated for the
  233. handle table entry.
  234. STATUS_TOO_MANY_HANDLES if the given minimum handle value was too high.
  235. --*/
  236. {
  237. ULONG Descriptor;
  238. KSTATUS Status;
  239. ASSERT(KeGetRunLevel() == RunLevelLow);
  240. ASSERT((Table->Process == NULL) ||
  241. (Table->Process->ThreadCount == 0) ||
  242. (Table->Process == PsGetCurrentProcess()));
  243. OB_ACQUIRE_HANDLE_TABLE_LOCK(Table);
  244. //
  245. // Either use the next free slot, or try to use a descriptor at least as
  246. // high as the given handle.
  247. //
  248. if (*NewHandle == INVALID_HANDLE) {
  249. Descriptor = Table->NextDescriptor;
  250. } else {
  251. Descriptor = (UINTN)(*NewHandle);
  252. }
  253. //
  254. // Loop until a free slot is found.
  255. //
  256. while ((Descriptor < Table->ArraySize) &&
  257. ((Table->Entries[Descriptor].Flags & HANDLE_FLAG_ALLOCATED) != 0)) {
  258. Descriptor += 1;
  259. }
  260. if (*NewHandle == INVALID_HANDLE) {
  261. Table->NextDescriptor = Descriptor + 1;
  262. }
  263. //
  264. // Expand the table if needed.
  265. //
  266. if (Descriptor >= Table->ArraySize) {
  267. Status = ObpExpandHandleTable(Table, Descriptor);
  268. if (!KSUCCESS(Status)) {
  269. goto CreateHandleEnd;
  270. }
  271. }
  272. ASSERT(HandleValue != NULL);
  273. Table->Entries[Descriptor].Flags = HANDLE_FLAG_ALLOCATED |
  274. (Flags & HANDLE_FLAG_MASK);
  275. Table->Entries[Descriptor].HandleValue = HandleValue;
  276. *NewHandle = (HANDLE)(UINTN)Descriptor;
  277. if (Descriptor > Table->MaxDescriptor) {
  278. Table->MaxDescriptor = Descriptor;
  279. }
  280. Status = STATUS_SUCCESS;
  281. CreateHandleEnd:
  282. OB_RELEASE_HANDLE_TABLE_LOCK(Table);
  283. return Status;
  284. }
  285. VOID
  286. ObDestroyHandle (
  287. PHANDLE_TABLE Table,
  288. HANDLE Handle
  289. )
  290. /*++
  291. Routine Description:
  292. This routine destroys a handle.
  293. Arguments:
  294. Table - Supplies a pointer to the handle table.
  295. Handle - Supplies the handle returned when the handle was created.
  296. Return Value:
  297. None.
  298. --*/
  299. {
  300. ULONG Descriptor;
  301. ASSERT((Table->Process == NULL) ||
  302. (Table->Process->ThreadCount == 0) ||
  303. (Table->Process == PsGetCurrentProcess()));
  304. Descriptor = (UINTN)Handle;
  305. OB_ACQUIRE_HANDLE_TABLE_LOCK(Table);
  306. if (Descriptor >= Table->ArraySize) {
  307. goto DestroyHandleEnd;
  308. }
  309. if ((Table->Entries[Descriptor].Flags & HANDLE_FLAG_ALLOCATED) == 0) {
  310. goto DestroyHandleEnd;
  311. }
  312. Table->Entries[Descriptor].HandleValue = NULL;
  313. Table->Entries[Descriptor].Flags = 0;
  314. if (Table->NextDescriptor > Descriptor) {
  315. Table->NextDescriptor = Descriptor;
  316. }
  317. DestroyHandleEnd:
  318. OB_RELEASE_HANDLE_TABLE_LOCK(Table);
  319. return;
  320. }
  321. KSTATUS
  322. ObReplaceHandleValue (
  323. PHANDLE_TABLE Table,
  324. HANDLE Handle,
  325. PVOID NewHandleValue,
  326. ULONG NewFlags,
  327. PVOID *OldHandleValue,
  328. PULONG OldFlags
  329. )
  330. /*++
  331. Routine Description:
  332. This routine replaces a handle table entry, or creates a handle if none was
  333. there before. This routine must be called at low level.
  334. Arguments:
  335. Table - Supplies a pointer to the handle table.
  336. Handle - Supplies the handle to replace or create.
  337. NewHandleValue - Supplies the value to be associated with the handle.
  338. NewFlags - Supplies the new handle flags to set.
  339. OldHandleValue - Supplies an optional pointer where the original handle
  340. value will be returned.
  341. OldFlags - Supplies an optional pointer where the original handle flags
  342. will be returned.
  343. Return Value:
  344. STATUS_SUCCESS on success.
  345. STATUS_INSUFFICIENT_RESOURCES if memory could not be allocated for the
  346. handle table entry.
  347. STATUS_TOO_MANY_HANDLES if the given minimum handle value was too high.
  348. --*/
  349. {
  350. ULONG Descriptor;
  351. KSTATUS Status;
  352. ASSERT(KeGetRunLevel() == RunLevelLow);
  353. ASSERT((Table->Process == NULL) ||
  354. (Table->Process->ThreadCount == 0) ||
  355. (Table->Process == PsGetCurrentProcess()));
  356. OB_ACQUIRE_HANDLE_TABLE_LOCK(Table);
  357. ASSERT(Handle != INVALID_HANDLE);
  358. Descriptor = (UINTN)Handle;
  359. if (Descriptor >= Table->ArraySize) {
  360. Status = ObpExpandHandleTable(Table, Descriptor);
  361. if (!KSUCCESS(Status)) {
  362. goto ReplaceHandleValueEnd;
  363. }
  364. }
  365. ASSERT(NewHandleValue != NULL);
  366. if (OldFlags != NULL) {
  367. *OldFlags = Table->Entries[Descriptor].Flags & HANDLE_FLAG_MASK;
  368. }
  369. if (OldHandleValue != NULL) {
  370. *OldHandleValue = Table->Entries[Descriptor].HandleValue;
  371. }
  372. Table->Entries[Descriptor].Flags = HANDLE_FLAG_ALLOCATED |
  373. (NewFlags & HANDLE_FLAG_MASK);
  374. Table->Entries[Descriptor].HandleValue = NewHandleValue;
  375. if (Descriptor > Table->MaxDescriptor) {
  376. Table->MaxDescriptor = Descriptor;
  377. }
  378. Status = STATUS_SUCCESS;
  379. ReplaceHandleValueEnd:
  380. OB_RELEASE_HANDLE_TABLE_LOCK(Table);
  381. return Status;
  382. }
  383. PVOID
  384. ObGetHandleValue (
  385. PHANDLE_TABLE Table,
  386. HANDLE Handle,
  387. PULONG Flags
  388. )
  389. /*++
  390. Routine Description:
  391. This routine looks up the given handle and returns the value associated
  392. with that handle.
  393. Arguments:
  394. Table - Supplies a pointer to the handle table.
  395. Handle - Supplies the handle returned when the handle was created.
  396. Flags - Supplies an optional pointer that receives value of the handle's
  397. flags.
  398. Return Value:
  399. Returns the value associated with that handle upon success.
  400. NULL if the given handle is invalid.
  401. --*/
  402. {
  403. ULONG Descriptor;
  404. ULONG LocalFlags;
  405. PVOID Value;
  406. ASSERT((Table->Process == NULL) ||
  407. (Table->Process->ThreadCount == 0) ||
  408. (Table->Process == PsGetCurrentProcess()));
  409. Descriptor = (UINTN)Handle;
  410. LocalFlags = 0;
  411. Value = NULL;
  412. OB_ACQUIRE_HANDLE_TABLE_LOCK(Table);
  413. if (Descriptor >= Table->ArraySize) {
  414. goto GetHandleValueEnd;
  415. }
  416. LocalFlags = Table->Entries[Descriptor].Flags;
  417. if ((LocalFlags & HANDLE_FLAG_ALLOCATED) == 0) {
  418. goto GetHandleValueEnd;
  419. }
  420. Value = Table->Entries[Descriptor].HandleValue;
  421. if (Table->LookupCallback != NULL) {
  422. Table->LookupCallback(Table, (HANDLE)(UINTN)Descriptor, Value);
  423. }
  424. GetHandleValueEnd:
  425. OB_RELEASE_HANDLE_TABLE_LOCK(Table);
  426. if ((Flags != NULL) && (Value != NULL)) {
  427. *Flags = LocalFlags & HANDLE_FLAG_MASK;
  428. }
  429. return Value;
  430. }
  431. KSTATUS
  432. ObGetSetHandleFlags (
  433. PHANDLE_TABLE Table,
  434. HANDLE Handle,
  435. BOOL Set,
  436. PULONG Flags
  437. )
  438. /*++
  439. Routine Description:
  440. This routine sets and/or returns the flags associated with a handle. The
  441. lookup callback routine initialized with the handle table is not called
  442. during this operation.
  443. Arguments:
  444. Table - Supplies a pointer to the handle table.
  445. Handle - Supplies the handle whose flags should be retrieved.
  446. Set - Supplies a boolean indicating if the value in the flags parameter
  447. should be set as the new value.
  448. Flags - Supplies a pointer that on input contains the value of the flags
  449. to set if the set parameter is TRUE. This value will be ANDed with
  450. HANDLE_FLAG_MASK, so bits set outside of that mask will not stick.
  451. On output, contains the original value of the flags before the set was
  452. performed.
  453. Return Value:
  454. STATUS_SUCCESS on success.
  455. STATUS_INVALID_HANDLE if no such handle could be found.
  456. --*/
  457. {
  458. ULONG Descriptor;
  459. ULONG NewValue;
  460. ULONG OriginalValue;
  461. KSTATUS Status;
  462. ASSERT((Table->Process == NULL) ||
  463. (Table->Process->ThreadCount == 0) ||
  464. (Table->Process == PsGetCurrentProcess()));
  465. Status = STATUS_INVALID_HANDLE;
  466. Descriptor = (UINTN)Handle;
  467. OB_ACQUIRE_HANDLE_TABLE_LOCK(Table);
  468. if (Descriptor >= Table->ArraySize) {
  469. goto GetSetHandleFlagsEnd;
  470. }
  471. if ((Table->Entries[Descriptor].Flags & HANDLE_FLAG_ALLOCATED) == 0) {
  472. goto GetSetHandleFlagsEnd;
  473. }
  474. Status = STATUS_SUCCESS;
  475. NewValue = *Flags;
  476. OriginalValue = Table->Entries[Descriptor].Flags;
  477. *Flags = OriginalValue & HANDLE_FLAG_MASK;
  478. if (Set != FALSE) {
  479. Table->Entries[Descriptor].Flags = (NewValue & HANDLE_FLAG_MASK) |
  480. (OriginalValue & ~HANDLE_FLAG_MASK);
  481. }
  482. GetSetHandleFlagsEnd:
  483. OB_RELEASE_HANDLE_TABLE_LOCK(Table);
  484. return Status;
  485. }
  486. HANDLE
  487. ObGetHighestHandle (
  488. PHANDLE_TABLE Table
  489. )
  490. /*++
  491. Routine Description:
  492. This routine returns the highest allocated handle.
  493. Arguments:
  494. Table - Supplies a pointer to the handle table.
  495. Return Value:
  496. Returns the highest handle number (not the handle value).
  497. INVALID_HANDLE if the table is empty.
  498. --*/
  499. {
  500. ULONG Descriptor;
  501. HANDLE Handle;
  502. ASSERT((Table->Process == NULL) ||
  503. (Table->Process->ThreadCount == 0) ||
  504. (Table->Process == PsGetCurrentProcess()));
  505. Handle = INVALID_HANDLE;
  506. OB_ACQUIRE_HANDLE_TABLE_LOCK(Table);
  507. Descriptor = Table->MaxDescriptor;
  508. ASSERT(Descriptor < Table->ArraySize);
  509. while ((Table->Entries[Descriptor].Flags & HANDLE_FLAG_ALLOCATED) == 0) {
  510. if (Descriptor == 0) {
  511. break;
  512. }
  513. Descriptor -= 1;
  514. }
  515. if ((Table->Entries[Descriptor].Flags & HANDLE_FLAG_ALLOCATED) != 0) {
  516. Handle = (HANDLE)(UINTN)Descriptor;
  517. }
  518. Table->MaxDescriptor = Descriptor;
  519. OB_RELEASE_HANDLE_TABLE_LOCK(Table);
  520. return Handle;
  521. }
  522. VOID
  523. ObHandleTableIterate (
  524. PHANDLE_TABLE Table,
  525. PHANDLE_TABLE_ITERATE_ROUTINE IterateRoutine,
  526. PVOID IterateRoutineContext
  527. )
  528. /*++
  529. Routine Description:
  530. This routine iterates through all handles in the given handle table, and
  531. calls the given handle table for each one. The table will be locked when the
  532. iterate routine is called, so the iterate routine must not make any calls
  533. that would require use of the handle table.
  534. Arguments:
  535. Table - Supplies a pointer to the handle table to iterate through.
  536. IterateRoutine - Supplies a pointer to the routine to be called for each
  537. handle in the table.
  538. IterateRoutineContext - Supplies an opaque context pointer that will get
  539. passed to the iterate routine each time it is called.
  540. Return Value:
  541. None.
  542. --*/
  543. {
  544. ULONG Descriptor;
  545. ASSERT((Table->Process == NULL) ||
  546. (Table->Process->ThreadCount == 0) ||
  547. (Table->Process == PsGetCurrentProcess()));
  548. OB_ACQUIRE_HANDLE_TABLE_LOCK(Table);
  549. for (Descriptor = 0; Descriptor <= Table->MaxDescriptor; Descriptor += 1) {
  550. if ((Table->Entries[Descriptor].Flags & HANDLE_FLAG_ALLOCATED) == 0) {
  551. continue;
  552. }
  553. IterateRoutine(Table,
  554. (HANDLE)(UINTN)Descriptor,
  555. Table->Entries[Descriptor].Flags & HANDLE_FLAG_MASK,
  556. Table->Entries[Descriptor].HandleValue,
  557. IterateRoutineContext);
  558. }
  559. OB_RELEASE_HANDLE_TABLE_LOCK(Table);
  560. return;
  561. }
  562. //
  563. // --------------------------------------------------------- Internal Functions
  564. //
  565. KSTATUS
  566. ObpExpandHandleTable (
  567. PHANDLE_TABLE Table,
  568. ULONG Descriptor
  569. )
  570. /*++
  571. Routine Description:
  572. This routine expands the given handle table to support a given number of
  573. descriptors.
  574. Arguments:
  575. Table - Supplies a pointer to the handle table to expand.
  576. Descriptor - Supplies the descriptor that will need to be inserted in the
  577. handle table.
  578. Return Value:
  579. Status code.
  580. --*/
  581. {
  582. UINTN AllocationSize;
  583. PVOID NewBuffer;
  584. UINTN NewCapacity;
  585. KSTATUS Status;
  586. if (Descriptor >= OB_MAX_HANDLES) {
  587. Status = STATUS_INVALID_HANDLE;
  588. goto ExpandHandleTableEnd;
  589. }
  590. //
  591. // Expand the table if needed.
  592. //
  593. if (Descriptor >= Table->ArraySize) {
  594. NewCapacity = Table->ArraySize * 2;
  595. while ((NewCapacity <= Descriptor) &&
  596. (NewCapacity >= Table->ArraySize)) {
  597. NewCapacity *= 2;
  598. }
  599. AllocationSize = NewCapacity * sizeof(HANDLE_TABLE_ENTRY);
  600. if ((NewCapacity <= Descriptor) ||
  601. (NewCapacity < Table->ArraySize) ||
  602. ((AllocationSize / sizeof(HANDLE_TABLE_ENTRY)) != NewCapacity)) {
  603. Status = STATUS_TOO_MANY_HANDLES;
  604. goto ExpandHandleTableEnd;
  605. }
  606. ASSERT((NewCapacity > Table->ArraySize) &&
  607. (NewCapacity > Table->NextDescriptor));
  608. NewBuffer = MmAllocatePagedPool(AllocationSize,
  609. HANDLE_TABLE_ALLOCATION_TAG);
  610. if (NewBuffer == NULL) {
  611. Status = STATUS_INSUFFICIENT_RESOURCES;
  612. goto ExpandHandleTableEnd;
  613. }
  614. RtlCopyMemory(NewBuffer,
  615. Table->Entries,
  616. Table->ArraySize * sizeof(HANDLE_TABLE_ENTRY));
  617. RtlZeroMemory(
  618. NewBuffer + (Table->ArraySize * sizeof(HANDLE_TABLE_ENTRY)),
  619. (NewCapacity - Table->ArraySize) * sizeof(HANDLE_TABLE_ENTRY));
  620. MmFreePagedPool(Table->Entries);
  621. Table->Entries = NewBuffer;
  622. Table->ArraySize = NewCapacity;
  623. }
  624. Status = STATUS_SUCCESS;
  625. ExpandHandleTableEnd:
  626. return Status;
  627. }