1 /*-
2  * Copyright 2016 Vsevolod Stakhov
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #ifndef REF_H_
17 #define REF_H_
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 
24 /**
25  * @file ref.h
26  * A set of macros to handle refcounts
27  */
28 
29 typedef void (*ref_dtor_cb_t)(void *data);
30 
31 typedef struct ref_entry_s {
32 	unsigned int refcount;
33 	ref_dtor_cb_t dtor;
34 } ref_entry_t;
35 
36 #define REF_INIT(obj, dtor_cb) do {								\
37 	if ((obj) != NULL) {											\
38 	(obj)->ref.refcount = 0;										\
39 	(obj)->ref.dtor = (ref_dtor_cb_t)(dtor_cb);						\
40 	}																\
41 } while (0)
42 
43 #define REF_INIT_RETAIN(obj, dtor_cb) do {							\
44 	if ((obj) != NULL) {											\
45 	(obj)->ref.refcount = 1;										\
46 	(obj)->ref.dtor = (ref_dtor_cb_t)(dtor_cb);						\
47 	}																\
48 } while (0)
49 
50 #ifdef HAVE_ATOMIC_BUILTINS
51 #define REF_RETAIN_ATOMIC(obj) do {										\
52 	if ((obj) != NULL) {											\
53     __atomic_add_fetch (&(obj)->ref.refcount, 1, __ATOMIC_RELEASE);	\
54 	}																\
55 } while (0)
56 
57 #define REF_RELEASE_ATOMIC(obj) do {										\
58 	if ((obj) != NULL) {											\
59 	unsigned int _rc_priv = __atomic_sub_fetch (&(obj)->ref.refcount, 1, __ATOMIC_ACQ_REL); \
60 	if (_rc_priv == 0 && (obj)->ref.dtor) {								\
61 		(obj)->ref.dtor (obj);										\
62 	}																\
63 	}																\
64 } while (0)
65 
66 #else
67 #define REF_RETAIN_ATOMIC REF_RETAIN
68 #define REF_RELEASE_ATOMIC REF_RELEASE_ATOMIC
69 #endif
70 
71 #define REF_RETAIN(obj) do {										\
72 	if ((obj) != NULL) {											\
73 	(obj)->ref.refcount ++;											\
74 	}																\
75 } while (0)
76 
77 #define REF_RELEASE(obj) do {										\
78 	if ((obj) != NULL) {											\
79 	if (--(obj)->ref.refcount == 0 && (obj)->ref.dtor) {			\
80 		(obj)->ref.dtor (obj);										\
81 	}																\
82 	}																\
83 } while (0)
84 
85 #endif /* REF_H_ */
86