tor  0.4.0.0-alpha-dev
handles.h
Go to the documentation of this file.
1 /* Copyright (c) 2016-2018, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
3 
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, linkage) \
61  typedef struct name ## _handle_t name ## _handle_t; \
62  linkage name ## _handle_t *name ## _handle_new(struct structname *object); \
63  linkage void name ## _handle_free_(name ## _handle_t *); \
64  linkage struct structname *name ## _handle_get(name ## _handle_t *); \
65  linkage void name ## _handles_clear(struct structname *object);
66 
67 /*
68  * Implementation notes: there are lots of possible implementations here. We
69  * could keep a linked list of handles, each with a backpointer to the object,
70  * and set all of their backpointers to NULL when the object is freed. Or we
71  * could have the clear function invalidate the object, but not actually let
72  * the object get freed until the all the handles went away. We could even
73  * have a hash-table mapping unique identifiers to objects, and have each
74  * handle be a copy of the unique identifier. (We'll want to build that last
75  * one eventually if we want cross-process handles.)
76  *
77  * But instead we're opting for a single independent 'head' that knows how
78  * many handles there are, and where the object is (or isn't). This makes
79  * all of our functions O(1), and most as fast as a single pointer access.
80  *
81  * The handles themselves are opaque structures holding a pointer to the head.
82  * We could instead have each foo_handle_t* be identical to foo_handle_head_t
83  * *, and save some allocations ... but doing so would make handle leaks
84  * harder to debug. As it stands, every handle leak is a memory leak, and
85  * existing memory debugging tools should help with those. We can revisit
86  * this decision if handles are too slow.
87  */
88 
89 #define HANDLE_IMPL(name, structname, linkage) \
90  /* The 'head' object for a handle-accessible type. This object */ \
91  /* persists for as long as the object, or any handles, exist. */ \
92  typedef struct name ## _handle_head_t { \
93  struct structname *object; /* pointed-to object, or NULL */ \
94  unsigned int references; /* number of existing handles */ \
95  } name ## _handle_head_t; \
96  \
97  struct name ## _handle_t { \
98  struct name ## _handle_head_t *head; /* reference to the 'head'. */ \
99  }; \
100  \
101  linkage struct name ## _handle_t * \
102  name ## _handle_new(struct structname *object) \
103  { \
104  tor_assert(object); \
105  name ## _handle_head_t *head = object->handle_head; \
106  if (PREDICT_UNLIKELY(head == NULL)) { \
107  head = object->handle_head = tor_malloc_zero(sizeof(*head)); \
108  head->object = object; \
109  } \
110  name ## _handle_t *new_ref = tor_malloc_zero(sizeof(*new_ref)); \
111  new_ref->head = head; \
112  ++head->references; \
113  return new_ref; \
114  } \
115  \
116  linkage void \
117  name ## _handle_free_(struct name ## _handle_t *ref) \
118  { \
119  if (! ref) return; \
120  name ## _handle_head_t *head = ref->head; \
121  tor_assert(head); \
122  --head->references; \
123  tor_free(ref); \
124  if (head->object == NULL && head->references == 0) { \
125  tor_free(head); \
126  return; \
127  } \
128  } \
129  \
130  linkage struct structname * \
131  name ## _handle_get(struct name ## _handle_t *ref) \
132  { \
133  tor_assert(ref); \
134  name ## _handle_head_t *head = ref->head; \
135  tor_assert(head); \
136  return head->object; \
137  } \
138  \
139  linkage void \
140  name ## _handles_clear(struct structname *object) \
141  { \
142  tor_assert(object); \
143  name ## _handle_head_t *head = object->handle_head; \
144  if (! head) \
145  return; \
146  object->handle_head = NULL; \
147  head->object = NULL; \
148  if (head->references == 0) { \
149  tor_free(head); \
150  } \
151  }
152 
153 #endif /* !defined(TOR_HANDLE_H) */
Headers for util_malloc.c.
Macros to manage assertions, fatal and non-fatal.