refobject.h 6.94 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 40
/* 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).
 */
41 42
#ifdef HAVE_TYPE_ATTRIBUTE_TRANSPARENT_UNION
#define REFOBJECT_NULL          ((refobject_t)(refobject_base_t*)NULL)
43
#define REFOBJECT_GET_BASE(x)   (((refobject_t)(x)).refobject_base)
44 45 46 47
#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
48
#define REFOBJECT_GET_BASE(x)   ((refobject_base_t)(x))
49 50 51 52
#define REFOBJECT_IS_NULL(x)    ((x) == NULL)
#define REFOBJECT_TO_TYPE(x,y)  ((y)(x))
#endif

53 54
#define REFOBJECT_FROM_TYPE(x)  ((refobject_t)(refobject_base_t*)(x))

55 56 57
#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)

58
#define REFOBJECT_IS_VALID(x,type)  (!REFOBJECT_IS_NULL((x)) && REFOBJECT_GET_TYPE((x)) == (refobject_type__ ## type))
59

60 61 62 63 64
#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 = \
{ \
65 66 67
    .control_length = sizeof(refobject_type_t), \
    .control_version = REFOBJECT_CONTROL_VERSION, \
    .type_length = sizeof(type), \
68 69
    .type_name = # type \
    , ## __VA_ARGS__ \
70
}
71 72 73
#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)
74
#define REFOBJECT_DEFINE_TYPE_NEW(cb)               .type_newcb = (cb)
75
#define REFOBJECT_DEFINE_TYPE_NEW_NOOP()            .type_newcb = refobject_new__return_zero
76 77

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

80 81 82 83 84 85 86 87
/* 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.
 */
88
typedef void (*refobject_free_t)(refobject_t self, void **userdata);
89

90 91 92 93 94 95 96 97 98 99 100 101
/* 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);

102
/* Meta type used to defined types.
Philipp Schafft's avatar
Philipp Schafft committed
103
 * DO NOT use any of the members in here directly!
104 105
 */

106
struct refobject_type_tag {
Philipp Schafft's avatar
Philipp Schafft committed
107
    /* Size of this control structure */
108
    size_t              control_length;
Philipp Schafft's avatar
Philipp Schafft committed
109
    /* ABI version of this structure */
110
    int                 control_version;
Philipp Schafft's avatar
Philipp Schafft committed
111 112

    /* Total length of the objects to be created */
113
    size_t              type_length;
Philipp Schafft's avatar
Philipp Schafft committed
114
    /* Name of type */
115
    const char *        type_name;
Philipp Schafft's avatar
Philipp Schafft committed
116
    /* Callback to be called on final free() */
117
    refobject_free_t    type_freecb;
118 119 120
    /* Callback to be callback by refobject_new() */
    refobject_new_t     type_newcb;
};
121

122 123 124
/* Only defined here as the size must be publically known.
 * DO NOT use any of the members in here directly!
 */
125
struct refobject_base_tag {
126
    const refobject_type_t* type;
127 128 129
    size_t refc;
    mutex_t lock;
    void *userdata;
130
    char *name;
131
    refobject_t associated;
132 133
};

134 135
REFOBJECT_FORWARD_TYPE(refobject_base_t);

136 137 138 139 140 141 142 143 144 145
/* 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).
 */
146
#define         refobject_new__new(type, userdata, name, associated) REFOBJECT_TO_TYPE(refobject_new__real((refobject_type__ ## type), (userdata), (name), (associated)), type*)
147
refobject_t     refobject_new__real(const refobject_type_t *type, void *userdata, const char *name, refobject_t associated);
148 149 150
#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, ...);
151 152

/* This increases the reference counter of the object */
153
int             refobject_ref(refobject_t self);
154 155 156
/* This decreases the reference counter of the object.
 * If the object's reference counter reaches zero the object is freed.
 */
157
int             refobject_unref(refobject_t self);
158 159

/* This gets and sets the userdata */
160 161
void *          refobject_get_userdata(refobject_t self);
int             refobject_set_userdata(refobject_t self, void *userdata);
162 163

/* This gets the object's name */
164
const char *    refobject_get_name(refobject_t self);
165 166

/* This gets the object's associated object. */
167
refobject_t     refobject_get_associated(refobject_t self);
168 169

#endif