Leaked source code of windows server 2003
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.

1675 lines
73 KiB

  1. /*
  2. * handfact.c
  3. *
  4. * author: John R. Douceur
  5. * date: 26 January 1998
  6. *
  7. * This source file provides functions that implement assignment, release, and
  8. * dereferencing operations with a handle_factory. The code is object-oriented
  9. * C, transliterated from a C++ implementation.
  10. *
  11. * The handle factory is a component that generates and validates handles. It
  12. * is intended to be used in a software module that provides client software
  13. * modules with means to refer to information structures contained within the
  14. * provider. While such a means could simply be a pointer, this would not
  15. * enable the deletion of the information structures without explicitly
  16. * notifying the clients of such deletion. Unlike pointers, the handles
  17. * generated by the handle factory can be examined (by the handle factory)
  18. * to determine their validity.
  19. *
  20. * Handles can be invalidated in one of two ways. The handle can be released
  21. * by calling the release_HF_handle() function, indicating to the handle
  22. * factory that the handle is no longer necessary and that future requests
  23. * to dereference this handle should be met with a null pointer. Alternately,
  24. * the handle can be revoked by the handle factory; this will happen unter two
  25. * circumstances. If a large number of handles (more than four billion) are
  26. * issued and subsequently released, it becomes necessary to reuse portions of
  27. * the handle space for future assignments; under these circumstances, very
  28. * old handles will be revoked well before this recycling occurs, to give the
  29. * holders of those handles ample opportunity to notice that their handles
  30. * have become invalid and to request new handles. The other situation in
  31. * which revokation can occur is if the amount of available memory becomes
  32. * too small to allocate additional space to expand the handle database; then,
  33. * if the assignment of a new handle is requested, the least-recently-assigned
  34. * handle will be revoked to make room for the new request.
  35. *
  36. * Use of the handle factory in a multi-threaded environment requires a lock.
  37. * This lock must be taken by a single thread for the execution of either
  38. * assign_HF_handle() or release_HF_handle(). Use of dereference_HF_handle()
  39. * does not require taking a lock, since synchronization is handled internally
  40. * through careful sequencing of read and write operations.
  41. *
  42. * None of the code or comments in this file need to be understood by writers
  43. * of client code; all explanatory information for clients is found in the
  44. * associated header file, handfact.h.
  45. *
  46. */
  47. #include "precomp.h"
  48. /*
  49. * There are a number of aspects to the handle factory that must be understood
  50. * by anyone wishing to modify this code. The description in this comment
  51. * block is intended to provide a progressive overview of the handle factory.
  52. *
  53. * The basic system comprises a table of entries. Each assigned handle
  54. * corresponds to a single, unique entry, as determined by the handle value
  55. * modulo the table size. A handle is validated by comparing the handle value
  56. * to the stored handle value in the entry. The unassigned entries are kept
  57. * on a list; when an entry is released (or revoked), it is put on the tail of
  58. * the list, and when an entry is needed for an assignment, it is taken from
  59. * the head of the list.
  60. *
  61. * If there are no unassigned entries in the table when a new handle is
  62. * requested, a new table of twice the size is allocated, and all assigned
  63. * handles are relocated to the new table. All unassigned handles in the new
  64. * table are placed on the unassigned list.
  65. *
  66. * As handles are released, the space required for handle entries is reduced.
  67. * The table can be contracted into a table of half the size if no two assigned
  68. * handles will yield the same entry address. Two handles which will yield
  69. * the same entry address in a half-size table are called a pair, and the
  70. * number of such pairs is tracked in the variable pair_count, which must be
  71. * zero in order to contract the table. In order to minimize the number of
  72. * pairs in the table, there are actually two lists of unassigned entries.
  73. * Assigning an entry from the primary list will not increase the pair count,
  74. * whereas assigning an entry from the secondary list will increase the pair
  75. * count. Thus, assignments are always made from the primary list, if it is
  76. * not empty.
  77. *
  78. * Assigned handles are also kept on a list, in order of assignment. If it
  79. * becomes necessary to revoke a handle to make room for another, the oldest
  80. * handle will be revoked, and it will be found at the head of this list.
  81. *
  82. */
  83. // This macro allocates an array of HFEntry structures. The size of the array
  84. // is provided as an argument to the macro.
  85. //
  86. #define NEW_HFEntry_array(array_size) \
  87. ((HFEntry *)malloc(array_size * sizeof(HFEntry)))
  88. // This macro allocates an array of integers. The size of the array is
  89. // provided as an argument to the macro.
  90. //
  91. #define NEW_int_array(array_size) \
  92. ((int *)malloc(array_size * sizeof(int)))
  93. /*
  94. * Following are prototypes for static functions that are used internally by
  95. * the handle factory routines.
  96. *
  97. */
  98. // This function doubles the size of the table in which the handles and pointers
  99. // are stored. It is called by assign_HF_handle() when there is insufficient
  100. // space in the table to assign the newly requested handle. If the expansion
  101. // is successful, the function returns a value of 0. If the expansion fails
  102. // (due, for example, to an inability to allocate memory), the function returns
  103. // a value of 1.
  104. //
  105. int expand_HF_table(
  106. HandleFactory *hfact);
  107. // This function halves the size of the table in which the handles and pointers
  108. // are stored. In order to reduce the amount of space consumed by the handle
  109. // factory, this function is called called by release_HF_handle() and
  110. // revoke_ancient_HF_handles() when they determine that the table can and should
  111. // be contracted. The table can be contracted when pair_count == 0 and
  112. // table_size > 2. However, the table may not be contracted then, because
  113. // hysteresis is employed both to keep the mean assignment and release times
  114. // constant and to minimize the allocation chatter of rapidly expanding and
  115. // contracting the table. If the contraction is successful, the function
  116. // returns a value of 0. If the contraction fails, the function returns a
  117. // value of 1.
  118. //
  119. int contract_HF_table(
  120. HandleFactory *hfact);
  121. // This function revokes handles that are between handle_base and handle_base
  122. // + 2 * HANDLE_RANGE_STEP - 1, inclusive. It then increments the value of
  123. // handle_base by HANDLE_RANGE_STEP. Suspended handles will be revoked one
  124. // revokation pass later than non-suspended handles.
  125. //
  126. void revoke_ancient_HF_handles(
  127. HandleFactory *hfact);
  128. // Every entry is on one of three lists, and the heads and tails of these lists
  129. // are maintained in the entry_list[] array. The index of this array is given
  130. // by the following three manifest constants.
  131. //
  132. #define LD_PRIMARY 0 // first list from which to select an entry to assign
  133. #define LD_SECONDARY 1 // second list from which to select an entry to assign
  134. #define LD_ASSIGNED 2 // list of assigned entries, in order of assignment age
  135. // When the handle space is recycled, there is a danger of handle collisions.
  136. // In order to substantially reduce the likelihood of these collisions, very
  137. // old handles are revoked well before their recycling begins, to give the
  138. // holders of these handles ample opportunity to notice that their handles
  139. // have become invalid and to request new handles. Thus, handles are revoked
  140. // when they become more than MAX_HANDLE_RANGE less than the currently generated
  141. // handles. To reduce overhead, revokations are performed in batches of size
  142. // determined by HANDLE_RANGE_STEP.
  143. //
  144. // A handle may be suspended by incrementing the handle value by
  145. // HANDLE_RANGE_STEP. This causes the comparison in dereference_HF_handle() to
  146. // fail, so the handle is judged to be invalid. To reinstate the handle, the
  147. // handle value is decremented by HANDLE_RANGE_STEP, returning the handle to its
  148. // original value. A handle that is suspended will be revoked one revokation
  149. // pass later than it would have been if it hadn't been suspended.
  150. //
  151. #define HANDLE_RANGE_STEP ((HFHandle)0x20000000)
  152. #define MAX_HANDLE_RANGE ((HFHandle)0x90000000)
  153. // To keep the mean assignment and release times constant (and, indirectly, to
  154. // minimize the allocation chatter of rapidly expanding and contracting the
  155. // table), the table is not necessarily contracted as soon as possible.
  156. // Hysteresis is employed to postpone the contraction until the computational
  157. // cost of previous expansions and contractions is distributed over a sufficient
  158. // number of assignment or release operations to maintain a constant cost per
  159. // operation ratio. The cost of each expansion is equal to the overhead of
  160. // memory allocation and deallocation plus the cost to split each entry into
  161. // two entries. The cost of each contraction is equal to the overhead of
  162. // memory allocation and deallocation plus the cost to merge each pair of
  163. // entries into one entry. The cost of memory allocation and deallocation is
  164. // equal to ALLOCATION_COST times the mean cost of a single split or merge
  165. // operation. This value was determined by empirical measurement.
  166. //
  167. #define ALLOCATION_COST 12
  168. // This manifest constant is used by the expand and contract routines to request
  169. // access to a set of table_size and entries variables. It is subtracted from
  170. // the appropriate sync variable. If there are ever more than SYNC_SUBTRAHEND
  171. // threads simultaneously invoking dereference_HF_handle{), then the
  172. // synchronization logic will break.
  173. //
  174. #define SYNC_SUBTRAHEND 1000000000
  175. // Since this is not C++, the HandleFactory structure is not self-constructing;
  176. // therefore, the following constructor code must be called on the HandleFactory
  177. // structure after it is allocated. If the construction is successful, the
  178. // function returns a value of 0. If the construction fails (due, for example,
  179. // to an inability to allocate memory), the function returns a value of 1.
  180. //
  181. int
  182. constructHandleFactory(
  183. HandleFactory *hfact)
  184. {
  185. int table_size;
  186. HFEntry *entries;
  187. // The table size is initially set to 2, and it will never be smaller.
  188. table_size = 2;
  189. // Allocate space for the initial table.
  190. entries = NEW_HFEntry_array(table_size);
  191. if (entries == 0)
  192. {
  193. // Memory could not be allocated for the array of entries created by
  194. // the constructor. Therefore, we return an indication of failure to
  195. // the client.
  196. return 1;
  197. }
  198. // Initially, both sets of the table_size and entries variables are set
  199. // equal. They will match most of the time except during the very brief
  200. // moments when the table size is changed during an expansion or
  201. // contraction.
  202. hfact->table_size[0] = table_size;
  203. hfact->entries[0] = entries;
  204. hfact->table_size[1] = table_size;
  205. hfact->entries[1] = entries;
  206. // The sync variables are initialized to zero. These variables are
  207. // incremented by the dereference_HF_handle() routine to request access to
  208. // the corresponding table_size and entries variables. They are massively
  209. // decremented (by a value of SYNC_SUBTRAHEND) by the expansion and
  210. // contraction routines to request permission to change the corresponding
  211. // table_size and entries variables. If a sync variable is positive, then
  212. // at least one thread using the dereference routine has access to the
  213. // corresponding table_size and entries variables. If a sync variable
  214. // equals -SYNC_SUBTRAHEND, then the expand or contract routine has access
  215. // to the corresponding variables. A zero value means no one has requested
  216. // access, and a negative value greater than -SYNC_SUBTRAHEND means that
  217. // the expand or contract routine has requested access but has to wait
  218. // for one or more dereference threads to finish access.
  219. hfact->sync[0] = 0;
  220. hfact->sync[1] = 0;
  221. // Initially, the default variable set is set to zero. This is arbitrary;
  222. // it could be set to one, instead.
  223. hfact->varset = 0;
  224. hfact->handle_base = 0; // handles will start with 0
  225. hfact->population = 0; // no handles initially assigned
  226. hfact->pair_count = 0; // since no assigned handles, no pairs
  227. hfact->hysteresis_debt = 0;
  228. // Initialize the two entries that are initially allocated. Both are marked
  229. // as unassigned; the larger value (2) is put on the secondary list, and the
  230. // smaller value (1) on the secondary list. Record 0 contains an initial
  231. // handle value of 2 instead of 0 because a handle value of 0 is reserved.
  232. entries[0].handle = hfact->handle_base + table_size;
  233. entries[0].next_handle = hfact->handle_base + table_size;
  234. entries[0].reference = 0;
  235. entries[0].next_entry = &hfact->entry_list[LD_SECONDARY];
  236. entries[0].prev_entry = &hfact->entry_list[LD_SECONDARY];
  237. entries[1].handle = hfact->handle_base + 1;
  238. entries[1].next_handle = hfact->handle_base + 1;
  239. entries[1].reference = 0;
  240. entries[1].next_entry = &hfact->entry_list[LD_PRIMARY];
  241. entries[1].prev_entry = &hfact->entry_list[LD_PRIMARY];
  242. // Initialize the primary list. This list initially contains entry 1.
  243. hfact->entry_list[LD_PRIMARY].handle = 0;
  244. hfact->entry_list[LD_PRIMARY].next_handle = 0;
  245. hfact->entry_list[LD_PRIMARY].reference = 0;
  246. hfact->entry_list[LD_PRIMARY].next_entry = &entries[1];
  247. hfact->entry_list[LD_PRIMARY].prev_entry = &entries[1];
  248. // Initialize the secondary list. This list initially contains entry 0.
  249. hfact->entry_list[LD_SECONDARY].handle = 0;
  250. hfact->entry_list[LD_SECONDARY].next_handle = 0;
  251. hfact->entry_list[LD_SECONDARY].reference = 0;
  252. hfact->entry_list[LD_SECONDARY].next_entry = &entries[0];
  253. hfact->entry_list[LD_SECONDARY].prev_entry = &entries[0];
  254. // Initialize the assigned list. This list initially is empty.
  255. hfact->entry_list[LD_ASSIGNED].handle = 0;
  256. hfact->entry_list[LD_ASSIGNED].next_handle = 0;
  257. hfact->entry_list[LD_ASSIGNED].reference = 0;
  258. hfact->entry_list[LD_ASSIGNED].next_entry = &hfact->entry_list[LD_ASSIGNED];
  259. hfact->entry_list[LD_ASSIGNED].prev_entry = &hfact->entry_list[LD_ASSIGNED];
  260. // Reduce handle_base by HANDLE_RANGE_STEP so that suspended handles will
  261. // not slip through revokation.
  262. hfact->handle_base -= HANDLE_RANGE_STEP;
  263. // return an indication of success to the client.
  264. return 0;
  265. }
  266. // Since this is not C++, the HandleFactory structure is not self-destructing;
  267. // therefore, the following destructor code must be called on the HandleFactory
  268. // structure before it is deallocated.
  269. //
  270. void
  271. destructHandleFactory(
  272. HandleFactory *hfact)
  273. {
  274. // Free the space consumed by the table of handles.
  275. free(hfact->entries[hfact->varset]);
  276. }
  277. // This function generates a new handle value, associates the handle value with
  278. // the provided reference pointer, and returns the handle value. Barring
  279. // highly unusual circumstances, this handle will remain valid until it is
  280. // explicitly released by a call to release_HF_handle(). However, there is no
  281. // guarantee that the handle will persist for an arbitrary duration; it may
  282. // become necessary for the handle factory to revoke the handle under some
  283. // circumstances, particularly when the handle becomes very old or when memory
  284. // becomes scarce.
  285. //
  286. // The assign_HF_handle() function will never return a handle value of zero.
  287. // Thus, the client program is free to use a zero handle value as an escape
  288. // indicator, if desired.
  289. //
  290. // In a multi-threaded environment, a single thread must take a lock prior to
  291. // calling this function, and this must be the same lock taken before calling
  292. // release_HF_handle().
  293. //
  294. HFHandle
  295. assign_HF_handle(
  296. HandleFactory *hfact,
  297. void *reference)
  298. {
  299. int table_size;
  300. int list;
  301. HFEntry *entry;
  302. volatile HFEntry *seq_entry; // volatile to ensure sequencing
  303. HFHandle handle;
  304. HFHandle handle_range;
  305. table_size = hfact->table_size[hfact->varset];
  306. if (hfact->population >= table_size)
  307. {
  308. // All entries in the table are assigned, so it is necessary to
  309. // increase the table size.
  310. int expansion_failure = expand_HF_table(hfact);
  311. // Update the local value of table_size to reflect the new value.
  312. table_size = hfact->table_size[hfact->varset];
  313. if (expansion_failure)
  314. {
  315. // Expanding the table failed, presumably due to inability to
  316. // allocate sufficient memory. So, instead, we revoke the least-
  317. // recently assigned handle. First, remove the entry from the
  318. // assigned list and place it on the secondary list.
  319. entry = hfact->entry_list[LD_ASSIGNED].next_entry;
  320. entry->next_entry->prev_entry = &hfact->entry_list[LD_ASSIGNED];
  321. hfact->entry_list[LD_ASSIGNED].next_entry = entry->next_entry;
  322. entry->next_entry = &hfact->entry_list[LD_SECONDARY];
  323. entry->prev_entry = hfact->entry_list[LD_SECONDARY].prev_entry;
  324. hfact->entry_list[LD_SECONDARY].prev_entry->next_entry = entry;
  325. hfact->entry_list[LD_SECONDARY].prev_entry = entry;
  326. // Then, invalidate the handle. The order of the operations is
  327. // important to correct multi-threaded operation.
  328. seq_entry = entry;
  329. seq_entry->handle = entry->next_handle; // first invalidate handle
  330. seq_entry->reference = 0; // then clear reference
  331. // Decrement the pair count and population, so that when they are
  332. // incremented in the code below, they will have correct values.
  333. hfact->pair_count--;
  334. hfact->population--;
  335. }
  336. }
  337. // At this point, there is at least one available entry. If there is any
  338. // entry on the primary list, it should be selected.
  339. list = LD_PRIMARY;
  340. if (hfact->entry_list[LD_PRIMARY].next_entry ==
  341. &hfact->entry_list[LD_PRIMARY])
  342. {
  343. // The primary list is empty, so we take from the secondary list. By
  344. // definition, this will increase the pair count.
  345. list = LD_SECONDARY;
  346. hfact->pair_count++;
  347. }
  348. // Remove the entry from the head of the appropriate list and place it on
  349. // the assigned list.
  350. entry = hfact->entry_list[list].next_entry;
  351. handle = entry->handle;
  352. entry->next_entry->prev_entry = entry->prev_entry;
  353. entry->prev_entry->next_entry = entry->next_entry;
  354. entry->next_entry = &hfact->entry_list[LD_ASSIGNED];
  355. entry->prev_entry = hfact->entry_list[LD_ASSIGNED].prev_entry;
  356. hfact->entry_list[LD_ASSIGNED].prev_entry->next_entry = entry;
  357. hfact->entry_list[LD_ASSIGNED].prev_entry = entry;
  358. // Set the reference pointer to that provided as an argument.
  359. entry->reference = reference;
  360. // The next handle for this entry will be greater by the table size. It
  361. // is important to set this value in this routine because unequal values of
  362. // handle and next_handle indicate an assigned entry.
  363. entry->next_handle = handle + table_size;
  364. if (entry->next_handle == 0)
  365. {
  366. // The handle value has wrapped around back to zero; however, zero is
  367. // a reserved value, so we instead set the next handle to the subsequent
  368. // legal value, which is the table size.
  369. entry->next_handle = table_size;
  370. }
  371. // The population has increased by one.
  372. hfact->population++;
  373. // We're being tricky with unsigned integer math here. We revoke ancient
  374. // handles if the value of the handle we are currently issuing is greater
  375. // than the handle base by more than MAX_HANDLE_RANGE, modulo the size of
  376. // the handle space. The modulo is implicit.
  377. handle_range = handle - hfact->handle_base;
  378. if (handle_range > MAX_HANDLE_RANGE)
  379. {
  380. revoke_ancient_HF_handles(hfact);
  381. }
  382. // This assignment operation decreases the hysteresis debt.
  383. if (hfact->hysteresis_debt > 0)
  384. {
  385. hfact->hysteresis_debt--;
  386. }
  387. // Return the newly assigned handle.
  388. return handle;
  389. }
  390. // This function releases a handle, indicating that further attempts to
  391. // dereference the handle should result in a null pointer value rather than the
  392. // pointer value that was originally assigned to the handle. The handle factory
  393. // checks the validity of the handle and returns a corresponding status code.
  394. // If the handle is currently assigned, then it is released, and the function
  395. // returns a value of 0. If the handle is not currently assigned, the function
  396. // aborts and returns a value of 1.
  397. //
  398. // In a multi-threaded environment, a single thread must take a lock prior to
  399. // calling this function, and this must be the same lock taken before calling
  400. // assign_HF_handle().
  401. //
  402. int
  403. release_HF_handle(
  404. HandleFactory *hfact,
  405. HFHandle handle)
  406. {
  407. int table_size;
  408. HFEntry *entries;
  409. int entry_index;
  410. HFEntry *entry;
  411. HFEntry *other_entry;
  412. int list;
  413. HFHandle adjusted_next_handle;
  414. HFHandle adjusted_other_next_handle;
  415. volatile HFEntry *seq_entry; // volatile to ensure sequencing
  416. table_size = hfact->table_size[hfact->varset];
  417. entries = hfact->entries[hfact->varset];
  418. // Compute the index of the entry by taking the handle value modulo the
  419. // table size. Since the table size is a power of two, we can simply
  420. // subtract one to produce a mask and then conjoin the mask with the
  421. // handle value.
  422. entry_index = handle & table_size - 1;
  423. entry = &entries[entry_index];
  424. if ((entry->handle != handle && entry->handle != handle + HANDLE_RANGE_STEP)
  425. || entry->handle == entry->next_handle)
  426. {
  427. // Either the indexed entry does not refer to the provided handle nor to
  428. // the provided handle's suspension value, or the entry is unassigned.
  429. // In any of these cases, abort and return an error code to the client.
  430. return 1;
  431. }
  432. // The "other entry" is the entry that would have to be merged with the
  433. // indexed entry if the table size were to be contracted in half.
  434. other_entry = &entries[entry_index ^ table_size / 2];
  435. if (other_entry->handle == other_entry->next_handle)
  436. {
  437. // We're being tricky with unsigned integer math here. Before comparing
  438. // the two next handles, we subtract from each the value of handle_base,
  439. // modulo the size of the handle space (the modulo is implicit). This
  440. // allows the effective comparison of their logical acyclic values
  441. // rather than their actual cyclic values.
  442. adjusted_next_handle = entry->next_handle - hfact->handle_base;
  443. adjusted_other_next_handle =
  444. other_entry->next_handle - hfact->handle_base;
  445. if (adjusted_other_next_handle < adjusted_next_handle)
  446. {
  447. // The other entry is unassigned and has a smaller handle value
  448. // than the indexed entry. Thus, the other entry should be moved
  449. // from the secondary list to the primary list, and the indexed
  450. // entry should be placed on the secondary list.
  451. other_entry->next_entry->prev_entry = other_entry->prev_entry;
  452. other_entry->prev_entry->next_entry = other_entry->next_entry;
  453. other_entry->next_entry = &hfact->entry_list[LD_PRIMARY];
  454. other_entry->prev_entry = hfact->entry_list[LD_PRIMARY].prev_entry;
  455. hfact->entry_list[LD_PRIMARY].prev_entry->next_entry = other_entry;
  456. hfact->entry_list[LD_PRIMARY].prev_entry = other_entry;
  457. list = LD_SECONDARY;
  458. }
  459. else
  460. {
  461. // The other entry is unassigned and has a larger handle value
  462. // than the indexed entry. Thus, the indexed entry should be
  463. // placed on the secondary list.
  464. list = LD_PRIMARY;
  465. }
  466. }
  467. else
  468. {
  469. // The other entry is assigned. Thus, the indexed entry should be
  470. // placed on the secondary list. Also, since the two entries were
  471. // both assigned, they formed a pair. Since we are releasing one of
  472. // them, the pair count drops by one.
  473. list = LD_SECONDARY;
  474. hfact->pair_count--;
  475. }
  476. // Remove the entry from the assigned list and place it on the
  477. // appropriate list.
  478. entry->next_entry->prev_entry = entry->prev_entry;
  479. entry->prev_entry->next_entry = entry->next_entry;
  480. entry->next_entry = &hfact->entry_list[list];
  481. entry->prev_entry = hfact->entry_list[list].prev_entry;
  482. hfact->entry_list[list].prev_entry->next_entry = entry;
  483. hfact->entry_list[list].prev_entry = entry;
  484. // Invalidate the handle. The order of the operations is important to
  485. // correct multi-threaded operation.
  486. seq_entry = entry;
  487. seq_entry->handle = entry->next_handle; // first invalidate handle
  488. seq_entry->reference = 0; // then clear reference
  489. // The population has decreased by one.
  490. hfact->population--;
  491. // This release operation decreases the hysteresis debt.
  492. if (hfact->hysteresis_debt > 0)
  493. {
  494. hfact->hysteresis_debt--;
  495. }
  496. // To contract the table, there must be no pairs, because otherwise two
  497. // assigned handles would yield the same entry index and thereby conflict.
  498. // Furthermore, the table size must be greater than 2, because much of the
  499. // handle factory code assumes that the table is at least of size 2. In
  500. // addition to these strict requirements, hysteresis is employed both to
  501. // keep the mean assignment and release times constant and to minimize the
  502. // allocation chatter of rapidly expanding and contracting the table. Only
  503. // if the hysteresis debt is zero will the table be contracted.
  504. if (hfact->pair_count == 0 && table_size > 2 &&
  505. hfact->hysteresis_debt == 0)
  506. {
  507. contract_HF_table(hfact);
  508. // Note that we ignore the return code. If the contraction is
  509. // unsuccessful, we just continue as usual. There is no real harm in
  510. // not contracting the table, except that we consume more space than
  511. // necessary.
  512. }
  513. // return an indication of success to the client.
  514. return 0;
  515. }
  516. // This function suspends a handle, indicating that further attempts to
  517. // dereference the handle should result in a null pointer value rather than the
  518. // pointer value that was originally assigned to the handle, unless and until
  519. // reinstate_HF_handle() is called on the handle value. The handle factory
  520. // checks the validity of the handle and returns a corresponding status code.
  521. // If the handle is currently assigned and not suspended, then it is suspended,
  522. // and the function returns a value of 0. If the handle is not currently
  523. // assigned or has already been suspended, the function aborts and returns a
  524. // value of 1.
  525. //
  526. // In a multi-threaded environment, a single thread must take a lock prior to
  527. // calling this function, and this must be the same lock taken before calling
  528. // assign_HF_handle(), release_HF_handle(), and reinstate_HF_handle().
  529. //
  530. int
  531. suspend_HF_handle(
  532. HandleFactory *hfact,
  533. HFHandle handle)
  534. {
  535. int table_size;
  536. HFEntry *entries;
  537. int entry_index;
  538. HFEntry *entry;
  539. table_size = hfact->table_size[hfact->varset];
  540. entries = hfact->entries[hfact->varset];
  541. // Compute the index of the entry by taking the handle value modulo the
  542. // table size. Since the table size is a power of two, we can simply
  543. // subtract one to produce a mask and then conjoin the mask with the
  544. // handle value.
  545. entry_index = handle & table_size - 1;
  546. entry = &entries[entry_index];
  547. if (entry->handle != handle || entry->handle == entry->next_handle)
  548. {
  549. // Either the indexed entry does not refer to the provided handle, or
  550. // the entry is unassigned. In either case, abort and return an error
  551. // code to the client.
  552. return 1;
  553. }
  554. // Suspend the handle.
  555. entry->handle += HANDLE_RANGE_STEP;
  556. // This suspension operation decreases the hysteresis debt.
  557. if (hfact->hysteresis_debt > 0)
  558. {
  559. hfact->hysteresis_debt--;
  560. }
  561. // return an indication of success to the client.
  562. return 0;
  563. }
  564. // This function reinstates a suspended handle, indicating that further attempts
  565. // to dereference the handle should result in the pointer value that was
  566. // originally assigned to the handle, rather than the null pointer value to
  567. // which a suspended handle dereferences. The handle factory checks the
  568. // validity of the handle and returns a corresponding status code. If the handle
  569. // is currently assigned and suspended, then it is reinstated, and the function
  570. // returns a value of 0. If the handle is not currently assigned or is not
  571. // suspended, the function aborts and returns a value of 1.
  572. //
  573. // In a multi-threaded environment, a single thread must take a lock prior to
  574. // calling this function, and this must be the same lock taken before calling
  575. // assign_HF_handle(), release_HF_handle(), and suspend_HF_handle().
  576. //
  577. int
  578. reinstate_HF_handle(
  579. HandleFactory *hfact,
  580. HFHandle handle)
  581. {
  582. int table_size;
  583. HFEntry *entries;
  584. int entry_index;
  585. HFEntry *entry;
  586. table_size = hfact->table_size[hfact->varset];
  587. entries = hfact->entries[hfact->varset];
  588. // Compute the index of the entry by taking the handle value modulo the
  589. // table size. Since the table size is a power of two, we can simply
  590. // subtract one to produce a mask and then conjoin the mask with the
  591. // handle value.
  592. entry_index = handle & table_size - 1;
  593. entry = &entries[entry_index];
  594. if (entry->handle != handle + HANDLE_RANGE_STEP ||
  595. entry->handle == entry->next_handle)
  596. {
  597. // Either the indexed entry does not refer to the provided handle's
  598. // suspension value, or the entry is unassigned. In either case, abort
  599. // and return an error code to the client.
  600. return 1;
  601. }
  602. // Reinstate the handle.
  603. entry->handle -= HANDLE_RANGE_STEP;
  604. // This reinstatement operation decreases the hysteresis debt.
  605. if (hfact->hysteresis_debt > 0)
  606. {
  607. hfact->hysteresis_debt--;
  608. }
  609. // return an indication of success to the client.
  610. return 0;
  611. }
  612. // This function validates a handle and returns either the associated pointer
  613. // (if the handle is valid) or a null pointer value (if the handle is invalid).
  614. // If the handle has not been released but a null value is returned, then the
  615. // handle has been revoked by the handle factory. This is expected to be a
  616. // highly unusual occurrence; however, since it can happen, any program that
  617. // employs the handle factory must have some auxiliary mechanism for retrieving
  618. // the desired pointer information. Once the pointer is retrieved through this
  619. // (presumably expensive) auxiliary means, a new handle can be reassigned to
  620. // the pointer by another call to assign_HF_handle().
  621. //
  622. // Even in a multi-threaded environment, it is not necessary to take a lock
  623. // prior to calling this function. Careful sequencing of read and write
  624. // operations inside the handle factory code obviates the need to explicitly
  625. // lock the data structure for dereferencing handles.
  626. //
  627. void *
  628. dereference_HF_handle(
  629. HandleFactory *hfact,
  630. HFHandle handle)
  631. {
  632. HFHandle entry_handle;
  633. void *reference;
  634. int entry_index;
  635. volatile HFEntry *entry; // volatile to ensure sequencing
  636. LONG sync;
  637. int varset;
  638. int loopcount = 0;
  639. // This loop spins until one of the sync variables passes the interlocked
  640. // increment with a non-negative value, indicating that the corresponding
  641. // data values are valid. There is a very short sequence of instructions
  642. // in the expand and contract routines that modifies the values of the
  643. // entries and table_size variables and also frees memory, and these
  644. // modifications are bracketed by massive interlocked changes to the
  645. // associated sync variables. The loop should rarely be entered, since
  646. // the modification in the other routines is so short. The loop should
  647. // almost never be execute more than once, because this would require two
  648. // invokations of expand or contract during this short function.
  649. //
  650. // Start with the default variable set.
  651. // If we read hfact->varset at the same instant that another thread is
  652. // writing it, we should get either the old value or the new value, either
  653. // of which will work fine in the following code. We should never get a
  654. // garbage value, but just to be safe, we clear all bits other than the
  655. // LSB, to ensure that the value we use is valid.
  656. varset = hfact->varset & 1;
  657. // Indicate intention to access table_size and entries.
  658. sync = InterlockedIncrement(&hfact->sync[varset]);
  659. loopcount = 0;
  660. while (sync < 0)
  661. {
  662. // We incremented the sync variable after the expand or contract
  663. // routine massively decremented it, so we can not be sure that we
  664. // have access to the table_size and entries variables. Thus, we
  665. // indicate that we are no longer interested in accessing these
  666. // variables.
  667. InterlockedDecrement(&hfact->sync[varset]);
  668. // Since we didn't get access to the table_size and entries variables,
  669. // we try accessing the other set.
  670. varset = 1 - varset;
  671. sync = InterlockedIncrement(&hfact->sync[varset]);
  672. loopcount++;
  673. }
  674. if (loopcount > 2) {
  675. OutputDebugString(TEXT("Loopcount in deref was > 2 - how bizzare!\n"));
  676. DEBUGBREAK();
  677. }
  678. // We incremented the sync variable before the expand or contract routine
  679. // massively decremented it, so we have access to the table_size and
  680. // entries variables.
  681. //
  682. // Compute the index of the entry by taking the handle value modulo the
  683. // table size. Since the table size is a power of two, we can simply
  684. // subtract one to produce a mask and then conjoin the mask with the
  685. // handle value.
  686. entry_index = handle & hfact->table_size[varset] - 1;
  687. entry = &hfact->entries[varset][entry_index];
  688. // Get local copies of the reference pointer and handle value. The order
  689. // of the operations is important to correct multi-threaded operation.
  690. reference = entry->reference; // first get reference
  691. entry_handle = entry->handle; // then get handle to check validity
  692. // Indicate that we're done with table_size and entries
  693. InterlockedDecrement(&hfact->sync[varset]);
  694. if (entry_handle == handle)
  695. {
  696. // The stored handle matches the provided handle, so the latter is
  697. // valid. We thus return the reference pointer.
  698. return reference;
  699. }
  700. else
  701. {
  702. // The stored handle does not match the provided handle, so the latter
  703. // is invalid. We thus return a null pointer.
  704. return 0;
  705. }
  706. }
  707. #ifdef _TEST_HANDFACT
  708. // This is a test routine that simply verifies the internal valididy of the
  709. // handle factory's data structures. By defining the constant _TEST_HANDFACT,
  710. // this routine will be compiled and available to the client code. It can be
  711. // called at any time, unless running in a multi-threaded environment, in which
  712. // case the caller must first take the same lock used for assign_HF_handle()
  713. // and release_HF_handle. If the routine returns any value other than zero,
  714. // then the internal lists of records are in an inconsistent state.
  715. //
  716. int
  717. verify_HF_lists(
  718. HandleFactory *hfact)
  719. {
  720. int table_size;
  721. HFEntry *entries;
  722. int entry_count[3];
  723. int list;
  724. HFEntry *entry;
  725. table_size = hfact->table_size[hfact->varset];
  726. entries = hfact->entries[hfact->varset];
  727. for (list = 0; list < 3; list++)
  728. {
  729. entry_count[list] = 0;
  730. entry = &hfact->entry_list[list];
  731. do
  732. {
  733. entry_count[list]++;
  734. if (entry->next_entry->prev_entry != entry)
  735. {
  736. return 1;
  737. }
  738. entry = entry->next_entry;
  739. } while (entry != &hfact->entry_list[list]);
  740. entry_count[list]--;
  741. }
  742. if (entry_count[2] != hfact->population)
  743. {
  744. return 2;
  745. }
  746. if (entry_count[0] + entry_count[2] - 2 * hfact->pair_count !=
  747. entry_count[1])
  748. {
  749. return 3;
  750. }
  751. if (entry_count[0] + entry_count[1] + entry_count[2] != table_size)
  752. {
  753. return 4;
  754. }
  755. return 0;
  756. }
  757. #endif /* _TEST_HANDFACT */
  758. // This function doubles the size of the table in which the handles and pointers
  759. // are stored. It is called by assign_HF_handle() when there is insufficient
  760. // space in the table to assign the newly requested handle. If the expansion
  761. // is successful, the function returns a value of 0. If the expansion fails
  762. // (due, for example, to an inability to allocate memory), the function returns
  763. // a value of 1.
  764. //
  765. int expand_HF_table(
  766. HandleFactory *hfact)
  767. {
  768. int table_size;
  769. HFEntry *entries;
  770. int double_size;
  771. HFEntry *new_entries;
  772. HFEntry *old_entries;
  773. HFEntry *old_entry;
  774. HFEntry *low_entry;
  775. HFEntry *high_entry;
  776. HFEntry *assigned_entry;
  777. HFEntry *secondary_entry;
  778. HFEntry *other_entry;
  779. HFHandle handle;
  780. HFHandle next_handle;
  781. HFHandle other_handle;
  782. void *reference;
  783. int other_entry_index;
  784. int index;
  785. int varset;
  786. DWORD StartTick =0, EndTick = 0;
  787. table_size = hfact->table_size[hfact->varset];
  788. entries = hfact->entries[hfact->varset];
  789. // Expanded table is double the size of the old table.
  790. double_size = table_size * 2;
  791. // Allocate space for the expanded table.
  792. new_entries = NEW_HFEntry_array(double_size);
  793. if (new_entries == 0)
  794. {
  795. // Memory could not be allocated for the new array of entries.
  796. // Therefore, we return an indication of failure.
  797. return 1;
  798. }
  799. // Since we are doubling the table size, we will be treating one more bit
  800. // of each handle as a bit of the entry index. The value of this bit
  801. // determines the index of the entry in the new table. For each entry,
  802. // we have to determine the value of this bit and relocate the entry to
  803. // the indicated location.
  804. for (index = 0; index < table_size; index++)
  805. {
  806. old_entry = &entries[index];
  807. low_entry = &new_entries[index];
  808. high_entry = &new_entries[table_size + index];
  809. handle = old_entry->handle;
  810. next_handle = old_entry->next_handle;
  811. reference = old_entry->reference;
  812. // One of the two entries in the new table that correspond to the
  813. // indexed entry in the old table will have a next handle value equal
  814. // to the next handle value of the entry in the old table, and one will
  815. // have a handle value equal to the indexed entry's next handle plus
  816. // the old table size.
  817. other_handle = next_handle + table_size;
  818. if (other_handle == 0)
  819. {
  820. // The handle value has wrapped around back to zero; however, zero
  821. // is a reserved value, so we instead set the next handle to the
  822. // subsequent legal value, which is the new table size.
  823. other_handle = double_size;
  824. }
  825. if ((handle & table_size) == 0)
  826. {
  827. // The handle of the old entry has a zero in its next bit, so the
  828. // old entry will be located in the lower half of the new table.
  829. if ((next_handle & table_size) == 0)
  830. {
  831. // The next handle of the old entry has a zero in its next bit,
  832. // so this value will be the next handle for the lower entry
  833. // and the other next handle value will be the next handle
  834. // value for the higher entry. The high entry handle is set
  835. // equal to its next handle because it is unassigned.
  836. high_entry->handle = other_handle;
  837. high_entry->next_handle = other_handle;
  838. low_entry->next_handle = next_handle;
  839. }
  840. else
  841. {
  842. // The next handle of the old entry has a zero in its next bit,
  843. // so this value will be the next handle for the higher entry
  844. // and the other next handle value will be the next handle
  845. // value for the lower entry. The high entry handle is set
  846. // equal to its next handle because it is unassigned.
  847. high_entry->handle = next_handle;
  848. high_entry->next_handle = next_handle;
  849. low_entry->next_handle = other_handle;
  850. }
  851. // The high entry is unassigned, so set its reference to null.
  852. // Copy the information from the old entry to the low entry.
  853. // Remove the old entry from the assigned list, and replace it
  854. // with the low entry.
  855. high_entry->reference = 0;
  856. low_entry->handle = handle;
  857. low_entry->reference = reference;
  858. old_entry->next_entry->prev_entry = low_entry;
  859. old_entry->prev_entry->next_entry = low_entry;
  860. low_entry->next_entry = old_entry->next_entry;
  861. low_entry->prev_entry = old_entry->prev_entry;
  862. }
  863. else
  864. {
  865. // The handle of the old entry has a one in its next bit, so the
  866. // old entry will be located in the higher half of the new table.
  867. if ((next_handle & table_size) == 0)
  868. {
  869. // The next handle of the old entry has a zero in its next bit,
  870. // so this value will be the next handle for the lower entry
  871. // and the other next handle value will be the next handle
  872. // value for the higher entry. The low entry handle is set
  873. // equal to its next handle because it is unassigned.
  874. high_entry->next_handle = other_handle;
  875. low_entry->handle = next_handle;
  876. low_entry->next_handle = next_handle;
  877. }
  878. else
  879. {
  880. // The next handle of the old entry has a zero in its next bit,
  881. // so this value will be the next handle for the higher entry
  882. // and the other next handle value will be the next handle
  883. // value for the lower entry. The low entry handle is set
  884. // equal to its next handle because it is unassigned.
  885. high_entry->next_handle = next_handle;
  886. low_entry->handle = other_handle;
  887. low_entry->next_handle = other_handle;
  888. }
  889. // The low entry is unassigned, so set its reference to null.
  890. // Copy the information from the old entry to the high entry.
  891. // Remove the old entry from the assigned list, and replace it
  892. // with the high entry.
  893. low_entry->reference = 0;
  894. high_entry->handle = handle;
  895. high_entry->reference = reference;
  896. old_entry->next_entry->prev_entry = high_entry;
  897. old_entry->prev_entry->next_entry = high_entry;
  898. high_entry->next_entry = old_entry->next_entry;
  899. high_entry->prev_entry = old_entry->prev_entry;
  900. }
  901. }
  902. // All of the unassigned entries in the new table will be placed on the
  903. // secondary list. We loop through the assigned list and place the
  904. // unassigned entry corresponding each assigned entry onto the secondary
  905. // list. Doing the list assignment in this manner tends to approximately
  906. // sort the secondary list according to handle value, since the assigned
  907. // list is sorted according to assignment order, and this approximately
  908. // correlates to the handle value.
  909. assigned_entry = hfact->entry_list[LD_ASSIGNED].next_entry;
  910. secondary_entry = &hfact->entry_list[LD_SECONDARY];
  911. while (assigned_entry != &hfact->entry_list[LD_ASSIGNED])
  912. {
  913. other_entry_index =
  914. assigned_entry->handle + table_size & double_size - 1;
  915. other_entry = &new_entries[other_entry_index];
  916. secondary_entry->next_entry = other_entry;
  917. other_entry->prev_entry = secondary_entry;
  918. secondary_entry = other_entry;
  919. assigned_entry = assigned_entry->next_entry;
  920. }
  921. // Wrap up lists by connecting in tails.
  922. secondary_entry->next_entry = &hfact->entry_list[LD_SECONDARY];
  923. hfact->entry_list[LD_SECONDARY].prev_entry = secondary_entry;
  924. // This expansion increases the hysteresis debt by the cost of one set of
  925. // allocation and deallocation operations plus the cost of splitting each
  926. // entry into two entries.
  927. hfact->hysteresis_debt += ALLOCATION_COST + table_size;
  928. // Save a pointer to the old entry table so that it can be deallocated.
  929. old_entries = entries;
  930. // Note that we have not modified the handle, next_handle, or reference
  931. // fields of any entries in the old table. Therefore, any calls to the
  932. // dereference_HF_handle() routine that may have been made by other threads
  933. // during the above operations would have been performed successfully.
  934. // We are now about to increase the table size and update the entries
  935. // variable to point to the new table. We do this by first updating the
  936. // alternate table_size and entries variables and then updating the standard
  937. // ones. That way, there will always be one set that is correct, so that
  938. // dereferences can proceed relatively unimpeded.
  939. //
  940. // Our local varset is initialized to the non-default set.
  941. varset = 1 - hfact->varset;
  942. // Indicate that the non-default table_size and entries are becoming
  943. // inaccessible.
  944. InterlockedExchangeAdd(&hfact->sync[varset], -SYNC_SUBTRAHEND);
  945. // Wait until no dereferences to the non-default variables are in progress.
  946. StartTick = GetTickCount();
  947. while (hfact->sync[varset] > -SYNC_SUBTRAHEND)
  948. {
  949. // no-op or sleep
  950. if ((GetTickCount() - StartTick) > 300000000) {
  951. OutputDebugString(TEXT("Expand 1\n"));
  952. DEBUGBREAK();
  953. }
  954. }
  955. // Update non-default table_size and entries to new table.
  956. hfact->entries[varset] = new_entries;
  957. hfact->table_size[varset] = double_size;
  958. // Indicate that non-default table_size and entries are usable again.
  959. InterlockedExchangeAdd(&hfact->sync[varset], SYNC_SUBTRAHEND);
  960. // Make non-default table_size and entries the default set.
  961. hfact->varset = varset;
  962. // Update our local varset so it again indicates the non-default set.
  963. varset = 1 - varset;
  964. // Indicate that the non-default table_size and entries are becoming
  965. // inaccessible.
  966. InterlockedExchangeAdd(&hfact->sync[varset], -SYNC_SUBTRAHEND);
  967. // Wait until no dereferences to the non-default variables are in progress.
  968. while (hfact->sync[varset] > -SYNC_SUBTRAHEND)
  969. {
  970. if ((GetTickCount() - StartTick) > 300000000) {
  971. OutputDebugString(TEXT("Expand 2\n"));
  972. DEBUGBREAK();
  973. }
  974. // no-op or sleep
  975. }
  976. // Update non-default table_size and entries to new table.
  977. hfact->entries[varset] = new_entries;
  978. hfact->table_size[varset] = double_size;
  979. // Indicate that non-default table_size and entries are usable again.
  980. InterlockedExchangeAdd(&hfact->sync[varset], SYNC_SUBTRAHEND);
  981. // Deallocate the old table.
  982. free(old_entries);
  983. // Since the new table was created by expanding a half-size table, the pair
  984. // count must be zero.
  985. hfact->pair_count = 0;
  986. // return an indication of success.
  987. return 0;
  988. }
  989. // This function halves the size of the table in which the handles and pointers
  990. // are stored. In order to reduce the amount of space consumed by the handle
  991. // factory, this function is called called by release_HF_handle() and
  992. // revoke_ancient_HF_handles() when they determine that the table can and should
  993. // be contracted. The table can be contracted when pair_count == 0 and
  994. // table_size > 2. However, the table may not be contracted then, because
  995. // hysteresis is employed both to keep the mean assignment and release times
  996. // constant and to minimize the allocation chatter of rapidly expanding and
  997. // contracting the table. If the contraction is successful, the function
  998. // returns a value of 0. If the contraction fails, the function returns a
  999. // value of 1.
  1000. //
  1001. int contract_HF_table(
  1002. HandleFactory *hfact)
  1003. {
  1004. int table_size;
  1005. HFEntry *entries;
  1006. HFEntry *new_entries;
  1007. HFEntry *old_entries;
  1008. int *list;
  1009. int half_size;
  1010. int quarter_size;
  1011. int index;
  1012. HFEntry *high_entry1;
  1013. HFEntry *high_entry0;
  1014. HFEntry *low_entry1;
  1015. HFEntry *low_entry0;
  1016. HFEntry *new_entry1;
  1017. HFEntry *new_entry0;
  1018. HFHandle adjusted_high_next_handle1;
  1019. HFHandle adjusted_low_next_handle1;
  1020. HFHandle next_handle1;
  1021. HFHandle adjusted_high_next_handle0;
  1022. HFHandle adjusted_low_next_handle0;
  1023. HFHandle next_handle0;
  1024. HFHandle adjusted_new_handle0;
  1025. HFHandle adjusted_new_handle1;
  1026. HFEntry *entry;
  1027. HFEntry *primary_entry;
  1028. HFEntry *secondary_entry;
  1029. int varset;
  1030. DWORD StartTick = 0;
  1031. table_size = hfact->table_size[hfact->varset];
  1032. entries = hfact->entries[hfact->varset];
  1033. // Contracted table is half the size of the old table.
  1034. half_size = table_size / 2;
  1035. quarter_size = half_size / 2;
  1036. // Allocate space for the contracted table.
  1037. new_entries = NEW_HFEntry_array(half_size);
  1038. if (new_entries == 0)
  1039. {
  1040. // Memory could not be allocated for the new array of entries, so we
  1041. // are ironically prevented from reducing the amount of memory that
  1042. // the handle factory is consuming. Therefore, we return an indication
  1043. // of failure.
  1044. return 1;
  1045. }
  1046. // Allocate space for auxiliary array of list indicators
  1047. list = NEW_int_array(half_size);
  1048. if (list == 0)
  1049. {
  1050. // Memory could not be allocated for the auxiliary array, so again we
  1051. // are ironically prevented from reducing the amount of memory that
  1052. // the handle factory is consuming. Therefore, we return an indication
  1053. // of failure. First, however, we must free the memory allocated for
  1054. // the new array of entries above.
  1055. free(new_entries);
  1056. return 1;
  1057. }
  1058. // Since we are halving the size of the table, it might seem reasonable to
  1059. // loop through each index of the new table and merge the two corresponding
  1060. // entries from the old table. This is in fact what the following routine
  1061. // does; however, it does it by looping through only half of the new indices
  1062. // and processing two merges for each index. It does this so that it can
  1063. // then examine the two new entries to determine on which list to place each
  1064. // of them.
  1065. for (index = 0; index < quarter_size; index++)
  1066. {
  1067. // We're looking at four entries at once. First we merge high_entry1
  1068. // and low_entry1, and then we independently merge high_entry0 and
  1069. // low_entry0. After the two merges, we examine the results jointly.
  1070. high_entry1 = &entries[half_size + quarter_size + index];
  1071. high_entry0 = &entries[half_size + index];
  1072. low_entry1 = &entries[quarter_size + index];
  1073. low_entry0 = &entries[index];
  1074. new_entry1 = &new_entries[quarter_size + index];
  1075. new_entry0 = &new_entries[index];
  1076. // When merging two entries, the next handle value for the combined
  1077. // entry is equal to the larger next handle value of the two, minus
  1078. // the new table size. However, the determination of which is larger
  1079. // must be made with respect to their logical acyclic values rather
  1080. // than their actual cyclic values, so we subtract from each the value
  1081. // of handle_base, modulo the size of the handle space. The modulo is
  1082. // implicit.
  1083. adjusted_high_next_handle1 =
  1084. high_entry1->next_handle - hfact->handle_base;
  1085. adjusted_low_next_handle1 =
  1086. low_entry1->next_handle - hfact->handle_base;
  1087. next_handle1 = __max(adjusted_high_next_handle1,
  1088. adjusted_low_next_handle1) + hfact->handle_base - half_size;
  1089. // Since handle 1 is -- by definition -- in either the second or fourth
  1090. // quarter of the table, there is no need to check for the reserved
  1091. // value of zero.
  1092. if (high_entry1->handle != high_entry1->next_handle)
  1093. {
  1094. // The high entry is assigned, so we copy its handle value and
  1095. // reference pointer. Also, we remove it from the assigned list
  1096. // and replace it with the new entry.
  1097. new_entry1->handle = high_entry1->handle;
  1098. new_entry1->reference = high_entry1->reference;
  1099. high_entry1->next_entry->prev_entry = new_entry1;
  1100. high_entry1->prev_entry->next_entry = new_entry1;
  1101. new_entry1->next_entry = high_entry1->next_entry;
  1102. new_entry1->prev_entry = high_entry1->prev_entry;
  1103. }
  1104. else if (low_entry1->handle != low_entry1->next_handle)
  1105. {
  1106. // The low entry is assigned, so we copy its handle value and
  1107. // reference pointer. Also, we remove it from the assigned list
  1108. // and replace it with the new entry.
  1109. new_entry1->handle = low_entry1->handle;
  1110. new_entry1->reference = low_entry1->reference;
  1111. low_entry1->next_entry->prev_entry = new_entry1;
  1112. low_entry1->prev_entry->next_entry = new_entry1;
  1113. new_entry1->next_entry = low_entry1->next_entry;
  1114. new_entry1->prev_entry = low_entry1->prev_entry;
  1115. }
  1116. else
  1117. {
  1118. // Neither entry is assigned, so we indicate an unassigned condition
  1119. // in the new entry.
  1120. new_entry1->handle = next_handle1;
  1121. new_entry1->reference = 0;
  1122. if (adjusted_high_next_handle1 < adjusted_low_next_handle1)
  1123. {
  1124. // The high entry next handle has a lesser value than the low
  1125. // entry next handle, so the high entry must be on the primary
  1126. // list. We remove it from the primary list and replace it
  1127. // with the new entry.
  1128. high_entry1->next_entry->prev_entry = new_entry1;
  1129. high_entry1->prev_entry->next_entry = new_entry1;
  1130. new_entry1->next_entry = high_entry1->next_entry;
  1131. new_entry1->prev_entry = high_entry1->prev_entry;
  1132. }
  1133. else
  1134. {
  1135. // The low entry next handle has a lesser value than the high
  1136. // entry next handle, so the low entry must be on the primary
  1137. // list. We remove it from the primary list and replace it
  1138. // with the new entry.
  1139. low_entry1->next_entry->prev_entry = new_entry1;
  1140. low_entry1->prev_entry->next_entry = new_entry1;
  1141. new_entry1->next_entry = low_entry1->next_entry;
  1142. new_entry1->prev_entry = low_entry1->prev_entry;
  1143. }
  1144. }
  1145. // Set the next handle for the new entry.
  1146. new_entry1->next_handle = next_handle1;
  1147. // When merging two entries, the next handle value for the combined
  1148. // entry is equal to the larger next handle value of the two, minus
  1149. // the new table size. However, the determination of which is larger
  1150. // must be made with respect to their logical acyclic values rather
  1151. // than their actual cyclic values, so we subtract from each the value
  1152. // of handle_base, modulo the size of the handle space. The modulo is
  1153. // implicit.
  1154. adjusted_high_next_handle0 =
  1155. high_entry0->next_handle - hfact->handle_base;
  1156. adjusted_low_next_handle0 =
  1157. low_entry0->next_handle - hfact->handle_base;
  1158. next_handle0 = __max(adjusted_high_next_handle0,
  1159. adjusted_low_next_handle0) + hfact->handle_base - half_size;
  1160. if (next_handle0 == 0)
  1161. {
  1162. // The handle value has wrapped around back to zero; however, zero
  1163. // is a reserved value, so we instead set the next handle to the
  1164. // subsequent legal value, which is the new table size.
  1165. next_handle0 = half_size;
  1166. }
  1167. if (high_entry0->handle != high_entry0->next_handle)
  1168. {
  1169. // The high entry is assigned, so we copy its handle value and
  1170. // reference pointer. Also, we remove it from the assigned list
  1171. // and replace it with the new entry.
  1172. new_entry0->handle = high_entry0->handle;
  1173. new_entry0->reference = high_entry0->reference;
  1174. high_entry0->next_entry->prev_entry = new_entry0;
  1175. high_entry0->prev_entry->next_entry = new_entry0;
  1176. new_entry0->next_entry = high_entry0->next_entry;
  1177. new_entry0->prev_entry = high_entry0->prev_entry;
  1178. }
  1179. else if (low_entry0->handle != low_entry0->next_handle)
  1180. {
  1181. // The low entry is assigned, so we copy its handle value and
  1182. // reference pointer. Also, we remove it from the assigned list
  1183. // and replace it with the new entry.
  1184. new_entry0->handle = low_entry0->handle;
  1185. new_entry0->reference = low_entry0->reference;
  1186. low_entry0->next_entry->prev_entry = new_entry0;
  1187. low_entry0->prev_entry->next_entry = new_entry0;
  1188. new_entry0->next_entry = low_entry0->next_entry;
  1189. new_entry0->prev_entry = low_entry0->prev_entry;
  1190. }
  1191. else
  1192. {
  1193. // Neither entry is assigned, so we indicate an unassigned condition
  1194. // in the new entry.
  1195. new_entry0->handle = next_handle0;
  1196. new_entry0->reference = 0;
  1197. if (adjusted_high_next_handle0 < adjusted_low_next_handle0)
  1198. {
  1199. // The high entry next handle has a lesser value than the low
  1200. // entry next handle, so the high entry must be on the primary
  1201. // list. We remove it from the primary list and replace it
  1202. // with the new entry.
  1203. high_entry0->next_entry->prev_entry = new_entry0;
  1204. high_entry0->prev_entry->next_entry = new_entry0;
  1205. new_entry0->next_entry = high_entry0->next_entry;
  1206. new_entry0->prev_entry = high_entry0->prev_entry;
  1207. }
  1208. else
  1209. {
  1210. // The low entry next handle has a lesser value than the high
  1211. // entry next handle, so the low entry must be on the primary
  1212. // list. We remove it from the primary list and replace it
  1213. // with the new entry.
  1214. low_entry0->next_entry->prev_entry = new_entry0;
  1215. low_entry0->prev_entry->next_entry = new_entry0;
  1216. new_entry0->next_entry = low_entry0->next_entry;
  1217. new_entry0->prev_entry = low_entry0->prev_entry;
  1218. }
  1219. }
  1220. // Set the next handle for the new entry.
  1221. new_entry0->next_handle = next_handle0;
  1222. // Now that we have merged high_entry1 and low_entry1 into new_entry1,
  1223. // and independently merged high_entry0 and low_entry0 into new_entry0,
  1224. // we examine the two new entries to determine on which list to place
  1225. // each of them. Note that we do not actually manipulate the lists in
  1226. // this portion of the code; we merely make decisions and record these
  1227. // decisions for the future.
  1228. if (new_entry0->handle == new_entry0->next_handle &&
  1229. new_entry1->handle == new_entry1->next_handle)
  1230. {
  1231. // Both new_entry0 and new_entry1 are unassigned, so one of them
  1232. // belongs on the primary list and the other on the secondary list.
  1233. // Which goes on which is determined by a comparison of their handle
  1234. // values. We're being tricky with unsigned integer math here.
  1235. // Before comparing the two handles, we subtract from each the value
  1236. // of handle_base, modulo the size of the handle space (the modulo
  1237. // is implicit). This allows the effective comparison of their
  1238. // logical acyclic values rather than their actual cyclic values.
  1239. adjusted_new_handle0 = new_entry0->handle - hfact->handle_base;
  1240. adjusted_new_handle1 = new_entry1->handle - hfact->handle_base;
  1241. if (adjusted_new_handle0 < adjusted_new_handle1)
  1242. {
  1243. // The handle value for new_entry0 is lower, so new_entry0
  1244. // belongs on the primary list and new_entry1 on the secondary
  1245. // list. We indicate this decision in the list array.
  1246. list[index] = LD_PRIMARY;
  1247. list[quarter_size + index] = LD_SECONDARY;
  1248. }
  1249. else
  1250. {
  1251. // The handle value for new_entry1 is lower, so new_entry1
  1252. // belongs on the primary list and new_entry0 on the secondary
  1253. // list. We indicate this decision in the list array.
  1254. list[index] = LD_SECONDARY;
  1255. list[quarter_size + index] = LD_PRIMARY;
  1256. }
  1257. }
  1258. else
  1259. {
  1260. // Either new_entry0 or new_entry1 (or both) is assigned, and it is
  1261. // therefore already on the assigned list. If one of the entries
  1262. // is not assigned, it belongs on the secondary list. We indicate
  1263. // this decision in both places of the list array, which is safe to
  1264. // do since the assigned entry's list indicator will never be
  1265. // examined.
  1266. list[index] = LD_SECONDARY;
  1267. list[quarter_size + index] = LD_SECONDARY;
  1268. }
  1269. if (new_entry0->handle != new_entry0->next_handle &&
  1270. new_entry1->handle != new_entry1->next_handle)
  1271. {
  1272. // Both new_entry0 and new_entry1 are assigned, so they form a pair.
  1273. // We thus increment the pair count. Note that we never set the
  1274. // pair count to zero above, but this was not necessary since the
  1275. // table could not be contracted unless the pair count was zero.
  1276. hfact->pair_count++;
  1277. }
  1278. }
  1279. // At this point, the table has been completely contracted except for the
  1280. // reassembly of the unassigned lists. In the code above, any entries that
  1281. // had previously been on the secondary list were merged with assigned
  1282. // entries, so they are no longer relevant. Only those entries that had
  1283. // previously been (and are still) on the primary list will still be
  1284. // unassigned. We now loop through the primary list and place each list
  1285. // element on the appropriate list, as indicated by the list array. Doing
  1286. // the list assignment in these two steps preserves the general order of
  1287. // the entries, which has some value since they will tend to be partially
  1288. // sorted.
  1289. entry = hfact->entry_list[LD_PRIMARY].next_entry;
  1290. primary_entry = &hfact->entry_list[LD_PRIMARY];
  1291. secondary_entry = &hfact->entry_list[LD_SECONDARY];
  1292. while (entry != &hfact->entry_list[LD_PRIMARY])
  1293. {
  1294. if (list[entry->handle & half_size - 1] == LD_PRIMARY)
  1295. {
  1296. // The list array indicates the primary list, so place the entry
  1297. // onto the primary list.
  1298. primary_entry->next_entry = entry;
  1299. entry->prev_entry = primary_entry;
  1300. primary_entry = entry;
  1301. }
  1302. else
  1303. {
  1304. // The list array indicates the secondary list, so place the entry
  1305. // onto the secondary list.
  1306. secondary_entry->next_entry = entry;
  1307. entry->prev_entry = secondary_entry;
  1308. secondary_entry = entry;
  1309. }
  1310. entry = entry->next_entry;
  1311. }
  1312. // Wrap up lists by connecting in tails.
  1313. primary_entry->next_entry = &hfact->entry_list[LD_PRIMARY];
  1314. hfact->entry_list[LD_PRIMARY].prev_entry = primary_entry;
  1315. secondary_entry->next_entry = &hfact->entry_list[LD_SECONDARY];
  1316. hfact->entry_list[LD_SECONDARY].prev_entry = secondary_entry;
  1317. // This contraction increases the hysteresis debt by the cost of one set of
  1318. // allocation and deallocation operations plus the cost of merging each
  1319. // pair of entries into a single entry.
  1320. hfact->hysteresis_debt += ALLOCATION_COST + half_size;
  1321. // Save a pointer to the old entry table so that it can be deallocated.
  1322. old_entries = entries;
  1323. // Note that we have not modified the handle, next_handle, or reference
  1324. // fields of any entries in the old table. Therefore, any calls to the
  1325. // dereference_HF_handle() routine that may have been made by other threads
  1326. // during the above operations would have been performed successfully.
  1327. // We are now about to increase the table size and update the entries
  1328. // variable to point to the new table. We do this by first updating the
  1329. // alternate table_size and entries variables and then updating the standard
  1330. // ones. That way, there will always be one set that is correct, so that
  1331. // dereferences can proceed relatively unimpeded.
  1332. //
  1333. // Our local varset is initialized to the non-default set.
  1334. varset = 1 - hfact->varset;
  1335. // Indicate that the non-default table_size and entries are becoming
  1336. // inaccessible.
  1337. InterlockedExchangeAdd(&hfact->sync[varset], -SYNC_SUBTRAHEND);
  1338. // Wait until no dereferences to the non-default variables are in progress.
  1339. StartTick = GetTickCount();
  1340. while (hfact->sync[varset] > -SYNC_SUBTRAHEND)
  1341. {
  1342. if ((GetTickCount() - StartTick) > 300000000) {
  1343. OutputDebugString(TEXT("Contract 1\n"));
  1344. DEBUGBREAK();
  1345. }
  1346. // no-op or sleep
  1347. }
  1348. // Update non-default table_size and entries to new table.
  1349. hfact->table_size[varset] = half_size;
  1350. hfact->entries[varset] = new_entries;
  1351. // Indicate that non-default table_size and entries are usable again.
  1352. InterlockedExchangeAdd(&hfact->sync[varset], SYNC_SUBTRAHEND);
  1353. // Make non-default table_size and entries the default set.
  1354. hfact->varset = varset;
  1355. // Update our local varset so it again indicates the non-default set.
  1356. varset = 1 - varset;
  1357. // Indicate that the non-default table_size and entries are becoming
  1358. // inaccessible.
  1359. InterlockedExchangeAdd(&hfact->sync[varset], -SYNC_SUBTRAHEND);
  1360. // Wait until no dereferences to the non-default variables are in progress.
  1361. while (hfact->sync[varset] > -SYNC_SUBTRAHEND)
  1362. {
  1363. // no-op or sleep
  1364. if ((GetTickCount() - StartTick) > 300000000) {
  1365. OutputDebugString(TEXT("Contract 2\n"));
  1366. DEBUGBREAK();
  1367. }
  1368. }
  1369. // Update non-default table_size and entries to new table.
  1370. hfact->table_size[varset] = half_size;
  1371. hfact->entries[varset] = new_entries;
  1372. // Indicate that non-default table_size and entries are usable again.
  1373. InterlockedExchangeAdd(&hfact->sync[varset], SYNC_SUBTRAHEND);
  1374. // Deallocate the old table and the auxiliary list indicator array.
  1375. free(old_entries);
  1376. free(list);
  1377. // return an indication of success.
  1378. return 0;
  1379. }
  1380. // This function revokes handles that are between handle_base and handle_base
  1381. // + 2 * HANDLE_RANGE_STEP - 1, inclusive. It then increments the value of
  1382. // handle_base by HANDLE_RANGE_STEP. Suspended handles will be revoked one
  1383. // revokation pass later than non-suspended handles.
  1384. //
  1385. void revoke_ancient_HF_handles(
  1386. HandleFactory *hfact)
  1387. {
  1388. int table_size;
  1389. HFEntry *entries;
  1390. HFHandle new_handle_base;
  1391. int half_size;
  1392. int index;
  1393. HFEntry *high_entry;
  1394. HFEntry *low_entry;
  1395. HFHandle adjusted_high_handle;
  1396. HFHandle adjusted_low_handle;
  1397. HFHandle adjusted_high_next_handle;
  1398. HFHandle adjusted_low_next_handle;
  1399. HFHandle handle;
  1400. volatile HFEntry *seq_entry; // volatile to ensure sequencing
  1401. table_size = hfact->table_size[hfact->varset];
  1402. entries = hfact->entries[hfact->varset];
  1403. // Compute new handle base.
  1404. new_handle_base = hfact->handle_base + HANDLE_RANGE_STEP;
  1405. // It might seem reasonable to loop through each index of the table and
  1406. // determine whether to revoke the handle of each entry. This is in fact
  1407. // what the following routine does; however, it does it by looping through
  1408. // only half of the indices and examining two entries for each index. It
  1409. // does this so that it can compare the two entries to determine on which
  1410. // list to place each of them.
  1411. half_size = table_size / 2;
  1412. for (index = 0; index < half_size; index++)
  1413. {
  1414. // We're looking at two entries at once.
  1415. high_entry = &entries[half_size + index];
  1416. low_entry = &entries[index];
  1417. // We're being tricky with unsigned integer math here. Before making
  1418. // comparisons on either handle, we subtract from it the value of
  1419. // handle_base, modulo the size of the handle space (the modulo is
  1420. // implicit). This allows the effective comparison of its logical
  1421. // acyclic value rather than its actual cyclic value.
  1422. adjusted_high_handle = high_entry->handle - hfact->handle_base;
  1423. adjusted_low_handle = low_entry->handle - hfact->handle_base;
  1424. if (adjusted_high_handle < 2 * HANDLE_RANGE_STEP ||
  1425. adjusted_low_handle < 2 * HANDLE_RANGE_STEP)
  1426. {
  1427. // At least one of the handles is less than twice HANDLE_RANGE_STEP
  1428. // more than the current handle base, so it will need to be updated.
  1429. // For the vast majority of cases, this test is expected to fail,
  1430. // and so all of the following work can be skipped.
  1431. if (high_entry->handle != high_entry->next_handle &&
  1432. low_entry->handle != low_entry->next_handle)
  1433. {
  1434. // Both of the entries are assigned, so, since at least one of
  1435. // them will be revoked, we will be losing one pair.
  1436. hfact->pair_count--;
  1437. }
  1438. if (high_entry->handle == high_entry->next_handle ||
  1439. adjusted_high_handle < 2 * HANDLE_RANGE_STEP)
  1440. {
  1441. // Either the high entry is unassigned or in need of revokation
  1442. // (after which it will be unassigned), so we remove it from
  1443. // whatever list it is on. We do this because all unassigned
  1444. // entries will be added to the appropriate list below.
  1445. high_entry->next_entry->prev_entry = high_entry->prev_entry;
  1446. high_entry->prev_entry->next_entry = high_entry->next_entry;
  1447. // Zeroing these pointers is unnecessary, but it will help to
  1448. // catch any mistakes made further down.
  1449. high_entry->next_entry = 0;
  1450. high_entry->prev_entry = 0;
  1451. }
  1452. if (adjusted_high_handle < 2 * HANDLE_RANGE_STEP)
  1453. {
  1454. // The high handle needs to be updated.
  1455. if (high_entry->handle != high_entry->next_handle)
  1456. {
  1457. // The high handle is assigned, so this updating will
  1458. // revoke the handle. Thus, we decrement the population.
  1459. hfact->population--;
  1460. }
  1461. // Compute the handle value as the maximum of (1) the next
  1462. // handle and (2) the new handle base plus the entry index.
  1463. // We're being tricky with unsigned integer math here. The
  1464. // maximum involves partial decomposition of the sums, from
  1465. // which we then subtract the value of handle_base, modulo the
  1466. // size of the handle space (the modulo is implicit). Thus,
  1467. // the maximum is taken with respect to the logical acyclic
  1468. // values rather than the actual cyclic values.
  1469. adjusted_high_next_handle =
  1470. high_entry->next_handle - hfact->handle_base;
  1471. handle = __max(adjusted_high_next_handle,
  1472. HANDLE_RANGE_STEP + half_size + index) + hfact->handle_base;
  1473. // Since the high handle is -- by definition -- in the upper
  1474. // half of the table, there is no need to check for the reserved
  1475. // value of zero.
  1476. // Update the handle value. Since this updating will invalidate
  1477. // the handle if it is currently assigned, the order of the
  1478. // operations is important to correct multi-threaded operation.
  1479. seq_entry = high_entry;
  1480. seq_entry->next_handle = handle;
  1481. seq_entry->handle = handle; // first invalidate handle
  1482. seq_entry->reference = 0; // then clear reference
  1483. }
  1484. if (low_entry->handle == low_entry->next_handle ||
  1485. adjusted_low_handle < 2 * HANDLE_RANGE_STEP)
  1486. {
  1487. // Either the low entry is unassigned or in need of revokation
  1488. // (after which it will be unassigned), so we remove it from
  1489. // whatever list it is on. We do this because all unassigned
  1490. // entries will be added to the appropriate list below.
  1491. low_entry->next_entry->prev_entry = low_entry->prev_entry;
  1492. low_entry->prev_entry->next_entry = low_entry->next_entry;
  1493. // Zeroing these pointers is unnecessary, but it will help to
  1494. // catch any mistakes made further down.
  1495. low_entry->next_entry = 0;
  1496. low_entry->prev_entry = 0;
  1497. }
  1498. if (adjusted_low_handle < 2 * HANDLE_RANGE_STEP)
  1499. {
  1500. // The low handle needs to be updated.
  1501. if (low_entry->handle != low_entry->next_handle)
  1502. {
  1503. // The low handle is assigned, so this updating will
  1504. // revoke the handle. Thus, we decrement the population.
  1505. hfact->population--;
  1506. }
  1507. // Compute the handle value as the maximum of (1) the next
  1508. // handle and (2) the new handle base plus the entry index.
  1509. // We're being tricky with unsigned integer math here. The
  1510. // maximum involves partial decomposition of the sums, from
  1511. // which we then subtract the value of handle_base, modulo the
  1512. // size of the handle space (the modulo is implicit). Thus,
  1513. // the maximum is taken with respect to the logical acyclic
  1514. // values rather than the actual cyclic values.
  1515. adjusted_low_next_handle =
  1516. low_entry->next_handle - hfact->handle_base;
  1517. handle = __max(adjusted_low_next_handle,
  1518. HANDLE_RANGE_STEP + index) + hfact->handle_base;
  1519. if (handle == 0)
  1520. {
  1521. // The handle value has wrapped around back to zero;
  1522. // however, zero is a reserved value, so we instead set the
  1523. // handle to the subsequent legal value, which is the table
  1524. // size.
  1525. handle = table_size;
  1526. }
  1527. // Update the handle value. Since this updating will invalidate
  1528. // the handle if it is currently assigned, the order of the
  1529. // operations is important to correct multi-threaded operation.
  1530. seq_entry = low_entry;
  1531. seq_entry->next_handle = handle;
  1532. seq_entry->handle = handle; // first invalidate handle
  1533. seq_entry->reference = 0; // then clear reference
  1534. }
  1535. if (high_entry->handle != high_entry->next_handle)
  1536. {
  1537. // The high entry is still assigned, so the low entry belongs
  1538. // on the secondary list.
  1539. low_entry->next_entry = &hfact->entry_list[LD_SECONDARY];
  1540. low_entry->prev_entry =
  1541. hfact->entry_list[LD_SECONDARY].prev_entry;
  1542. hfact->entry_list[LD_SECONDARY].prev_entry->next_entry =
  1543. low_entry;
  1544. hfact->entry_list[LD_SECONDARY].prev_entry = low_entry;
  1545. }
  1546. else if (low_entry->handle != low_entry->next_handle)
  1547. {
  1548. // The low entry is still assigned, so the high entry belongs
  1549. // on the secondary list.
  1550. high_entry->next_entry = &hfact->entry_list[LD_SECONDARY];
  1551. high_entry->prev_entry =
  1552. hfact->entry_list[LD_SECONDARY].prev_entry;
  1553. hfact->entry_list[LD_SECONDARY].prev_entry->next_entry =
  1554. high_entry;
  1555. hfact->entry_list[LD_SECONDARY].prev_entry = high_entry;
  1556. }
  1557. else
  1558. {
  1559. // Neither entry is still assigned, so one entry belongs on the
  1560. // primary list and one on the secondary list. Which goes on
  1561. // which is determined by a comparison of their handle values.
  1562. // We're being tricky with unsigned integer math here. Before
  1563. // comparing the two handles, we subtract from each the value
  1564. // of handle_base, modulo the size of the handle space (the
  1565. // modulo is implicit). This allows the effective comparison
  1566. // of their logical acyclic values rather than their actual
  1567. // cyclic values.
  1568. adjusted_high_next_handle =
  1569. high_entry->next_handle - new_handle_base;
  1570. adjusted_low_next_handle =
  1571. low_entry->next_handle - new_handle_base;
  1572. if (adjusted_low_next_handle < adjusted_high_next_handle)
  1573. {
  1574. // The handle value for the low entry is smaller, so it
  1575. // belongs on the primary list and the high entry on the
  1576. // secondary list.
  1577. high_entry->next_entry = &hfact->entry_list[LD_SECONDARY];
  1578. high_entry->prev_entry =
  1579. hfact->entry_list[LD_SECONDARY].prev_entry;
  1580. hfact->entry_list[LD_SECONDARY].prev_entry->next_entry =
  1581. high_entry;
  1582. hfact->entry_list[LD_SECONDARY].prev_entry = high_entry;
  1583. low_entry->next_entry = &hfact->entry_list[LD_PRIMARY];
  1584. low_entry->prev_entry =
  1585. hfact->entry_list[LD_PRIMARY].prev_entry;
  1586. hfact->entry_list[LD_PRIMARY].prev_entry->next_entry =
  1587. low_entry;
  1588. hfact->entry_list[LD_PRIMARY].prev_entry = low_entry;
  1589. }
  1590. else
  1591. {
  1592. // The handle value for the high entry is smaller, so it
  1593. // belongs on the primary list and the low entry on the
  1594. // secondary list.
  1595. high_entry->next_entry = &hfact->entry_list[LD_PRIMARY];
  1596. high_entry->prev_entry =
  1597. hfact->entry_list[LD_PRIMARY].prev_entry;
  1598. hfact->entry_list[LD_PRIMARY].prev_entry->next_entry =
  1599. high_entry;
  1600. hfact->entry_list[LD_PRIMARY].prev_entry = high_entry;
  1601. low_entry->next_entry = &hfact->entry_list[LD_SECONDARY];
  1602. low_entry->prev_entry =
  1603. hfact->entry_list[LD_SECONDARY].prev_entry;
  1604. hfact->entry_list[LD_SECONDARY].prev_entry->next_entry =
  1605. low_entry;
  1606. hfact->entry_list[LD_SECONDARY].prev_entry = low_entry;
  1607. }
  1608. }
  1609. }
  1610. }
  1611. // Update the handle base with the new handle base.
  1612. hfact->handle_base = new_handle_base;
  1613. // To contract the table, there must be no pairs, because otherwise two
  1614. // assigned handles would yield the same entry index and thereby conflict.
  1615. // Furthermore, the table size must be greater than 2, because much of the
  1616. // handle factory code assumes that the table is at least of size 2. In
  1617. // addition to these strict requirements, hysteresis is employed both to
  1618. // keep the mean assignment and release times constant and to minimize the
  1619. // allocation chatter of rapidly expanding and contracting the table. Only
  1620. // if the hysteresis debt is zero will the table be contracted.
  1621. if (hfact->pair_count == 0 && table_size > 2 &&
  1622. hfact->hysteresis_debt == 0)
  1623. {
  1624. contract_HF_table(hfact);
  1625. // Note that we ignore the return code. If the contraction is
  1626. // unsuccessful, we just continue as usual. There is no real harm in
  1627. // not contracting the table, except that we consume more space than
  1628. // necessary.
  1629. }
  1630. }