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