refobject.h 5.25 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 22 23 24
#include "common/thread/thread.h"

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

25 26 27 28 29 30 31 32 33 34 35 36 37 38
/* 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).
 */
39 40
#ifdef HAVE_TYPE_ATTRIBUTE_TRANSPARENT_UNION
#define REFOBJECT_NULL          ((refobject_t)(refobject_base_t*)NULL)
41
#define REFOBJECT_GET_BASE(x)   (((refobject_t)(x)).refobject_base)
42 43 44 45
#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
46
#define REFOBJECT_GET_BASE(x)   ((refobject_base_t)(x))
47 48 49 50
#define REFOBJECT_IS_NULL(x)    ((x) == NULL)
#define REFOBJECT_TO_TYPE(x,y)  ((y)(x))
#endif

51 52
#define REFOBJECT_FROM_TYPE(x)  ((refobject_t)(refobject_base_t*)(x))

53 54 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)

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

58 59 60 61 62 63 64 65 66 67 68 69
#define REFOBJECT_CONTROL_VERSION           0
#define REFOBJECT_FORWARD_TYPE(type)        extern const refobject_type_t refobject_type__ ## type;
#define REFOBJECT_DEFINE_TYPE(type, extra)  const refobject_type_t refobject_type__ ## type = { \
    .control_length = sizeof(refobject_type_t), \
    .control_version = REFOBJECT_CONTROL_VERSION, \
    .type_length = sizeof(type), \
    .type_name = # type, \
    extra \
}
#define REFOBJECT_DEFINE_PRIVATE_TYPE(type, extra) static REFOBJECT_DEFINE_TYPE(type, extra)
#define REFOBJECT_DEFINE_TYPE_FREE(cb)      .type_freecb = (cb)

70 71 72 73 74 75 76 77
/* 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.
 */
78
typedef void (*refobject_free_t)(refobject_t self, void **userdata);
79

80
/* Meta type used to defined types.
Philipp Schafft's avatar
Philipp Schafft committed
81
 * DO NOT use any of the members in here directly!
82 83 84
 */

typedef struct {
Philipp Schafft's avatar
Philipp Schafft committed
85
    /* Size of this control structure */
86
    size_t              control_length;
Philipp Schafft's avatar
Philipp Schafft committed
87
    /* ABI version of this structure */
88
    int                 control_version;
Philipp Schafft's avatar
Philipp Schafft committed
89 90

    /* Total length of the objects to be created */
91
    size_t              type_length;
Philipp Schafft's avatar
Philipp Schafft committed
92
    /* Name of type */
93
    const char *        type_name;
Philipp Schafft's avatar
Philipp Schafft committed
94
    /* Callback to be called on final free() */
95 96 97
    refobject_free_t    type_freecb;
} refobject_type_t;

98 99 100
/* Only defined here as the size must be publically known.
 * DO NOT use any of the members in here directly!
 */
101
struct refobject_base_tag {
102
    const refobject_type_t* type;
103 104 105
    size_t refc;
    mutex_t lock;
    void *userdata;
106
    char *name;
107
    refobject_t associated;
108 109
};

110 111
REFOBJECT_FORWARD_TYPE(refobject_base_t);

112 113 114 115 116 117 118 119 120 121
/* 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).
 */
122 123
#define         refobject_new__new(type, userdata, name, associated) REFOBJECT_TO_TYPE(refobject_new__real(&(refobject_type__ ## type), (userdata), (name), (associated)), type*)
refobject_t     refobject_new__real(const refobject_type_t *type, void *userdata, const char *name, refobject_t associated);
124 125

/* This increases the reference counter of the object */
126
int             refobject_ref(refobject_t self);
127 128 129
/* This decreases the reference counter of the object.
 * If the object's reference counter reaches zero the object is freed.
 */
130
int             refobject_unref(refobject_t self);
131 132

/* This gets and sets the userdata */
133 134
void *          refobject_get_userdata(refobject_t self);
int             refobject_set_userdata(refobject_t self, void *userdata);
135 136

/* This gets the object's name */
137
const char *    refobject_get_name(refobject_t self);
138 139

/* This gets the object's associated object. */
140
refobject_t     refobject_get_associated(refobject_t self);
141 142

#endif