take: add labels when CCAN_TAKE_DEBUG set, return in taken_any().
[ccan] / ccan / take / take.h
1 /* CC0 (Public domain) - see LICENSE file for details */
2 #ifndef CCAN_TAKE_H
3 #define CCAN_TAKE_H
4 #include "config.h"
5 #include <stdbool.h>
6 #include <ccan/str/str.h>
7
8 #ifdef CCAN_TAKE_DEBUG
9 #define TAKE_LABEL(p) __FILE__ ":" stringify(__LINE__) ":" stringify(p)
10 #else
11 #define TAKE_LABEL(p) NULL
12 #endif
13
14 /**
15  * take - record a pointer to be consumed by the function its handed to.
16  * @p: the pointer to mark, or NULL.
17  *
18  * This marks a pointer object to be freed by the called function,
19  * which is extremely useful for chaining functions.  It works on
20  * NULL, for pass-through error handling.
21  */
22 #define take(p) (take_typeof(p) take_((p), TAKE_LABEL(p)))
23
24 /**
25  * taken - check (and un-take) a pointer was passed with take()
26  * @p: the pointer to check.
27  *
28  * A function which accepts take() arguments uses this to see if it
29  * should own the pointer; it will be removed from the take list, so
30  * this only returns true once.
31  *
32  * Example:
33  *      // Silly routine to add 1
34  *      static int *add_one(const int *num)
35  *      {
36  *              int *ret;
37  *              if (taken(num))
38  *                      ret = (int *)num;
39  *              else
40  *                      ret = malloc(sizeof(int));
41  *              if (ret)
42  *                      *ret = (*num) + 1;
43  *              return ret;
44  *      }
45  */
46 bool taken(const void *p);
47
48 /**
49  * is_taken - check if a pointer was passed with take()
50  * @p: the pointer to check.
51  *
52  * This is like the above, but doesn't remove it from the taken list.
53  *
54  * Example:
55  *      // Silly routine to add 1: doesn't handle taken args!
56  *      static int *add_one_notake(const int *num)
57  *      {
58  *              int *ret = malloc(sizeof(int));
59  *              assert(!is_taken(num));
60  *              if (ret)
61  *                      *ret = (*num) + 1;
62  *              return ret;
63  *      }
64  */
65 bool is_taken(const void *p);
66
67 /**
68  * taken_any - are there any taken pointers?
69  *
70  * Mainly useful for debugging take() leaks.  With CCAN_TAKE_DEBUG, returns
71  * the label where the pointer was passed to take(), otherwise returns
72  * a static char buffer with the pointer value in it.  NULL if none are taken.
73  *
74  * Example:
75  *      static void cleanup(void)
76  *      {
77  *              assert(!taken_any());
78  *      }
79  */
80 const char *taken_any(void);
81
82 /**
83  * take_cleanup - remove all taken pointers from list.
84  *
85  * This is useful in atexit() handlers for valgrind-style leak detection.
86  *
87  * Example:
88  *      static void cleanup2(void)
89  *      {
90  *              take_cleanup();
91  *      }
92  */
93 void take_cleanup(void);
94
95 /**
96  * take_allocfail - set function to call if we can't reallocated taken array.
97  * @fn: the function.
98  *
99  * If this is not set, then if the array reallocation fails, the
100  * pointer won't be marked taken().  If @fn returns, it is expected to
101  * free the pointer; we return NULL from take() and the function handles
102  * it like any allocation failure.
103  *
104  * Example:
105  *      static void free_on_fail(const void *p)
106  *      {
107  *              free((void *)p);
108  *      }
109  *
110  *      static void init(void)
111  *      {
112  *              take_allocfail(free_on_fail);
113  *      }
114  */
115 void take_allocfail(void (*fn)(const void *p));
116
117 /* Private functions */
118 #if HAVE_TYPEOF
119 #define take_typeof(ptr) (__typeof__(ptr))
120 #else
121 #define take_typeof(ptr)
122 #endif
123
124 void *take_(const void *p, const char *label);
125 #endif /* CCAN_TAKE_H */