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