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

318 lines
15 KiB

  1. //#define WIN32_LEAN_AND_MEAN 1
  2. //#include <windows.h>
  3. /*
  4. * handfact.h
  5. *
  6. * author: John R. Douceur
  7. * date: 26 January 1998
  8. *
  9. * This header file defines structures, function prototypes, and macros for
  10. * the handle factory. The code is object-oriented C, transliterated from a
  11. * C++ implementation.
  12. *
  13. * The handle factory is a component that generates and validates handles. It
  14. * is intended to be used in a software module that provides client software
  15. * modules with means to refer to information structures contained within the
  16. * provider. While such a means could simply be a pointer, this would not
  17. * enable the deletion of the information structures without explicitly
  18. * notifying the clients of such deletion. Unlike pointers, the handles
  19. * generated by the handle factory can be examined (by the handle factory)
  20. * to determine their validity.
  21. *
  22. * Handles can be invalidated in one of two ways. The handle can be released
  23. * by calling the release_HF_handle() function, indicating to the handle
  24. * factory that the handle is no longer necessary and that future requests
  25. * to dereference this handle should be met with a null pointer. Alternately,
  26. * the handle can be revoked by the handle factory; this will happen unter two
  27. * circumstances. If a large number of handles (more than four billion) are
  28. * issued and subsequently released, it becomes necessary to reuse portions of
  29. * the handle space for future assignments; under these circumstances, very
  30. * old handles will be revoked well before this recycling occurs, to give the
  31. * holders of those handles ample opportunity to notice that their handles
  32. * have become invalid and to request new handles. The other situation in
  33. * which revokation can occur is if the amount of available memory becomes
  34. * too small to allocate additional space to expand the handle database; then,
  35. * if the assignment of a new handle is requested, the least-recently-assigned
  36. * handle will be revoked to make room for the new request.
  37. *
  38. * Use of the handle factory in a multi-threaded environment requires a lock.
  39. * This lock must be taken by a single thread for the execution of either
  40. * assign_HF_handle() or release_HF_handle(). Use of dereference_HF_handle()
  41. * does not require taking a lock, since synchronization is handled internally
  42. * through careful sequencing of read and write operations.
  43. *
  44. * Because this code is C, rather than C++, it is not possible to hide as
  45. * much of the implementation from the client code as one might wish.
  46. * Nonetheless, there is an attempt to isolate the client from some of the
  47. * implementation details through the use of macros. Below is described each
  48. * of the functions and macros necessary to use the handle factory.
  49. *
  50. */
  51. #ifndef _INC_HANDFACT
  52. #define _INC_HANDFACT
  53. #ifdef __cplusplus
  54. extern "C" {
  55. #endif
  56. /*
  57. * There are two basic structures employed: the HFEntry and the HandleFactory.
  58. * Ideally, these would be completely hidden from the client, but the size of
  59. * the HandleFactory structure structure needs to be known by the client for
  60. * allocation purposes, and this is most easily accomplished by declaring the
  61. * structure itself here in the header file, which in turn requires declaring
  62. * the HFEntry structure. It is strongly urged that the client not directly
  63. * refer to any of the fields of either of these structures. To support the
  64. * documentation of the accompanying rhizome.c file, these structures are
  65. * annotated with internal comments, but these can be ignored by the reader
  66. * who wishes only to understand how to write client code that makes use of
  67. * the handle factory.
  68. *
  69. * The handles generated by the handle factory are of type HFHandle. This is
  70. * typedefed to an unsigned int, but this fact can be ignored by the client,
  71. * since it is an implementation detail.
  72. *
  73. */
  74. //#include <stdlib.h>
  75. //#include <malloc.h>
  76. // HFHandle is the type of the handles generated by the handle factory.
  77. //
  78. typedef unsigned int HFHandle;
  79. struct _HFEntry;
  80. typedef struct _HFEntry HFEntry;
  81. struct _HFEntry
  82. {
  83. // This is the element in which each handle and its associated pointer are
  84. // stored. If handle == next_handle, the entry is not assigned, and it is
  85. // available for assignment to a pointer via the assign_HF_handle()
  86. // function. If handle != next_handle, then the entry is assigned to the
  87. // pointer in the reference field.
  88. //
  89. // Each entry is on one of three lists: the primary free list, the secondary
  90. // free list, or the assigned list. Each of these lists is maintained via
  91. // the next_entry and prev_entry pointers.
  92. HFHandle handle; // value of handle
  93. HFHandle next_handle; // next value given to handle when invalidated
  94. void *reference; // pointer to which handle refers
  95. HFEntry *next_entry; // pointer to next entry in list
  96. HFEntry *prev_entry; // pointer to previous entry in list
  97. };
  98. struct _HandleFactory;
  99. typedef struct _HandleFactory HandleFactory;
  100. struct _HandleFactory
  101. {
  102. // This structure contains private member variables for the handle factory.
  103. // The table_size and entries fields are marked volatile to insure that the
  104. // operations performed on them occur in the specified sequence. The handle
  105. // factory can operate in a multi-threaded environment without requiring
  106. // that a lock be taken before calling dereference_HF_handle(), and this is
  107. // accomplished by careful sequencing of the read and write operations on
  108. // these two variables.
  109. //
  110. // There are two sets of table_size and entries variables, which are used
  111. // to provide a synchronization mechanism in conjunction with the two
  112. // sync variables. The varset variable indicates which set of these three
  113. // variables is used by default. Most normal operations (assign, release,
  114. // suspend, reinstate) simply use the default set of table_size and entries.
  115. // However, the expand and contract routines update both sets, and the
  116. // dereference routine needs to examine the sets in a special way to ensure
  117. // that it does not conflict with a concurrent expansion or contraction.
  118. //
  119. // The dereference_HF_handle() routine increments one of the sync variables
  120. // to indicate an intention to refer to the corresponding table_size and
  121. // entries variables. The expand_HF_table() and contract_HF_table()
  122. // routines each massively decrement one of the sync variables to indicate
  123. // an intention to change the corresponding table_size and entries
  124. // variables. All changes to the sync variables are done through
  125. // interlocked operations.
  126. //
  127. // The table that holds the handles can only be contracted (shrunk in half)
  128. // when for each assigned handle in the lower half of the table, there is
  129. // no assigned handle in the corresponding upper half of the table. The
  130. // number of correspondences between the two table halves is given by
  131. // pair_count.
  132. volatile int table_size[2]; // size of table for storing entries
  133. HFEntry *volatile entries[2]; // pointer to tables of entries
  134. LONG sync[2]; // synchronization variable
  135. int varset; // variable set for default usage
  136. HFHandle handle_base; // rolling point of lowest handle value
  137. int population; // number of handles currently assigned
  138. int pair_count; // contractions can occur when pair_count == 0
  139. int hysteresis_debt; // must be zero before contraction
  140. HFEntry entry_list[3]; // array of all three entry lists
  141. };
  142. /*
  143. * The client interface to the handle factory is provided by seven functions
  144. * and one macro. It is expected that the provider will first instantiate a
  145. * handle factory, either in the static data segment, on the stack, or on the
  146. * heap. Then, the provider will assign handles to various pointers by
  147. * calling assign_HF_handle(), which it will distribute to its clients. When
  148. * the provider wishes to release these handles, it will do so by calling
  149. * release_HF_handle(). Each time a client presents a handle to the provider,
  150. * the provider can validate the handle and retrieve the associated pointer
  151. * by calling dereference_HF_handle(). A client can temporarily suspend a
  152. * handle by calling suspend_HF_handle(), after which it can either reinstate
  153. * the handle by calling reinstate_HF_handle() or release the handle by calling
  154. * release_HF_handle().
  155. *
  156. */
  157. // A handle factory may be allocated in the static data segment or on the stack
  158. // simply by declaring a variable of type HandleFactory. To allocate it on the
  159. // heap, the following macro returns a pointer to a new HandleFactory structure.
  160. // If this macro is used, a corresponding call to free() must be made to
  161. // deallocate the structure from the heap.
  162. //
  163. #define NEW_HandleFactory(_h) AllocMem(&(_h), sizeof(HandleFactory))
  164. #define FreeHandleFactory(_h) FreeMem(_h)
  165. // Since this is not C++, the HandleFactory structure is not self-constructing;
  166. // therefore, the following constructor code must be called on the HandleFactory
  167. // structure after it is allocated. If the construction is successful, the
  168. // function returns a value of 0. If the construction fails (due, for example,
  169. // to an inability to allocate memory), the function returns a value of 1.
  170. //
  171. int
  172. constructHandleFactory(
  173. HandleFactory *hfact);
  174. // Since this is not C++, the HandleFactory structure is not self-destructing;
  175. // therefore, the following destructor code must be called on the HandleFactory
  176. // structure before it is deallocated.
  177. //
  178. void
  179. destructHandleFactory(
  180. HandleFactory *hfact);
  181. // This function generates a new handle value, associates the handle value with
  182. // the provided reference pointer, and returns the handle value. Barring
  183. // highly unusual circumstances, this handle will remain valid until it is
  184. // explicitly released by a call to release_HF_handle(). However, there is no
  185. // guarantee that the handle will persist for an arbitrary duration; it may
  186. // become necessary for the handle factory to revoke the handle under some
  187. // circumstances, particularly when the handle becomes very old or when memory
  188. // becomes scarce.
  189. //
  190. // The assign_HF_handle() function will never return a handle value of zero.
  191. // Thus, the client program is free to use a zero handle value as an escape
  192. // indicator, if desired.
  193. //
  194. // In a multi-threaded environment, a single thread must take a lock prior to
  195. // calling this function, and this must be the same lock taken before calling
  196. // release_HF_handle(), suspend_HF_handle(), and reinstate_HF_handle().
  197. //
  198. HFHandle
  199. assign_HF_handle(
  200. HandleFactory *hfact,
  201. void *reference);
  202. // This function releases a handle, indicating that further attempts to
  203. // dereference the handle should result in a null pointer value rather than the
  204. // pointer value that was originally assigned to the handle. The handle factory
  205. // checks the validity of the handle and returns a corresponding status code.
  206. // If the handle is currently assigned, then it is released, and the function
  207. // returns a value of 0. If the handle is not currently assigned, the function
  208. // aborts and returns a value of 1.
  209. //
  210. // In a multi-threaded environment, a single thread must take a lock prior to
  211. // calling this function, and this must be the same lock taken before calling
  212. // assign_HF_handle(), suspend_HF_handle(), and reinstate_HF_handle().
  213. //
  214. int
  215. release_HF_handle(
  216. HandleFactory *hfact,
  217. HFHandle handle);
  218. // This function suspends a handle, indicating that further attempts to
  219. // dereference the handle should result in a null pointer value rather than the
  220. // pointer value that was originally assigned to the handle, unless and until
  221. // reinstate_HF_handle() is called on the handle value. The handle factory
  222. // checks the validity of the handle and returns a corresponding status code.
  223. // If the handle is currently assigned and not suspended, then it is suspended,
  224. // and the function returns a value of 0. If the handle is not currently
  225. // assigned or has already been suspended, the function aborts and returns a
  226. // value of 1.
  227. //
  228. // In a multi-threaded environment, a single thread must take a lock prior to
  229. // calling this function, and this must be the same lock taken before calling
  230. // assign_HF_handle(), release_HF_handle(), and reinstate_HF_handle().
  231. //
  232. int
  233. suspend_HF_handle(
  234. HandleFactory *hfact,
  235. HFHandle handle);
  236. // This function reinstates a suspended handle, indicating that further attempts
  237. // to dereference the handle should result in the pointer value that was
  238. // originally assigned to the handle, rather than the null pointer value to
  239. // which a suspended handle dereferences. The handle factory checks the
  240. // validity of the handle and returns a corresponding status code. If the handle
  241. // is currently assigned and suspended, then it is reinstated, and the function
  242. // returns a value of 0. If the handle is not currently assigned or is not
  243. // suspended, the function aborts and returns a value of 1.
  244. //
  245. // In a multi-threaded environment, a single thread must take a lock prior to
  246. // calling this function, and this must be the same lock taken before calling
  247. // assign_HF_handle(), release_HF_handle(), and suspend_HF_handle().
  248. //
  249. int
  250. reinstate_HF_handle(
  251. HandleFactory *hfact,
  252. HFHandle handle);
  253. // This function validates a handle and returns either the associated pointer
  254. // (if the handle is valid) or a null pointer value (if the handle is invalid).
  255. // If the handle has not been released or suspended but a null value is
  256. // returned, then the handle has been revoked by the handle factory. This is
  257. // expected to be a highly unusual occurrence; however, since it can happen, any
  258. // program that employs the handle factory must have some auxiliary mechanism
  259. // for retrieving the desired pointer information. Once the pointer is
  260. // retrieved through this (presumably expensive) auxiliary means, a new handle
  261. // can be reassigned to the pointer by another call to assign_HF_handle().
  262. //
  263. // Even in a multi-threaded environment, it is not necessary to take a lock
  264. // prior to calling this function. Careful sequencing of read and write
  265. // operations inside the handle factory code obviates the need to explicitly
  266. // lock the data structure for dereferencing handles.
  267. //
  268. void *
  269. dereference_HF_handle(
  270. HandleFactory *hfact,
  271. HFHandle handle);
  272. #ifdef _TEST_HANDFACT
  273. // This is a test routine that simply verifies the internal valididy of the
  274. // handle factory's data structures. By defining the constant _TEST_HANDFACT,
  275. // this routine will be compiled and available to the client code. It can be
  276. // called at any time, unless running in a multi-threaded environment, in which
  277. // case the caller must first take the same lock used for assign_HF_handle(),
  278. // release_HF_handle(), suspend_HF_handle(), and reinstate_HF_handle(). If the
  279. // routine returns any value other than zero, then the internal lists of records
  280. // are in an inconsistent state.
  281. //
  282. int
  283. verify_HF_lists(
  284. HandleFactory *hfact);
  285. #endif /* _TEST_HANDFACT */
  286. #ifdef __cplusplus
  287. }
  288. #endif
  289. #endif /* _INC_HANDFACT */