tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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) */