2018-05-25 09:24:03 -04:00
|
|
|
/* 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>,
|
|
|
|
*/
|
|
|
|
|
2018-07-27 06:33:57 -04:00
|
|
|
/* 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.
|
|
|
|
*/
|
|
|
|
|
2018-05-25 09:24:03 -04:00
|
|
|
#ifndef __REFOBJECT_H__
|
|
|
|
#define __REFOBJECT_H__
|
|
|
|
|
2018-06-06 10:38:24 -04:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2018-10-10 10:27:07 -04:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
2018-05-25 09:24:03 -04:00
|
|
|
#include "common/thread/thread.h"
|
|
|
|
|
|
|
|
#include "icecasttypes.h"
|
|
|
|
#include "compat.h"
|
|
|
|
|
2018-07-27 06:33:57 -04:00
|
|
|
/* 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).
|
|
|
|
*/
|
2018-06-06 10:38:24 -04:00
|
|
|
#ifdef HAVE_TYPE_ATTRIBUTE_TRANSPARENT_UNION
|
|
|
|
#define REFOBJECT_NULL ((refobject_t)(refobject_base_t*)NULL)
|
2018-10-10 09:12:01 -04:00
|
|
|
#define REFOBJECT_GET_BASE(x) (((refobject_t)(x)).refobject_base)
|
2018-06-06 10:38:24 -04:00
|
|
|
#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
|
2018-10-10 09:12:01 -04:00
|
|
|
#define REFOBJECT_GET_BASE(x) ((refobject_base_t)(x))
|
2018-06-06 10:38:24 -04:00
|
|
|
#define REFOBJECT_IS_NULL(x) ((x) == NULL)
|
|
|
|
#define REFOBJECT_TO_TYPE(x,y) ((y)(x))
|
|
|
|
#endif
|
|
|
|
|
2018-10-10 08:55:32 -04:00
|
|
|
#define REFOBJECT_FROM_TYPE(x) ((refobject_t)(refobject_base_t*)(x))
|
|
|
|
|
2018-10-10 09:12:01 -04:00
|
|
|
#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)
|
|
|
|
|
2018-10-10 10:11:24 -04:00
|
|
|
#define REFOBJECT_IS_VALID(x,type) (!REFOBJECT_IS_NULL((x)) && REFOBJECT_GET_TYPE((x)) == (refobject_type__ ## type))
|
2018-10-10 09:12:01 -04:00
|
|
|
|
2018-10-10 10:11:24 -04:00
|
|
|
#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 = \
|
|
|
|
{ \
|
2018-10-10 07:15:39 -04:00
|
|
|
.control_length = sizeof(refobject_type_t), \
|
|
|
|
.control_version = REFOBJECT_CONTROL_VERSION, \
|
|
|
|
.type_length = sizeof(type), \
|
2018-10-10 10:11:24 -04:00
|
|
|
.type_name = # type \
|
|
|
|
, ## __VA_ARGS__ \
|
2018-10-10 07:15:39 -04:00
|
|
|
}
|
2018-10-10 10:11:24 -04:00
|
|
|
#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)
|
2018-10-10 10:27:07 -04:00
|
|
|
#define REFOBJECT_DEFINE_TYPE_NEW(cb) .type_newcb = (cb)
|
2018-10-10 10:42:37 -04:00
|
|
|
#define REFOBJECT_DEFINE_TYPE_NEW_NOOP() .type_newcb = refobject_new__return_zero
|
2018-10-10 10:27:07 -04:00
|
|
|
|
|
|
|
typedef struct refobject_type_tag refobject_type_t;
|
2018-10-10 10:42:37 -04:00
|
|
|
int refobject_new__return_zero(refobject_t self, const refobject_type_t *type, va_list ap);
|
2018-10-10 07:15:39 -04:00
|
|
|
|
2018-07-27 06:33:57 -04:00
|
|
|
/* 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.
|
|
|
|
*/
|
2018-05-25 10:45:08 -04:00
|
|
|
typedef void (*refobject_free_t)(refobject_t self, void **userdata);
|
2018-05-25 09:24:03 -04:00
|
|
|
|
2018-10-10 10:27:07 -04:00
|
|
|
/* 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);
|
|
|
|
|
2018-10-10 07:15:39 -04:00
|
|
|
/* Meta type used to defined types.
|
2018-10-10 09:18:33 -04:00
|
|
|
* DO NOT use any of the members in here directly!
|
2018-10-10 07:15:39 -04:00
|
|
|
*/
|
|
|
|
|
2018-10-10 10:27:07 -04:00
|
|
|
struct refobject_type_tag {
|
2018-10-10 09:18:33 -04:00
|
|
|
/* Size of this control structure */
|
2018-10-10 07:15:39 -04:00
|
|
|
size_t control_length;
|
2018-10-10 09:18:33 -04:00
|
|
|
/* ABI version of this structure */
|
2018-10-10 07:15:39 -04:00
|
|
|
int control_version;
|
2018-10-10 09:18:33 -04:00
|
|
|
|
|
|
|
/* Total length of the objects to be created */
|
2018-10-10 07:15:39 -04:00
|
|
|
size_t type_length;
|
2018-10-10 09:18:33 -04:00
|
|
|
/* Name of type */
|
2018-10-10 07:15:39 -04:00
|
|
|
const char * type_name;
|
2018-10-10 09:18:33 -04:00
|
|
|
/* Callback to be called on final free() */
|
2018-10-10 07:15:39 -04:00
|
|
|
refobject_free_t type_freecb;
|
2018-10-10 10:27:07 -04:00
|
|
|
/* Callback to be callback by refobject_new() */
|
|
|
|
refobject_new_t type_newcb;
|
|
|
|
};
|
2018-10-10 07:15:39 -04:00
|
|
|
|
2018-07-27 06:33:57 -04:00
|
|
|
/* Only defined here as the size must be publically known.
|
|
|
|
* DO NOT use any of the members in here directly!
|
|
|
|
*/
|
2018-05-25 09:24:03 -04:00
|
|
|
struct refobject_base_tag {
|
2018-10-10 07:15:39 -04:00
|
|
|
const refobject_type_t* type;
|
2018-05-25 09:24:03 -04:00
|
|
|
size_t refc;
|
|
|
|
mutex_t lock;
|
|
|
|
void *userdata;
|
2018-05-25 10:45:08 -04:00
|
|
|
char *name;
|
2018-06-17 03:06:36 -04:00
|
|
|
refobject_t associated;
|
2018-05-25 09:24:03 -04:00
|
|
|
};
|
|
|
|
|
2018-10-10 07:15:39 -04:00
|
|
|
REFOBJECT_FORWARD_TYPE(refobject_base_t);
|
|
|
|
|
2018-07-27 06:33:57 -04:00
|
|
|
/* 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).
|
|
|
|
*/
|
2018-10-10 10:11:24 -04:00
|
|
|
#define refobject_new__new(type, userdata, name, associated) REFOBJECT_TO_TYPE(refobject_new__real((refobject_type__ ## type), (userdata), (name), (associated)), type*)
|
2018-10-10 07:15:39 -04:00
|
|
|
refobject_t refobject_new__real(const refobject_type_t *type, void *userdata, const char *name, refobject_t associated);
|
2018-10-10 10:27:07 -04:00
|
|
|
#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, ...);
|
2018-07-27 06:33:57 -04:00
|
|
|
|
|
|
|
/* This increases the reference counter of the object */
|
2018-05-25 09:24:03 -04:00
|
|
|
int refobject_ref(refobject_t self);
|
2018-07-27 06:33:57 -04:00
|
|
|
/* This decreases the reference counter of the object.
|
|
|
|
* If the object's reference counter reaches zero the object is freed.
|
|
|
|
*/
|
2018-05-25 09:24:03 -04:00
|
|
|
int refobject_unref(refobject_t self);
|
2018-07-27 06:33:57 -04:00
|
|
|
|
|
|
|
/* This gets and sets the userdata */
|
2018-05-25 09:24:03 -04:00
|
|
|
void * refobject_get_userdata(refobject_t self);
|
|
|
|
int refobject_set_userdata(refobject_t self, void *userdata);
|
2018-07-27 06:33:57 -04:00
|
|
|
|
|
|
|
/* This gets the object's name */
|
2018-05-25 10:45:08 -04:00
|
|
|
const char * refobject_get_name(refobject_t self);
|
2018-07-27 06:33:57 -04:00
|
|
|
|
|
|
|
/* This gets the object's associated object. */
|
2018-06-17 03:06:36 -04:00
|
|
|
refobject_t refobject_get_associated(refobject_t self);
|
2018-05-25 09:24:03 -04:00
|
|
|
|
|
|
|
#endif
|