diff --git a/src/buffer.c b/src/buffer.c index 9d8e1ace..33259993 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -37,16 +37,18 @@ static void __free(refobject_t self, void **userdata) free(buffer->buffer); } +REFOBJECT_DEFINE_TYPE(buffer_t, + REFOBJECT_DEFINE_TYPE_FREE(__free), + REFOBJECT_DEFINE_TYPE_NEW_NOOP() + ); + buffer_t * buffer_new(ssize_t preallocation, void *userdata, const char *name, refobject_t associated) { - buffer_t *buffer = NULL; - refobject_t refobject = refobject_new(sizeof(*buffer), __free, userdata, name, associated); + buffer_t *buffer = refobject_new_ext(buffer_t, userdata, name, associated); - if (REFOBJECT_IS_NULL(refobject)) + if (!buffer) return NULL; - buffer = REFOBJECT_TO_TYPE(refobject, buffer_t *); - if (preallocation > 0) buffer_preallocate(buffer, preallocation); @@ -55,7 +57,7 @@ buffer_t * buffer_new(ssize_t preallocation, void *userdata, const char *name, buffer_t * buffer_new_simple(void) { - return buffer_new(-1, NULL, NULL, REFOBJECT_NULL); + return refobject_new(buffer_t); } void buffer_preallocate(buffer_t *buffer, size_t request) diff --git a/src/buffer.h b/src/buffer.h index 8aea026a..c2a33a62 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -28,6 +28,8 @@ * This set of functions is intentinally not thread safe. */ +REFOBJECT_FORWARD_TYPE(buffer_t); + /* This creates a new buffer object. * Parameters: * preallocation @@ -37,7 +39,9 @@ */ buffer_t * buffer_new(ssize_t preallocation, void *userdata, const char *name, refobject_t associated); -/* This creates a new buffer with defaults. +/* Depreciated: This creates a new buffer with defaults. + * Do NOT use this. Use refobject_new(buffer_t) + * * This is the same as: * buffer_new(-1, NULL, NULL, REFOBJECT_NULL) */ diff --git a/src/cfgfile.c b/src/cfgfile.c index 2a014b1e..b8a973fd 100644 --- a/src/cfgfile.c +++ b/src/cfgfile.c @@ -232,7 +232,7 @@ void config_init_configuration(ice_config_t *configuration) { memset(configuration, 0, sizeof(ice_config_t)); _set_defaults(configuration); - configuration->reportxml_db = reportxml_database_new(); + configuration->reportxml_db = refobject_new(reportxml_database_t); } static inline void __read_int(xmlDocPtr doc, xmlNodePtr node, int *val, const char *warning) diff --git a/src/client.c b/src/client.c index 5c91cd13..e7e1bd51 100644 --- a/src/client.c +++ b/src/client.c @@ -661,7 +661,7 @@ reportxml_t *client_get_reportxml(const char *state_definition, const char *stat if (!report) { reportxml_node_t *rootnode, *incidentnode, *statenode; - report = reportxml_new(); + report = refobject_new(reportxml_t); rootnode = reportxml_get_root_node(report); incidentnode = reportxml_node_new(REPORTXML_NODE_TYPE_INCIDENT, NULL, NULL, NULL); statenode = reportxml_node_new(REPORTXML_NODE_TYPE_STATE, NULL, state_definition, state_akindof); diff --git a/src/connection.c b/src/connection.c index a71333ce..c533c15e 100644 --- a/src/connection.c +++ b/src/connection.c @@ -1703,7 +1703,7 @@ void connection_setup_sockets (ice_config_t *config) allowed_ip = matchfile_new(config->allowfile); } - global.listensockets = listensocket_container_new(); + global.listensockets = refobject_new(listensocket_container_t); listensocket_container_configure(global.listensockets, config); global_unlock(); diff --git a/src/fastevent.c b/src/fastevent.c index 5022c698..5ab90b64 100644 --- a/src/fastevent.c +++ b/src/fastevent.c @@ -26,19 +26,19 @@ #ifdef FASTEVENT_ENABLED -struct registration { +typedef struct { refobject_base_t __base; fastevent_type_t type; fastevent_cb_t cb; fastevent_freecb_t freecb; void *userdata; -}; +} fastevent_registration_t; struct eventrow { size_t length; size_t used; - struct registration **registrations; + fastevent_registration_t **registrations; }; static struct eventrow fastevent_registrations[FASTEVENT_TYPE__END]; @@ -54,9 +54,9 @@ static inline struct eventrow * __get_row(fastevent_type_t type) return &(fastevent_registrations[idx]); } -static int __add_to_row(struct eventrow * row, struct registration *registration) +static int __add_to_row(struct eventrow * row, fastevent_registration_t *registration) { - struct registration **n; + fastevent_registration_t **n; if (row == NULL) return -1; @@ -77,7 +77,7 @@ static int __add_to_row(struct eventrow * row, struct registration *registration return 0; } -static int __remove_from_row(struct eventrow * row, struct registration *registration) +static int __remove_from_row(struct eventrow * row, fastevent_registration_t *registration) { size_t i; @@ -98,7 +98,7 @@ static int __remove_from_row(struct eventrow * row, struct registration *registr static void __unregister(refobject_t self, void **userdata) { - struct registration *registration = REFOBJECT_TO_TYPE(self, struct registration *); + fastevent_registration_t *registration = REFOBJECT_TO_TYPE(self, fastevent_registration_t *); struct eventrow * row; (void)userdata; @@ -143,11 +143,14 @@ int fastevent_shutdown(void) return 0; } +REFOBJECT_DEFINE_PRIVATE_TYPE(fastevent_registration_t, + REFOBJECT_DEFINE_TYPE_FREE(__unregister) + ); + refobject_t fastevent_register(fastevent_type_t type, fastevent_cb_t cb, fastevent_freecb_t freecb, void *userdata) { struct eventrow * row; - struct registration *registration; - refobject_t ret; + fastevent_registration_t *registration; if (cb == NULL) return REFOBJECT_NULL; @@ -160,15 +163,13 @@ refobject_t fastevent_register(fastevent_type_t type, fastevent_cb_t cb, fasteve return REFOBJECT_NULL; } - ret = refobject_new(sizeof(struct registration), __unregister, NULL, NULL, NULL); + registration = refobject_new__new(fastevent_registration_t, NULL, NULL, NULL); - if (REFOBJECT_IS_NULL(ret)) { + if (!registration) { thread_rwlock_unlock(&fastevent_lock); return REFOBJECT_NULL; } - registration = REFOBJECT_TO_TYPE(ret, struct registration *); - registration->type = type; registration->cb = cb; registration->freecb = freecb; @@ -176,12 +177,12 @@ refobject_t fastevent_register(fastevent_type_t type, fastevent_cb_t cb, fasteve if (__add_to_row(row, registration) != 0) { thread_rwlock_unlock(&fastevent_lock); - refobject_unref(ret); + refobject_unref(REFOBJECT_FROM_TYPE(registration)); return REFOBJECT_NULL; } thread_rwlock_unlock(&fastevent_lock); - return ret; + return REFOBJECT_FROM_TYPE(registration); } void fastevent_emit(fastevent_type_t type, fastevent_flag_t flags, fastevent_datatype_t datatype, ...) diff --git a/src/fastevent.h b/src/fastevent.h index a45a8bfb..1a18ba6f 100644 --- a/src/fastevent.h +++ b/src/fastevent.h @@ -15,7 +15,7 @@ #endif #include -#include +#include "refobject.h" typedef enum { FASTEVENT_TYPE_SLOWEVENT = 0, diff --git a/src/global.c b/src/global.c index db126887..9671e036 100644 --- a/src/global.c +++ b/src/global.c @@ -38,7 +38,7 @@ void global_initialize(void) global.clients = 0; global.sources = 0; global.source_tree = avl_tree_new(source_compare_sources, NULL); - global.modulecontainer = module_container_new(); + global.modulecontainer = refobject_new(module_container_t); thread_mutex_create(&_global_mutex); } diff --git a/src/listensocket.c b/src/listensocket.c index f188ef56..2fef714a 100644 --- a/src/listensocket.c +++ b/src/listensocket.c @@ -150,22 +150,25 @@ static void __listensocket_container_free(refobject_t self, void **userdata) thread_mutex_destroy(&container->lock); } -listensocket_container_t * listensocket_container_new(void) +int __listensocket_container_new(refobject_t self, const refobject_type_t *type, va_list ap) { - listensocket_container_t *self = REFOBJECT_TO_TYPE(refobject_new(sizeof(listensocket_container_t), __listensocket_container_free, NULL, NULL, NULL), listensocket_container_t *); - if (!self) - return NULL; + listensocket_container_t *ret = REFOBJECT_TO_TYPE(self, listensocket_container_t*); - self->sock = NULL; - self->sock_len = 0; - self->sockcount_cb = NULL; - self->sockcount_userdata = NULL; + ret->sock = NULL; + ret->sock_len = 0; + ret->sockcount_cb = NULL; + ret->sockcount_userdata = NULL; - thread_mutex_create(&self->lock); + thread_mutex_create(&ret->lock); - return self; + return 0; } +REFOBJECT_DEFINE_TYPE(listensocket_container_t, + REFOBJECT_DEFINE_TYPE_FREE(__listensocket_container_free), + REFOBJECT_DEFINE_TYPE_NEW(__listensocket_container_new) + ); + static inline void __find_matching_entry(listensocket_container_t *self, const listener_t *listener, listensocket_t ***found, int **ref) { const listener_t *b; @@ -527,13 +530,17 @@ static void __listensocket_free(refobject_t self, void **userdata) thread_mutex_destroy(&listensocket->lock); } +REFOBJECT_DEFINE_TYPE(listensocket_t, + REFOBJECT_DEFINE_TYPE_FREE(__listensocket_free) + ); + static listensocket_t * listensocket_new(const listener_t *listener) { listensocket_t *self; if (listener == NULL) return NULL; - self = REFOBJECT_TO_TYPE(refobject_new(sizeof(listensocket_t), __listensocket_free, NULL, NULL, NULL), listensocket_t *); + self = refobject_new__new(listensocket_t, NULL, NULL, NULL); if (!self) return NULL; diff --git a/src/listensocket.h b/src/listensocket.h index 4991892d..a6d063bd 100644 --- a/src/listensocket.h +++ b/src/listensocket.h @@ -10,8 +10,11 @@ #define __LISTENSOCKET_H__ #include "icecasttypes.h" +#include "refobject.h" #include "cfgfile.h" +REFOBJECT_FORWARD_TYPE(listensocket_container_t); + listensocket_container_t * listensocket_container_new(void); int listensocket_container_configure(listensocket_container_t *self, const ice_config_t *config); int listensocket_container_configure_and_setup(listensocket_container_t *self, const ice_config_t *config); @@ -20,6 +23,8 @@ connection_t * listensocket_container_accept(listensocket_container int listensocket_container_set_sockcount_cb(listensocket_container_t *self, void (*cb)(size_t count, void *userdata), void *userdata); ssize_t listensocket_container_sockcount(listensocket_container_t *self); +REFOBJECT_FORWARD_TYPE(listensocket_t); + int listensocket_refsock(listensocket_t *self); int listensocket_unrefsock(listensocket_t *self); connection_t * listensocket_accept(listensocket_t *self, listensocket_container_t *container); diff --git a/src/module.c b/src/module.c index 997d4819..52287f42 100644 --- a/src/module.c +++ b/src/module.c @@ -50,20 +50,22 @@ static void __module_container_free(refobject_t self, void **userdata) avl_tree_free(cont->module, (avl_free_key_fun_type)refobject_unref); } -module_container_t * module_container_new(void) +int __module_container_new(refobject_t self, const refobject_type_t *type, va_list ap) { - module_container_t *ret = REFOBJECT_TO_TYPE(refobject_new(sizeof(module_container_t), __module_container_free, NULL, NULL, NULL), module_container_t *); - - if (!ret) - return NULL; + module_container_t *ret = REFOBJECT_TO_TYPE(self, module_container_t*); thread_mutex_create(&(ret->lock)); ret->module = avl_tree_new(compare_refobject_t_name, NULL); - return ret; + return 0; } +REFOBJECT_DEFINE_TYPE(module_container_t, + REFOBJECT_DEFINE_TYPE_FREE(__module_container_free), + REFOBJECT_DEFINE_TYPE_NEW(__module_container_new) + ); + int module_container_add_module(module_container_t *self, module_t *module) { if (!self) @@ -101,13 +103,13 @@ int module_container_delete_module(module_container_t *self, module_t * module_container_get_module(module_container_t *self, const char *name) { - refobject_t search; + refobject_base_t *search; module_t *ret; if (!self || !name) return NULL; - search = refobject_new(sizeof(refobject_base_t), NULL, NULL, name, NULL); + search = refobject_new__new(refobject_base_t, NULL, name, NULL); thread_mutex_lock(&(self->lock)); if (avl_get_by_key(self->module, REFOBJECT_TO_TYPE(search, void *), (void**)&ret) != 0) { @@ -168,9 +170,13 @@ static void __module_free(refobject_t self, void **userdata) thread_mutex_destroy(&(mod->lock)); } +REFOBJECT_DEFINE_TYPE(module_t, + REFOBJECT_DEFINE_TYPE_FREE(__module_free) + ); + module_t * module_new(const char *name, module_setup_handler_t newcb, module_setup_handler_t freecb, void *userdata) { - module_t *ret = REFOBJECT_TO_TYPE(refobject_new(sizeof(module_t), __module_free, NULL, name, NULL), module_t *); + module_t *ret = refobject_new__new(module_t, NULL, name, NULL); if (!ret) return NULL; diff --git a/src/module.h b/src/module.h index d9d38a2f..20ed3ada 100644 --- a/src/module.h +++ b/src/module.h @@ -12,6 +12,7 @@ #include #include "icecasttypes.h" +#include "refobject.h" typedef void (*module_client_handler_function_t)(module_t *self, client_t *client); typedef int (*module_setup_handler_t)(module_t *self, void **userdata); @@ -21,7 +22,9 @@ typedef struct { module_client_handler_function_t cb; } module_client_handler_t; -module_container_t * module_container_new(void); +REFOBJECT_FORWARD_TYPE(module_container_t); +REFOBJECT_FORWARD_TYPE(module_t); + int module_container_add_module(module_container_t *self, module_t *module); int module_container_delete_module(module_container_t *self, const char *name); module_t * module_container_get_module(module_container_t *self, const char *name); diff --git a/src/refobject.c b/src/refobject.c index 2aa7fd18..7b8eb464 100644 --- a/src/refobject.c +++ b/src/refobject.c @@ -19,19 +19,35 @@ #define TO_BASE(x) REFOBJECT_TO_TYPE((x), refobject_base_t *) -refobject_t refobject_new(size_t len, refobject_free_t freecb, void *userdata, const char *name, refobject_t associated) +int refobject_new__return_zero(refobject_t self, const refobject_type_t *type, va_list ap) +{ + (void)self, (void)type, (void)ap; + return 0; +} + +REFOBJECT_DEFINE_TYPE(refobject_base_t, + REFOBJECT_DEFINE_TYPE_NEW_NOOP() + ); + +static inline int check_type(const refobject_type_t *type) +{ + return type->control_length == sizeof(refobject_type_t) && type->control_version == REFOBJECT_CONTROL_VERSION && + type->type_length >= sizeof(refobject_base_t); +} + +refobject_t refobject_new__real(const refobject_type_t *type, void *userdata, const char *name, refobject_t associated) { refobject_base_t *ret = NULL; - if (len < sizeof(refobject_base_t)) + if (!check_type(type)) return (refobject_t)ret; - ret = calloc(1, len); + ret = calloc(1, type->type_length); if (ret == NULL) return (refobject_t)ret; + ret->type = type; ret->refc = 1; - ret->freecb = freecb; ret->userdata = userdata; thread_mutex_create(&(ret->lock)); @@ -56,6 +72,34 @@ refobject_t refobject_new(size_t len, refobject_free_t freecb, void *userdat return (refobject_t)ret; } +refobject_t refobject_new__simple(const refobject_type_t *type, void *userdata, const char *name, refobject_t associated, ...) +{ + refobject_t ret; + int res; + va_list ap; + + if (!check_type(type)) + return REFOBJECT_NULL; + + if (!type->type_newcb) + return REFOBJECT_NULL; + + ret = refobject_new__real(type, userdata, name, associated); + if (REFOBJECT_IS_NULL(ret)) + return REFOBJECT_NULL; + + va_start(ap, associated); + res = type->type_newcb(ret, type, ap); + va_end(ap); + + if (res != 0) { + refobject_unref(ret); + return REFOBJECT_NULL; + } + + return ret; +} + int refobject_ref(refobject_t self) { if (REFOBJECT_IS_NULL(self)) @@ -82,8 +126,8 @@ int refobject_unref(refobject_t self) return 0; } - if (base->freecb) - base->freecb(self, &(base->userdata)); + if (base->type->type_freecb) + base->type->type_freecb(self, &(base->userdata)); if (base->userdata) free(base->userdata); diff --git a/src/refobject.h b/src/refobject.h index e259dc5a..2e7ec504 100644 --- a/src/refobject.h +++ b/src/refobject.h @@ -17,6 +17,8 @@ #include #endif +#include + #include "common/thread/thread.h" #include "icecasttypes.h" @@ -35,17 +37,82 @@ * as the operation is only defined for it's members. * REFOBJECT_TO_TYPE(type,x) * This casts the refobject (x) to the type (type). + * 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. */ #ifdef HAVE_TYPE_ATTRIBUTE_TRANSPARENT_UNION #define REFOBJECT_NULL ((refobject_t)(refobject_base_t*)NULL) +#define REFOBJECT_GET_BASE(x) (((refobject_t)(x)).refobject_base) #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 +#define REFOBJECT_GET_BASE(x) ((refobject_base_t)(x)) #define REFOBJECT_IS_NULL(x) ((x) == NULL) #define REFOBJECT_TO_TYPE(x,y) ((y)(x)) #endif +#define REFOBJECT_FROM_TYPE(x) ((refobject_t)(refobject_base_t*)(x)) + +#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)) + +/* 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. + */ +#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 = \ +{ \ + .control_length = sizeof(refobject_type_t), \ + .control_version = REFOBJECT_CONTROL_VERSION, \ + .type_length = sizeof(type), \ + .type_name = # type \ + , ## __VA_ARGS__ \ +} +#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) +#define REFOBJECT_DEFINE_TYPE_NEW(cb) .type_newcb = (cb) +#define REFOBJECT_DEFINE_TYPE_NEW_NOOP() .type_newcb = refobject_new__return_zero + +typedef struct refobject_type_tag refobject_type_t; +int refobject_new__return_zero(refobject_t self, const refobject_type_t *type, va_list ap); + /* Type used for callback called then the object is actually freed * That is once all references to it are gone. * @@ -56,18 +123,52 @@ */ typedef void (*refobject_free_t)(refobject_t self, void **userdata); +/* 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 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); + +/* Meta type used to defined types. + * DO NOT use any of the members in here directly! + */ + +struct refobject_type_tag { + /* Size of this control structure */ + size_t control_length; + /* ABI version of this structure */ + int control_version; + + /* Total length of the objects to be created */ + size_t type_length; + /* Name of type */ + const char * type_name; + /* Callback to be called on final free() */ + refobject_free_t type_freecb; + /* Callback to be callback by refobject_new() */ + refobject_new_t type_newcb; +}; + /* Only defined here as the size must be publically known. * DO NOT use any of the members in here directly! */ struct refobject_base_tag { + const refobject_type_t* type; size_t refc; mutex_t lock; void *userdata; - refobject_free_t freecb; char *name; refobject_t associated; }; +REFOBJECT_FORWARD_TYPE(refobject_base_t); + /* 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), @@ -78,7 +179,11 @@ struct refobject_base_tag { * 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). */ -refobject_t refobject_new(size_t len, refobject_free_t freecb, void *userdata, const char *name, refobject_t associated); +#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); +#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, ...); /* This increases the reference counter of the object */ int refobject_ref(refobject_t self); diff --git a/src/reportxml.c b/src/reportxml.c index b6ea1c7e..afed1966 100644 --- a/src/reportxml.c +++ b/src/reportxml.c @@ -236,6 +236,24 @@ static void __report_free(refobject_t self, void **userdata) refobject_unref(report->root); } +static int __report_new(refobject_t self, const refobject_type_t *type, va_list ap) +{ + reportxml_t *ret = REFOBJECT_TO_TYPE(self, reportxml_t*); + reportxml_node_t *root = reportxml_node_new(REPORTXML_NODE_TYPE_REPORT, NULL, NULL, NULL); + + if (!root) + return -1; + + ret->root = root; + + return 0; +} + +REFOBJECT_DEFINE_TYPE(reportxml_t, + REFOBJECT_DEFINE_TYPE_FREE(__report_free), + REFOBJECT_DEFINE_TYPE_NEW(__report_new) + ); + static reportxml_t * reportxml_new_with_root(reportxml_node_t *root) { reportxml_t *ret; @@ -243,7 +261,7 @@ static reportxml_t * reportxml_new_with_root(reportxml_node_t *root) if (!root) return NULL; - ret = REFOBJECT_TO_TYPE(refobject_new(sizeof(reportxml_t), __report_free, NULL, NULL, NULL), reportxml_t *); + ret = refobject_new__new(reportxml_t, NULL, NULL, NULL); ret->root = root; return ret; @@ -251,20 +269,7 @@ static reportxml_t * reportxml_new_with_root(reportxml_node_t *root) reportxml_t * reportxml_new(void) { - reportxml_node_t *root = reportxml_node_new(REPORTXML_NODE_TYPE_REPORT, NULL, NULL, NULL); - reportxml_t *ret; - - if (!root) - return NULL; - - ret = reportxml_new_with_root(root); - - if (!ret) { - refobject_unref(root); - return NULL; - } - - return ret; + return refobject_new(reportxml_t); } reportxml_node_t * reportxml_get_root_node(reportxml_t *report) @@ -368,6 +373,10 @@ static void __report_node_free(refobject_t self, void **userdata) free(node->xml_childs); } +REFOBJECT_DEFINE_TYPE(reportxml_node_t, + REFOBJECT_DEFINE_TYPE_FREE(__report_node_free) + ); + reportxml_node_t * reportxml_node_new(reportxml_node_type_t type, const char *id, const char *definition, const char *akindof) { reportxml_node_t *ret; @@ -377,7 +386,7 @@ reportxml_node_t * reportxml_node_new(reportxml_node_type_t type, const cha if (!nodedef) return NULL; - ret = REFOBJECT_TO_TYPE(refobject_new(sizeof(reportxml_node_t), __report_node_free, NULL, NULL, NULL), reportxml_node_t *); + ret = refobject_new__new(reportxml_node_t, NULL, NULL, NULL); if (ret == NULL) return NULL; @@ -975,22 +984,27 @@ static int __compare_definitions(void *arg, void *a, void *b) return ret; } -reportxml_database_t * reportxml_database_new(void) +static int __database_new(refobject_t self, const refobject_type_t *type, va_list ap) { - reportxml_database_t *ret = REFOBJECT_TO_TYPE(refobject_new(sizeof(reportxml_database_t), __database_free, NULL, NULL, NULL), reportxml_database_t *); - - if (!ret) - return NULL; - - ret->definitions = avl_tree_new(__compare_definitions, NULL); - if (!ret->definitions) { - refobject_unref(ret); - return NULL; - } + reportxml_database_t *ret = REFOBJECT_TO_TYPE(self, reportxml_database_t*); thread_mutex_create(&(ret->lock)); - return ret; + ret->definitions = avl_tree_new(__compare_definitions, NULL); + if (!ret->definitions) + return -1; + + return 0; +} + +REFOBJECT_DEFINE_TYPE(reportxml_database_t, + REFOBJECT_DEFINE_TYPE_FREE(__database_free), + REFOBJECT_DEFINE_TYPE_NEW(__database_new) + ); + +reportxml_database_t * reportxml_database_new(void) +{ + return refobject_new(reportxml_database_t); } int reportxml_database_add_report(reportxml_database_t *db, reportxml_t *report) @@ -1293,7 +1307,7 @@ reportxml_t * reportxml_database_build_report(reportxml_database_t *db /* Empty definition? Not exactly an exciting report... */ ICECAST_LOG_WARN("Empty definition for \"%H\". Returning empty report. This is likely an error.", id); refobject_unref(definition); - return reportxml_new(); + return refobject_new(reportxml_t); } if (type == REPORTXML_NODE_TYPE__ERROR) { @@ -1321,7 +1335,7 @@ reportxml_t * reportxml_database_build_report(reportxml_database_t *db break; } - ret = reportxml_new(); + ret = refobject_new(reportxml_t); if (!ret) { refobject_unref(definition); ICECAST_LOG_ERROR("Can not allocate new report. BAD."); diff --git a/src/reportxml.h b/src/reportxml.h index 68d4b3d8..fb4c494c 100644 --- a/src/reportxml.h +++ b/src/reportxml.h @@ -15,6 +15,7 @@ #include "icecasttypes.h" #include "compat.h" +#include "refobject.h" /* XML Tag Types * While a hint of what the nodes are used for is given, see the specification for more details. @@ -60,12 +61,16 @@ typedef enum { REPORTXML_NODE_TYPE_EXTENSION } reportxml_node_type_t; +REFOBJECT_FORWARD_TYPE(reportxml_t); +REFOBJECT_FORWARD_TYPE(reportxml_node_t); +REFOBJECT_FORWARD_TYPE(reportxml_database_t); /* ---[ Document level ]--- */ /* The document object is NOT thread safe. */ - -/* This creates a new, empty report XML document */ +/* Depreciated: This creates a new, empty report XML document + * Do NOT use this. Use refobject_new(reportxml_t) + */ reportxml_t * reportxml_new(void); /* This gets the root node of a report XML document */ reportxml_node_t * reportxml_get_root_node(reportxml_t *report); @@ -125,7 +130,9 @@ xmlNodePtr reportxml_node_get_xml_child(reportxml_node_t *node, siz /* The database object is thread safe. */ -/* Create a new database object */ +/* Depreciated: Create a new database object + * Do NOT use this. Use refobject_new(reportxml_database_t) + */ reportxml_database_t * reportxml_database_new(void); /* Add an report to the database */ int reportxml_database_add_report(reportxml_database_t *db, reportxml_t *report); diff --git a/src/tests/ctest_buffer.c b/src/tests/ctest_buffer.c index d29219cb..682d3e00 100644 --- a/src/tests/ctest_buffer.c +++ b/src/tests/ctest_buffer.c @@ -25,7 +25,7 @@ static void test_create_ref_unref(void) ctest_test("buffer created", a != NULL); ctest_test("un-referenced", refobject_unref(a) == 0); - a = buffer_new_simple(); + a = refobject_new(buffer_t); ctest_test("buffer created", a != NULL); ctest_test("un-referenced", refobject_unref(a) == 0); @@ -80,10 +80,10 @@ static void test_userdata(void) static void test_associated(void) { - refobject_t a; + refobject_base_t *a; buffer_t *b; - a = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, REFOBJECT_NULL); + a = refobject_new(refobject_base_t); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); @@ -102,7 +102,7 @@ static void test_empty(void) const char *string; int ret; - a = buffer_new_simple(); + a = refobject_new(buffer_t); ctest_test("buffer created", a != NULL); ret = buffer_get_data(a, &data, &length); @@ -147,7 +147,7 @@ static void test_string(void) const char *string = NULL; int ret; - a = buffer_new_simple(); + a = refobject_new(buffer_t); ctest_test("buffer created", a != NULL); ctest_test("pushed string", buffer_push_string(a, hw) == 0); ret = buffer_get_string(a, &string); @@ -182,7 +182,7 @@ static void test_binary(void) size_t length; const void *data; - a = buffer_new_simple(); + a = refobject_new(buffer_t); ctest_test("buffer created", a != NULL); ctest_test("pushed data pattern a", buffer_push_data(a, pattern_a, sizeof(pattern_a)) == 0); @@ -238,7 +238,7 @@ static void test_shift(void) buffer_t *a; const char *pattern = "AABBBCC"; - a = buffer_new_simple(); + a = refobject_new(buffer_t); ctest_test("buffer created", a != NULL); ctest_test("pushed string", buffer_push_string(a, pattern) == 0); @@ -264,7 +264,7 @@ static void test_length(void) const char *match_b = "AABB"; const char *match_c = ""; - a = buffer_new_simple(); + a = refobject_new(buffer_t); ctest_test("buffer created", a != NULL); ctest_test("pushed string", buffer_push_string(a, pattern) == 0); @@ -290,7 +290,7 @@ static void test_printf(void) const char *match_b = ":Hello World!:<-127 >"; const char *match_c = ":Hello World!:<-127 >? +127?"; - a = buffer_new_simple(); + a = refobject_new(buffer_t); ctest_test("buffer created", a != NULL); ctest_test("Set length to match pattern a", buffer_push_printf(a, ":%s:", str) == 0); @@ -310,9 +310,9 @@ static void test_push_buffer(void) const char *pattern = "AABBBCC"; const char *match_a = "AABBBCCAABBBCC"; - a = buffer_new_simple(); + a = refobject_new(buffer_t); ctest_test("buffer a created", a != NULL); - b = buffer_new_simple(); + b = refobject_new(buffer_t); ctest_test("buffer b created", b != NULL); ctest_test("pushed string", buffer_push_string(a, pattern) == 0); diff --git a/src/tests/ctest_refobject.c b/src/tests/ctest_refobject.c index 1f553f6f..36cb292e 100644 --- a/src/tests/ctest_refobject.c +++ b/src/tests/ctest_refobject.c @@ -29,9 +29,9 @@ static void test_ptr(void) static void test_create_ref_unref(void) { - refobject_t a; + refobject_base_t *a; - a = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, REFOBJECT_NULL); + a = refobject_new(refobject_base_t); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ctest_test("referenced", refobject_ref(a) == 0); @@ -39,27 +39,91 @@ static void test_create_ref_unref(void) ctest_test("un-referenced (2 of 2)", refobject_unref(a) == 0); } +static void test_typename(void) +{ + refobject_base_t *a; + const char *typename; + + a = refobject_new(refobject_base_t); + ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); + + typename = REFOBJECT_GET_TYPENAME(a); + ctest_test("got typename", typename != NULL); + ctest_test("typename matches", strcmp(typename, "refobject_base_t") == 0); + + ctest_test("un-referenced", refobject_unref(a) == 0); +} + +static void test_valid(void) +{ + refobject_base_t *a; + + typedef struct { + refobject_base_t __base; + } ctest_test_type_t; + + REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_t); + + ctest_test("NULL is not valid", !REFOBJECT_IS_VALID(REFOBJECT_NULL, refobject_base_t)); + + a = refobject_new(refobject_base_t); + ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); + + ctest_test("is valid", REFOBJECT_IS_VALID(a, refobject_base_t)); + ctest_test("is valid as diffrent type", !REFOBJECT_IS_VALID(a, ctest_test_type_t)); + + ctest_test("un-referenced", refobject_unref(a) == 0); +} + static void test_sizes(void) { refobject_t a; - a = refobject_new(sizeof(refobject_base_t) + 1024, NULL, NULL, NULL, REFOBJECT_NULL); + typedef struct { + refobject_base_t __base; + char padding[1024]; + } ctest_test_type_a_t; + REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_a_t, + REFOBJECT_DEFINE_TYPE_NEW_NOOP() + ); + + typedef struct { + refobject_base_t __base; + char padding[131072]; + } ctest_test_type_b_t; + REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_b_t, + REFOBJECT_DEFINE_TYPE_NEW_NOOP() + ); + + typedef struct { + char padding[sizeof(refobject_base_t) - 1]; + } ctest_test_type_c_t; + REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_c_t, + REFOBJECT_DEFINE_TYPE_NEW_NOOP() + ); + + typedef struct { + char padding[0]; + } ctest_test_type_d_t; + REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_d_t, + REFOBJECT_DEFINE_TYPE_NEW_NOOP() + ); + + a = REFOBJECT_FROM_TYPE(refobject_new(ctest_test_type_a_t)); ctest_test("refobject created with size=sizeof(refobject_base_t) + 1024", !REFOBJECT_IS_NULL(a)); ctest_test("un-referenced", refobject_unref(a) == 0); - a = refobject_new(sizeof(refobject_base_t) + 131072, NULL, NULL, NULL, REFOBJECT_NULL); + a = REFOBJECT_FROM_TYPE(refobject_new(ctest_test_type_b_t)); ctest_test("refobject created with size=sizeof(refobject_base_t) + 131072", !REFOBJECT_IS_NULL(a)); ctest_test("un-referenced", refobject_unref(a) == 0); - if (sizeof(refobject_base_t) >= 1) { - a = refobject_new(sizeof(refobject_base_t) - 1, NULL, NULL, NULL, REFOBJECT_NULL); - ctest_test("refobject created with size=sizeof(refobject_base_t) - 1", REFOBJECT_IS_NULL(a)); - if (!REFOBJECT_IS_NULL(a)) { - ctest_test("un-referenced", refobject_unref(a) == 0); - } + a = REFOBJECT_FROM_TYPE(refobject_new(ctest_test_type_c_t)); + ctest_test("refobject created with size=sizeof(refobject_base_t) - 1", REFOBJECT_IS_NULL(a)); + if (!REFOBJECT_IS_NULL(a)) { + ctest_test("un-referenced", refobject_unref(a) == 0); } - a = refobject_new(0, NULL, NULL, NULL, REFOBJECT_NULL); + a = REFOBJECT_FROM_TYPE(refobject_new(ctest_test_type_d_t)); ctest_test("refobject created with size=0", REFOBJECT_IS_NULL(a)); if (!REFOBJECT_IS_NULL(a)) { ctest_test("un-referenced", refobject_unref(a) == 0); @@ -68,11 +132,11 @@ static void test_sizes(void) static void test_name(void) { - refobject_t a; + refobject_base_t *a; const char *name = "test object name"; const char *ret; - a = refobject_new(sizeof(refobject_base_t), NULL, NULL, name, REFOBJECT_NULL); + a = refobject_new_ext(refobject_base_t, NULL, name, REFOBJECT_NULL); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ret = refobject_get_name(a); @@ -84,12 +148,12 @@ static void test_name(void) static void test_userdata(void) { - refobject_t a; + refobject_base_t *a; int tmp = 0; void *userdata = &tmp; void *ret; - a = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, REFOBJECT_NULL); + a = refobject_new(refobject_base_t); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ret = refobject_get_userdata(a); @@ -103,7 +167,7 @@ static void test_userdata(void) ctest_test("un-referenced", refobject_unref(a) == 0); - a = refobject_new(sizeof(refobject_base_t), NULL, userdata, NULL, REFOBJECT_NULL); + a = refobject_new_ext(refobject_base_t, userdata, NULL, REFOBJECT_NULL); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); ret = refobject_get_userdata(a); ctest_test("get userdata", ret == userdata); @@ -115,12 +179,12 @@ static void test_userdata(void) static void test_associated(void) { - refobject_t a, b; + refobject_base_t *a, *b; - a = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, REFOBJECT_NULL); + a = refobject_new(refobject_base_t); ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); - b = refobject_new(sizeof(refobject_base_t), NULL, NULL, NULL, a); + b = refobject_new_ext(refobject_base_t, NULL, NULL, a); ctest_test("refobject created with associated", !REFOBJECT_IS_NULL(b)); ctest_test("un-referenced (1 of 2)", refobject_unref(b) == 0); @@ -135,22 +199,30 @@ static void test_freecb__freecb(refobject_t self, void **userdata) static void test_freecb(void) { - refobject_t a; + typedef struct { + refobject_base_t __base; + } ctest_test_type_t; + ctest_test_type_t *a; + + REFOBJECT_DEFINE_PRIVATE_TYPE(ctest_test_type_t, + REFOBJECT_DEFINE_TYPE_FREE(test_freecb__freecb), + REFOBJECT_DEFINE_TYPE_NEW_NOOP() + ); test_freecb__called = 0; - a = refobject_new(sizeof(refobject_base_t), test_freecb__freecb, NULL, NULL, REFOBJECT_NULL); - ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); - ctest_test("un-referenced", refobject_unref(a) == 0); + a = refobject_new(ctest_test_type_t); + ctest_test("refobject created", a != NULL); + ctest_test("un-referenced", refobject_unref(REFOBJECT_FROM_TYPE(a)) == 0); ctest_test("freecb called", test_freecb__called == 1); test_freecb__called = 0; - a = refobject_new(sizeof(refobject_base_t), test_freecb__freecb, NULL, NULL, REFOBJECT_NULL); - ctest_test("refobject created", !REFOBJECT_IS_NULL(a)); - ctest_test("referenced", refobject_ref(a) == 0); + a = refobject_new(ctest_test_type_t); + ctest_test("refobject created", a != NULL); + ctest_test("referenced", refobject_ref(REFOBJECT_FROM_TYPE(a)) == 0); ctest_test("freecb uncalled", test_freecb__called == 0); - ctest_test("un-referenced (1 of 2)", refobject_unref(a) == 0); + ctest_test("un-referenced (1 of 2)", refobject_unref(REFOBJECT_FROM_TYPE(a)) == 0); ctest_test("freecb uncalled", test_freecb__called == 0); - ctest_test("un-referenced (2 of 2)", refobject_unref(a) == 0); + ctest_test("un-referenced (2 of 2)", refobject_unref(REFOBJECT_FROM_TYPE(a)) == 0); ctest_test("freecb called", test_freecb__called == 1); } @@ -167,6 +239,9 @@ int main (void) test_create_ref_unref(); + test_typename(); + test_valid(); + test_sizes(); test_name();