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