handles.c 20 KB

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