refobject.h 8.37 KB
Newer Older
1 2 3 4 5 6 7 8
/* Icecast
 *
 * This program is distributed under the GNU General Public License, version 2.
 * A copy of this license is included with this source.
 *
 * Copyright 2018,      Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
 */

9 10 11 12
/* This file contains the API for the refobject helper type.
 * The refobject helper type is a base type that allows building other types with safe reference counting.
 */

13 14 15
#ifndef __REFOBJECT_H__
#define __REFOBJECT_H__

16 17 18 19
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

20 21
#include <stdarg.h>

22 23 24 25 26
#include "common/thread/thread.h"

#include "icecasttypes.h"
#include "compat.h"

27 28 29 30 31 32 33 34 35 36 37 38 39
/* The following macros are defined. The definition depends on if the compiler
 * supports transparent unions. If supported full type checking is enabled.
 * If the compiler does not support transparent unions, we fall back to using
 * (void*) pointers.
 *
 * REFOBJECT_NULL
 *  Can be used to set an refobject to NULL.
 * REFOBJECT_IS_NULL(x)
 *  Can be used to check if the refobject x is NULL.
 *  Checking by doing (x == NULL) does not work with transparent unions
 *  as the operation is only defined for it's members.
 * REFOBJECT_TO_TYPE(type,x)
 *  This casts the refobject (x) to the type (type).
40 41 42 43 44 45 46 47 48
 * REFOBJECT_FROM_TYPE(x)
 *  Converts an object to a (refobject_t). This is the inverse of REFOBJECT_TO_TYPE().
 * REFOBJECT_GET_TYPENAME(x)
 *  Get the name of the type of the object.
 * REFOBJECT_IS_VALID(x,type)
 *  This returns true if x is not NULL and of type type.
 * REFOBJECT_GET_BASE(x)
 * REFOBJECT_GET_TYPE(x)
 *  Not to be used by the user.
49
 */
50 51
#ifdef HAVE_TYPE_ATTRIBUTE_TRANSPARENT_UNION
#define REFOBJECT_NULL          ((refobject_t)(refobject_base_t*)NULL)
52
#define REFOBJECT_GET_BASE(x)   (((refobject_t)(x)).refobject_base)
53 54 55 56
#define REFOBJECT_IS_NULL(x)    (((refobject_t)(x)).refobject_base == NULL)
#define REFOBJECT_TO_TYPE(x,y)  ((y)(((refobject_t)(x)).refobject_base))
#else
#define REFOBJECT_NULL          NULL
57
#define REFOBJECT_GET_BASE(x)   ((refobject_base_t)(x))
58 59 60 61
#define REFOBJECT_IS_NULL(x)    ((x) == NULL)
#define REFOBJECT_TO_TYPE(x,y)  ((y)(x))
#endif

62 63
#define REFOBJECT_FROM_TYPE(x)  ((refobject_t)(refobject_base_t*)(x))

64 65 66
#define REFOBJECT_GET_TYPE(x)       (REFOBJECT_GET_BASE((x)) == NULL ? NULL : REFOBJECT_GET_BASE((x))->type)
#define REFOBJECT_GET_TYPENAME(x)   (REFOBJECT_GET_TYPE((x)) == NULL ? NULL : REFOBJECT_GET_TYPE((x))->type_name)

67
#define REFOBJECT_IS_VALID(x,type)  (!REFOBJECT_IS_NULL((x)) && REFOBJECT_GET_TYPE((x)) == (refobject_type__ ## type))
68

69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
/* The following macros are used to define types.
 *
 * REFOBJECT_FORWARD_TYPE(type)
 *  Adds a forward decleration for the type. This is useful for non private types.
 * REFOBJECT_DEFINE_TYPE(type,extras...)
 *  This defines a public type. One or more of the EXTRA macros be used.
 * REFOBJECT_DEFINE_PRIVATE_TYPE(type,extras...)
 *  Same as REFOBJECT_DEFINE_TYPE() but defines private type.
 *
 * EXTRA Marcos:
 * REFOBJECT_DEFINE_TYPE_FREE(cb)
 *  This defines a callback to be called when the object is freed.
 *  cb must be of type refobject_free_t.
 * REFOBJECT_DEFINE_TYPE_NEW(cb)
 *  This defines a callback to be called when a new object is created.
 *  cb must be of type refobject_new_t.
 * REFOBJECT_DEFINE_TYPE_NEW_NOOP()
 *  This installs a dummy callback for creation. This allows the type
 *  to be created using refobject_new(type) as with REFOBJECT_DEFINE_TYPE_NEW().
 *  This is useful for types that do not need to be initialized more than what
 *  refobject_new() already does.
 *
 * Other Macros:
 * REFOBJECT_CONTROL_VERSION
 * REFOBJECT_DEFINE_TYPE__RAW()
 *  Not to be used by the user.
 */
96 97 98 99 100
#define REFOBJECT_CONTROL_VERSION                   1
#define REFOBJECT_FORWARD_TYPE(type)                extern const refobject_type_t * refobject_type__ ## type;
#define REFOBJECT_DEFINE_TYPE__RAW(type, ...)       \
static const refobject_type_t refobject_typedef__ ## type = \
{ \
101 102 103
    .control_length = sizeof(refobject_type_t), \
    .control_version = REFOBJECT_CONTROL_VERSION, \
    .type_length = sizeof(type), \
104 105
    .type_name = # type \
    , ## __VA_ARGS__ \
106
}
107 108 109
#define REFOBJECT_DEFINE_TYPE(type, ...)            REFOBJECT_DEFINE_TYPE__RAW(type, ## __VA_ARGS__); const refobject_type_t * refobject_type__ ## type = &refobject_typedef__ ## type
#define REFOBJECT_DEFINE_PRIVATE_TYPE(type, ...)    REFOBJECT_DEFINE_TYPE__RAW(type, ## __VA_ARGS__); static const refobject_type_t * refobject_type__ ## type = &refobject_typedef__ ## type
#define REFOBJECT_DEFINE_TYPE_FREE(cb)              .type_freecb = (cb)
110
#define REFOBJECT_DEFINE_TYPE_NEW(cb)               .type_newcb = (cb)
111
#define REFOBJECT_DEFINE_TYPE_NEW_NOOP()            .type_newcb = refobject_new__return_zero
112 113

typedef struct refobject_type_tag refobject_type_t;
114
int refobject_new__return_zero(refobject_t self, const refobject_type_t *type, va_list ap);
115

116 117 118 119 120 121 122 123
/* Type used for callback called then the object is actually freed
 * That is once all references to it are gone.
 *
 * If the callback does not set *userdata to NULL *userdata will
 * be freed automatically by calling free(3).
 *
 * This function must not try to deallocate or alter self.
 */
124
typedef void (*refobject_free_t)(refobject_t self, void **userdata);
125

126 127 128 129 130 131 132 133 134 135 136 137
/* Type used for callback called then the object is created
 * using the generic refobject_new().
 *
 * Additional parameters passed to refobject_new() are passed
 * in the list ap. All limitations of <stdarg.h> apply.
 *
 * This function must return zero in case of success and
 * non-zero in case of error. In case of error refobject_unref()
 * is called internally to clear the object.
 */
typedef int (*refobject_new_t)(refobject_t self, const refobject_type_t *type, va_list ap);

138
/* Meta type used to defined types.
Philipp Schafft's avatar
Philipp Schafft committed
139
 * DO NOT use any of the members in here directly!
140 141
 */

142
struct refobject_type_tag {
Philipp Schafft's avatar
Philipp Schafft committed
143
    /* Size of this control structure */
144
    size_t              control_length;
Philipp Schafft's avatar
Philipp Schafft committed
145
    /* ABI version of this structure */
146
    int                 control_version;
Philipp Schafft's avatar
Philipp Schafft committed
147 148

    /* Total length of the objects to be created */
149
    size_t              type_length;
Philipp Schafft's avatar
Philipp Schafft committed
150
    /* Name of type */
151
    const char *        type_name;
Philipp Schafft's avatar
Philipp Schafft committed
152
    /* Callback to be called on final free() */
153
    refobject_free_t    type_freecb;
154 155 156
    /* Callback to be callback by refobject_new() */
    refobject_new_t     type_newcb;
};
157

158 159 160
/* Only defined here as the size must be publically known.
 * DO NOT use any of the members in here directly!
 */
161
struct refobject_base_tag {
162
    const refobject_type_t* type;
163 164 165
    size_t refc;
    mutex_t lock;
    void *userdata;
166
    char *name;
167
    refobject_t associated;
168 169
};

170 171
REFOBJECT_FORWARD_TYPE(refobject_base_t);

172 173 174 175 176 177 178 179 180 181
/* Create a new refobject
 * The total length of the new object is given by len (see malloc(3)),
 * the callback called on free is given by freecb (see refobject_free_t above),
 * the userdata us given by userdata,
 * the name for the object is given by name, and
 * the associated refobject is given by associated.
 *
 * All parameters beside len are optional and can be NULL/REFOBJECT_NULL.
 * If no freecb is given the userdata is freed (see refobject_free_t above).
 */
182
#define         refobject_new__new(type, userdata, name, associated) REFOBJECT_TO_TYPE(refobject_new__real((refobject_type__ ## type), (userdata), (name), (associated)), type*)
183
refobject_t     refobject_new__real(const refobject_type_t *type, void *userdata, const char *name, refobject_t associated);
184 185 186
#define         refobject_new(type, ...) REFOBJECT_TO_TYPE(refobject_new__simple((refobject_type__ ## type), NULL, NULL, REFOBJECT_NULL, ## __VA_ARGS__), type*)
#define         refobject_new_ext(type, userdata, name, associated, ...) REFOBJECT_TO_TYPE(refobject_new__simple((refobject_type__ ## type), (userdata), (name), (associated), ## __VA_ARGS__), type*)
refobject_t     refobject_new__simple(const refobject_type_t *type, void *userdata, const char *name, refobject_t associated, ...);
187 188

/* This increases the reference counter of the object */
189
int             refobject_ref(refobject_t self);
190 191 192
/* This decreases the reference counter of the object.
 * If the object's reference counter reaches zero the object is freed.
 */
193
int             refobject_unref(refobject_t self);
194 195

/* This gets and sets the userdata */
196 197
void *          refobject_get_userdata(refobject_t self);
int             refobject_set_userdata(refobject_t self, void *userdata);
198 199

/* This gets the object's name */
200
const char *    refobject_get_name(refobject_t self);
201 202

/* This gets the object's associated object. */
203
refobject_t     refobject_get_associated(refobject_t self);
204 205

#endif