handles.h 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /* Copyright (c) 2016, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file handles.h
  5. * \brief Macros for C weak-handle implementation.
  6. *
  7. * A 'handle' is a pointer to an object that is allowed to go away while
  8. * the handle stays alive. When you dereference the handle, you might get
  9. * the object, or you might get "NULL".
  10. *
  11. * Use this pattern when an object has a single obvious lifespan, so you don't
  12. * want to use reference counting, but when other objects might need to refer
  13. * to the first object without caring about its lifetime.
  14. *
  15. * To enable a type to have handles, add a HANDLE_ENTRY() field in its
  16. * definition, as in:
  17. *
  18. * struct walrus {
  19. * HANDLE_ENTRY(wlr, walrus);
  20. * // ...
  21. * };
  22. *
  23. * And invoke HANDLE_DECL(wlr, walrus, [static]) to declare the handle
  24. * manipulation functions (typically in a header):
  25. *
  26. * // opaque handle to walrus.
  27. * typedef struct wlr_handle_t wlr_handle_t;
  28. *
  29. * // make a new handle
  30. * struct wlr_handle_t *wlr_handle_new(struct walrus *);
  31. *
  32. * // release a handle
  33. * void wlr_handle_free(wlr_handle_t *);
  34. *
  35. * // return the pointed-to walrus, or NULL.
  36. * struct walrus *wlr_handle_get(wlr_handle_t *).
  37. *
  38. * // call this function when you're about to free the walrus;
  39. * // it invalidates all handles. (IF YOU DON'T, YOU WILL HAVE
  40. * // DANGLING REFERENCES)
  41. * void wlr_handles_clear(struct walrus *);
  42. *
  43. * Finally, use HANDLE_IMPL() to define the above functions in some
  44. * appropriate C file: HANDLE_IMPL(wlr, walrus, [static])
  45. *
  46. **/
  47. #ifndef TOR_HANDLE_H
  48. #define TOR_HANDLE_H
  49. #include "orconfig.h"
  50. #include "tor_queue.h"
  51. #include "util.h"
  52. #define HANDLE_ENTRY(name, structname) \
  53. struct name ## _handle_head_t *handle_head
  54. #define HANDLE_DECL(name, structname, linkage) \
  55. typedef struct name ## _handle_t name ## _handle_t; \
  56. linkage name ## _handle_t *name ## _handle_new(struct structname *object); \
  57. linkage void name ## _handle_free(name ## _handle_t *); \
  58. linkage struct structname *name ## _handle_get(name ## _handle_t *); \
  59. linkage void name ## _handles_clear(struct structname *object);
  60. /*
  61. * Implementation notes: there are lots of possible implementations here. We
  62. * could keep a linked list of handles, each with a backpointer to the object,
  63. * and set all of their backpointers to NULL when the object is freed. Or we
  64. * could have the clear function invalidate the object, but not actually let
  65. * the object get freed until the all the handles went away. We could even
  66. * have a hash-table mapping unique identifiers to objects, and have each
  67. * handle be a copy of the unique identifier. (We'll want to build that last
  68. * one eventually if we want cross-process handles.)
  69. *
  70. * But instead we're opting for a single independent 'head' that knows how
  71. * many handles there are, and where the object is (or isn't). This makes
  72. * all of our functions O(1), and most as fast as a single pointer access.
  73. *
  74. * The handles themselves are opaque structures holding a pointer to the head.
  75. * We could instead have each foo_handle_t* be identical to foo_handle_head_t
  76. * *, and save some allocations ... but doing so would make handle leaks
  77. * harder to debug. As it stands, every handle leak is a memory leak, and
  78. * existing memory debugging tools should help with those. We can revisit
  79. * this decision if handles are too slow.
  80. */
  81. #define HANDLE_IMPL(name, structname, linkage) \
  82. /* The 'head' object for a handle-accessible type. This object */ \
  83. /* persists for as long as the object, or any handles, exist. */ \
  84. typedef struct name ## _handle_head_t { \
  85. struct structname *object; /* pointed-to object, or NULL */ \
  86. unsigned int references; /* number of existing handles */ \
  87. } name ## _handle_head_t; \
  88. \
  89. struct name ## _handle_t { \
  90. struct name ## _handle_head_t *head; /* reference to the 'head'. */ \
  91. }; \
  92. \
  93. linkage struct name ## _handle_t * \
  94. name ## _handle_new(struct structname *object) \
  95. { \
  96. tor_assert(object); \
  97. name ## _handle_head_t *head = object->handle_head; \
  98. if (PREDICT_UNLIKELY(head == NULL)) { \
  99. head = object->handle_head = tor_malloc_zero(sizeof(*head)); \
  100. head->object = object; \
  101. } \
  102. name ## _handle_t *new_ref = tor_malloc_zero(sizeof(*new_ref)); \
  103. new_ref->head = head; \
  104. ++head->references; \
  105. return new_ref; \
  106. } \
  107. \
  108. linkage void \
  109. name ## _handle_free(struct name ## _handle_t *ref) \
  110. { \
  111. if (! ref) return; \
  112. name ## _handle_head_t *head = ref->head; \
  113. tor_assert(head); \
  114. --head->references; \
  115. tor_free(ref); \
  116. if (head->object == NULL && head->references == 0) { \
  117. tor_free(head); \
  118. return; \
  119. } \
  120. } \
  121. \
  122. linkage struct structname * \
  123. name ## _handle_get(struct name ## _handle_t *ref) \
  124. { \
  125. tor_assert(ref); \
  126. name ## _handle_head_t *head = ref->head; \
  127. tor_assert(head); \
  128. return head->object; \
  129. } \
  130. \
  131. linkage void \
  132. name ## _handles_clear(struct structname *object) \
  133. { \
  134. tor_assert(object); \
  135. name ## _handle_head_t *head = object->handle_head; \
  136. if (! head) \
  137. return; \
  138. object->handle_head = NULL; \
  139. head->object = NULL; \
  140. if (head->references == 0) { \
  141. tor_free(head); \
  142. } \
  143. }
  144. #endif /* TOR_HANDLE_H */