1 | /* |
2 | * librd - Rapid Development C library |
3 | * |
4 | * Copyright (c) 2012, Magnus Edenhill |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions are met: |
9 | * |
10 | * 1. Redistributions of source code must retain the above copyright notice, |
11 | * this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright notice, |
13 | * this list of conditions and the following disclaimer in the documentation |
14 | * and/or other materials provided with the distribution. |
15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
26 | * POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
28 | |
29 | |
30 | #ifndef _RD_H_ |
31 | #define _RD_H_ |
32 | |
33 | #ifndef _MSC_VER |
34 | #ifndef _GNU_SOURCE |
35 | #define _GNU_SOURCE /* for strndup() */ |
36 | #endif |
37 | #define __need_IOV_MAX |
38 | #ifndef _POSIX_C_SOURCE |
39 | #define _POSIX_C_SOURCE 200809L /* for timespec on solaris */ |
40 | #endif |
41 | #endif |
42 | |
43 | #include <stdio.h> |
44 | #include <stdlib.h> |
45 | #include <string.h> |
46 | #include <errno.h> |
47 | #include <time.h> |
48 | #include <assert.h> |
49 | #include <limits.h> |
50 | |
51 | #include "tinycthread.h" |
52 | #include "rdsysqueue.h" |
53 | |
54 | #ifdef _MSC_VER |
55 | /* Visual Studio */ |
56 | #include "win32_config.h" |
57 | #else |
58 | /* POSIX / UNIX based systems */ |
59 | #include "../config.h" /* mklove output */ |
60 | #endif |
61 | |
62 | #ifdef _MSC_VER |
63 | /* Win32/Visual Studio */ |
64 | #include "rdwin32.h" |
65 | |
66 | #else |
67 | /* POSIX / UNIX based systems */ |
68 | #include "rdposix.h" |
69 | #endif |
70 | |
71 | #include "rdtypes.h" |
72 | |
73 | |
74 | /* Debug assert, only enabled with --enable-devel */ |
75 | #if ENABLE_DEVEL == 1 |
76 | #define rd_dassert(cond) rd_assert(cond) |
77 | #else |
78 | #define rd_dassert(cond) do {} while (0) |
79 | #endif |
80 | |
81 | |
82 | /** Assert if reached */ |
83 | #define RD_NOTREACHED() rd_assert(!*"/* NOTREACHED */ violated") |
84 | |
85 | |
86 | |
87 | /** |
88 | * Allocator wrappers. |
89 | * We serve under the premise that if a (small) memory |
90 | * allocation fails all hope is lost and the application |
91 | * will fail anyway, so no need to handle it handsomely. |
92 | */ |
93 | static RD_INLINE RD_UNUSED void *rd_calloc(size_t num, size_t sz) { |
94 | void *p = calloc(num, sz); |
95 | rd_assert(p); |
96 | return p; |
97 | } |
98 | |
99 | static RD_INLINE RD_UNUSED void *rd_malloc(size_t sz) { |
100 | void *p = malloc(sz); |
101 | rd_assert(p); |
102 | return p; |
103 | } |
104 | |
105 | static RD_INLINE RD_UNUSED void *rd_realloc(void *ptr, size_t sz) { |
106 | void *p = realloc(ptr, sz); |
107 | rd_assert(p); |
108 | return p; |
109 | } |
110 | |
111 | static RD_INLINE RD_UNUSED void rd_free(void *ptr) { |
112 | free(ptr); |
113 | } |
114 | |
115 | static RD_INLINE RD_UNUSED char *rd_strdup(const char *s) { |
116 | #ifndef _MSC_VER |
117 | char *n = strdup(s); |
118 | #else |
119 | char *n = _strdup(s); |
120 | #endif |
121 | rd_assert(n); |
122 | return n; |
123 | } |
124 | |
125 | static RD_INLINE RD_UNUSED char *rd_strndup(const char *s, size_t len) { |
126 | #if HAVE_STRNDUP |
127 | char *n = strndup(s, len); |
128 | rd_assert(n); |
129 | #else |
130 | char *n = malloc(len + 1); |
131 | rd_assert(n); |
132 | memcpy(n, s, len); |
133 | n[len] = '\0'; |
134 | #endif |
135 | return n; |
136 | } |
137 | |
138 | |
139 | |
140 | /* |
141 | * Portability |
142 | */ |
143 | |
144 | #ifdef strndupa |
145 | #define rd_strndupa(DESTPTR,PTR,LEN) (*(DESTPTR) = strndupa(PTR,LEN)) |
146 | #else |
147 | #define rd_strndupa(DESTPTR,PTR,LEN) do { \ |
148 | const char *_src = (PTR); \ |
149 | size_t _srclen = (LEN); \ |
150 | char *_dst = rd_alloca(_srclen + 1); \ |
151 | memcpy(_dst, _src, _srclen); \ |
152 | _dst[_srclen] = '\0'; \ |
153 | *(DESTPTR) = _dst; \ |
154 | } while (0) |
155 | #endif |
156 | |
157 | #ifdef strdupa |
158 | #define rd_strdupa(DESTPTR,PTR) (*(DESTPTR) = strdupa(PTR)) |
159 | #else |
160 | #define rd_strdupa(DESTPTR,PTR) do { \ |
161 | const char *_src1 = (PTR); \ |
162 | size_t _srclen1 = strlen(_src1); \ |
163 | rd_strndupa(DESTPTR, _src1, _srclen1); \ |
164 | } while (0) |
165 | #endif |
166 | |
167 | #ifndef IOV_MAX |
168 | #ifdef __APPLE__ |
169 | /* Some versions of MacOSX dont have IOV_MAX */ |
170 | #define IOV_MAX 1024 |
171 | #elif defined(_MSC_VER) || defined(__GNU__) |
172 | /* There is no IOV_MAX on MSVC or GNU but it is used internally in librdkafka */ |
173 | #define IOV_MAX 1024 |
174 | #else |
175 | #error "IOV_MAX not defined" |
176 | #endif |
177 | #endif |
178 | |
179 | |
180 | /* Round/align X upwards to STRIDE, which must be power of 2. */ |
181 | #define RD_ROUNDUP(X,STRIDE) (((X) + ((STRIDE) - 1)) & ~(STRIDE-1)) |
182 | |
183 | #define RD_ARRAY_SIZE(A) (sizeof((A)) / sizeof(*(A))) |
184 | #define RD_ARRAYSIZE(A) RD_ARRAY_SIZE(A) |
185 | #define RD_SIZEOF(TYPE,MEMBER) sizeof(((TYPE *)NULL)->MEMBER) |
186 | #define RD_OFFSETOF(TYPE,MEMBER) ((size_t) &(((TYPE *)NULL)->MEMBER)) |
187 | |
188 | /** |
189 | * Returns the 'I'th array element from static sized array 'A' |
190 | * or NULL if 'I' is out of range. |
191 | * var-args is an optional prefix to provide the correct return type. |
192 | */ |
193 | #define RD_ARRAY_ELEM(A,I,...) \ |
194 | ((unsigned int)(I) < RD_ARRAY_SIZE(A) ? __VA_ARGS__ (A)[(I)] : NULL) |
195 | |
196 | |
197 | #define RD_STRINGIFY(X) # X |
198 | |
199 | |
200 | |
201 | #define RD_MIN(a,b) ((a) < (b) ? (a) : (b)) |
202 | #define RD_MAX(a,b) ((a) > (b) ? (a) : (b)) |
203 | |
204 | |
205 | /** |
206 | * Cap an integer (of any type) to reside within the defined limit. |
207 | */ |
208 | #define RD_INT_CAP(val,low,hi) \ |
209 | ((val) < (low) ? low : ((val) > (hi) ? (hi) : (val))) |
210 | |
211 | |
212 | |
213 | /** |
214 | * Allocate 'size' bytes, copy 'src', return pointer to new memory. |
215 | * |
216 | * Use rd_free() to free the returned pointer. |
217 | */ |
218 | static RD_INLINE RD_UNUSED void *rd_memdup (const void *src, size_t size) { |
219 | void *dst = rd_malloc(size); |
220 | memcpy(dst, src, size); |
221 | return dst; |
222 | } |
223 | |
224 | /** |
225 | * @brief Memset &OBJ to 0, does automatic sizeof(OBJ). |
226 | */ |
227 | #define RD_MEMZERO(OBJ) memset(&(OBJ), 0, sizeof(OBJ)) |
228 | |
229 | |
230 | /** |
231 | * Generic refcnt interface |
232 | */ |
233 | |
234 | #if !HAVE_ATOMICS_32 |
235 | #define RD_REFCNT_USE_LOCKS 1 |
236 | #endif |
237 | |
238 | #ifdef RD_REFCNT_USE_LOCKS |
239 | typedef struct rd_refcnt_t { |
240 | mtx_t lock; |
241 | int v; |
242 | } rd_refcnt_t; |
243 | #else |
244 | typedef rd_atomic32_t rd_refcnt_t; |
245 | #endif |
246 | |
247 | #ifdef RD_REFCNT_USE_LOCKS |
248 | static RD_INLINE RD_UNUSED int rd_refcnt_init (rd_refcnt_t *R, int v) { |
249 | int r; |
250 | mtx_init(&R->lock, mtx_plain); |
251 | mtx_lock(&R->lock); |
252 | r = R->v = v; |
253 | mtx_unlock(&R->lock); |
254 | return r; |
255 | } |
256 | #else |
257 | #define rd_refcnt_init(R,v) rd_atomic32_init(R, v) |
258 | #endif |
259 | |
260 | #ifdef RD_REFCNT_USE_LOCKS |
261 | static RD_INLINE RD_UNUSED void rd_refcnt_destroy (rd_refcnt_t *R) { |
262 | mtx_lock(&R->lock); |
263 | rd_assert(R->v == 0); |
264 | mtx_unlock(&R->lock); |
265 | |
266 | mtx_destroy(&R->lock); |
267 | } |
268 | #else |
269 | #define rd_refcnt_destroy(R) do { } while (0) |
270 | #endif |
271 | |
272 | |
273 | #ifdef RD_REFCNT_USE_LOCKS |
274 | static RD_INLINE RD_UNUSED int rd_refcnt_set (rd_refcnt_t *R, int v) { |
275 | int r; |
276 | mtx_lock(&R->lock); |
277 | r = R->v = v; |
278 | mtx_unlock(&R->lock); |
279 | return r; |
280 | } |
281 | #else |
282 | #define rd_refcnt_set(R,v) rd_atomic32_set(R, v) |
283 | #endif |
284 | |
285 | |
286 | #ifdef RD_REFCNT_USE_LOCKS |
287 | static RD_INLINE RD_UNUSED int rd_refcnt_add0 (rd_refcnt_t *R) { |
288 | int r; |
289 | mtx_lock(&R->lock); |
290 | r = ++(R->v); |
291 | mtx_unlock(&R->lock); |
292 | return r; |
293 | } |
294 | #else |
295 | #define rd_refcnt_add0(R) rd_atomic32_add(R, 1) |
296 | #endif |
297 | |
298 | static RD_INLINE RD_UNUSED int rd_refcnt_sub0 (rd_refcnt_t *R) { |
299 | int r; |
300 | #ifdef RD_REFCNT_USE_LOCKS |
301 | mtx_lock(&R->lock); |
302 | r = --(R->v); |
303 | mtx_unlock(&R->lock); |
304 | #else |
305 | r = rd_atomic32_sub(R, 1); |
306 | #endif |
307 | if (r < 0) |
308 | rd_assert(!*"refcnt sub-zero" ); |
309 | return r; |
310 | } |
311 | |
312 | #ifdef RD_REFCNT_USE_LOCKS |
313 | static RD_INLINE RD_UNUSED int rd_refcnt_get (rd_refcnt_t *R) { |
314 | int r; |
315 | mtx_lock(&R->lock); |
316 | r = R->v; |
317 | mtx_unlock(&R->lock); |
318 | return r; |
319 | } |
320 | #else |
321 | #define rd_refcnt_get(R) rd_atomic32_get(R) |
322 | #endif |
323 | |
324 | /** |
325 | * A wrapper for decreasing refcount and calling a destroy function |
326 | * when refcnt reaches 0. |
327 | */ |
328 | #define rd_refcnt_destroywrapper(REFCNT,DESTROY_CALL) do { \ |
329 | if (rd_refcnt_sub(REFCNT) > 0) \ |
330 | break; \ |
331 | DESTROY_CALL; \ |
332 | } while (0) |
333 | |
334 | |
335 | #define rd_refcnt_destroywrapper2(REFCNT,WHAT,DESTROY_CALL) do { \ |
336 | if (rd_refcnt_sub2(REFCNT,WHAT) > 0) \ |
337 | break; \ |
338 | DESTROY_CALL; \ |
339 | } while (0) |
340 | |
341 | #if ENABLE_REFCNT_DEBUG |
342 | #define rd_refcnt_add(R) \ |
343 | ( \ |
344 | printf("REFCNT DEBUG: %-35s %d +1: %16p: %s:%d\n", \ |
345 | #R, rd_refcnt_get(R), (R), __FUNCTION__,__LINE__), \ |
346 | rd_refcnt_add0(R) \ |
347 | ) |
348 | |
349 | #define rd_refcnt_add2(R,WHAT) do { \ |
350 | printf("REFCNT DEBUG: %-35s %d +1: %16p: %16s: %s:%d\n", \ |
351 | #R, rd_refcnt_get(R), (R), WHAT, __FUNCTION__,__LINE__), \ |
352 | rd_refcnt_add0(R); \ |
353 | } while (0) |
354 | |
355 | |
356 | #define rd_refcnt_sub2(R,WHAT) ( \ |
357 | printf("REFCNT DEBUG: %-35s %d -1: %16p: %16s: %s:%d\n", \ |
358 | #R, rd_refcnt_get(R), (R), WHAT, __FUNCTION__,__LINE__), \ |
359 | rd_refcnt_sub0(R) ) |
360 | |
361 | #define rd_refcnt_sub(R) ( \ |
362 | printf("REFCNT DEBUG: %-35s %d -1: %16p: %s:%d\n", \ |
363 | #R, rd_refcnt_get(R), (R), __FUNCTION__,__LINE__), \ |
364 | rd_refcnt_sub0(R) ) |
365 | |
366 | #else |
367 | #define rd_refcnt_add(R) rd_refcnt_add0(R) |
368 | #define rd_refcnt_sub(R) rd_refcnt_sub0(R) |
369 | #endif |
370 | |
371 | |
372 | |
373 | #if !ENABLE_SHAREDPTR_DEBUG |
374 | |
375 | /** |
376 | * The non-debug version of shared_ptr is simply a reference counting interface |
377 | * without any additional costs and no indirections. |
378 | */ |
379 | |
380 | #define RD_SHARED_PTR_TYPE(STRUCT_NAME,WRAPPED_TYPE) WRAPPED_TYPE |
381 | |
382 | |
383 | #define rd_shared_ptr_get_src(FUNC,LINE,OBJ,REFCNT,SPTR_TYPE) \ |
384 | (rd_refcnt_add(REFCNT), (OBJ)) |
385 | #define rd_shared_ptr_get(OBJ,REFCNT,SPTR_TYPE) \ |
386 | (rd_refcnt_add(REFCNT), (OBJ)) |
387 | |
388 | #define rd_shared_ptr_obj(SPTR) (SPTR) |
389 | |
390 | #define rd_shared_ptr_put(SPTR,REF,DESTRUCTOR) \ |
391 | rd_refcnt_destroywrapper(REF,DESTRUCTOR) |
392 | |
393 | |
394 | #else |
395 | |
396 | #define RD_SHARED_PTR_TYPE(STRUCT_NAME, WRAPPED_TYPE) \ |
397 | struct STRUCT_NAME { \ |
398 | LIST_ENTRY(rd_shptr0_s) link; \ |
399 | WRAPPED_TYPE *obj; \ |
400 | rd_refcnt_t *ref; \ |
401 | const char *typename; \ |
402 | const char *func; \ |
403 | int line; \ |
404 | } |
405 | |
406 | |
407 | |
408 | /* Common backing struct compatible with RD_SHARED_PTR_TYPE() types */ |
409 | typedef RD_SHARED_PTR_TYPE(rd_shptr0_s, void) rd_shptr0_t; |
410 | |
411 | LIST_HEAD(rd_shptr0_head, rd_shptr0_s); |
412 | extern struct rd_shptr0_head rd_shared_ptr_debug_list; |
413 | extern mtx_t rd_shared_ptr_debug_mtx; |
414 | |
415 | static RD_INLINE RD_UNUSED RD_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) |
416 | rd_shptr0_t *rd_shared_ptr_get0 (const char *func, int line, |
417 | const char *typename, |
418 | rd_refcnt_t *ref, void *obj) { |
419 | rd_shptr0_t *sptr = rd_calloc(1, sizeof(*sptr)); |
420 | sptr->obj = obj; |
421 | sptr->ref = ref; |
422 | sptr->typename = typename; |
423 | sptr->func = func; |
424 | sptr->line = line; |
425 | |
426 | mtx_lock(&rd_shared_ptr_debug_mtx); |
427 | LIST_INSERT_HEAD(&rd_shared_ptr_debug_list, sptr, link); |
428 | mtx_unlock(&rd_shared_ptr_debug_mtx); |
429 | return sptr; |
430 | } |
431 | |
432 | #define rd_shared_ptr_get_src(FUNC,LINE,OBJ,REF,SPTR_TYPE) \ |
433 | (rd_refcnt_add(REF), \ |
434 | (SPTR_TYPE *)rd_shared_ptr_get0(FUNC,LINE, #SPTR_TYPE,REF,OBJ)) |
435 | #define rd_shared_ptr_get(OBJ,REF,SPTR_TYPE) \ |
436 | rd_shared_ptr_get_src(__FUNCTION__, __LINE__, OBJ, REF, SPTR_TYPE) |
437 | |
438 | |
439 | |
440 | #define rd_shared_ptr_obj(SPTR) (SPTR)->obj |
441 | |
442 | #define rd_shared_ptr_put(SPTR,REF,DESTRUCTOR) do { \ |
443 | if (rd_refcnt_sub(REF) == 0) \ |
444 | DESTRUCTOR; \ |
445 | mtx_lock(&rd_shared_ptr_debug_mtx); \ |
446 | LIST_REMOVE(SPTR, link); \ |
447 | mtx_unlock(&rd_shared_ptr_debug_mtx); \ |
448 | rd_free(SPTR); \ |
449 | } while (0) |
450 | |
451 | void rd_shared_ptrs_dump (void); |
452 | #endif |
453 | |
454 | |
455 | #define RD_IF_FREE(PTR,FUNC) do { if ((PTR)) FUNC(PTR); } while (0) |
456 | |
457 | |
458 | /** |
459 | * @brief Utility types to hold memory,size tuple. |
460 | */ |
461 | |
462 | typedef struct rd_chariov_s { |
463 | char *ptr; |
464 | size_t size; |
465 | } rd_chariov_t; |
466 | |
467 | #endif /* _RD_H_ */ |
468 | |