diff --git a/Makefile.am b/Makefile.am index d3deaa3..ce1c4eb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -16,9 +16,14 @@ pkginclude_HEADERS = \ include/igloo/resolver.h \ include/igloo/sock.h \ include/igloo/thread.h \ - include/igloo/timing.h + include/igloo/timing.h \ + include/igloo/ro.h \ + include/igloo/types.h \ + include/igloo/typedef.h -libigloo_la_SOURCES = src/libigloo.c +libigloo_la_SOURCES = \ + src/libigloo.c \ + src/ro.c libigloo_la_LIBADD = \ avl/libiceavl.la \ httpp/libicehttpp.la \ diff --git a/include/igloo/igloo.h b/include/igloo/igloo.h index 9355e79..4750bec 100644 --- a/include/igloo/igloo.h +++ b/include/igloo/igloo.h @@ -1,4 +1,5 @@ -/* Copyright (C) 2018 Marvin Scholz +/* Copyright (C) 2018 Marvin Scholz + * Copyright (C) 2018 Philipp "ph3-der-loewe" Schafft * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -29,6 +30,24 @@ extern "C" { /* Put stuff here */ +#include "ro.h" + +/* + * This initializes libigloo. This MUST BE called before any + * other functions can be called. + * + * Returns a refobject on success or igloo_RO_NULL on failure. + * This can be called multiple times (e.g. by the application + * and by the libraries it uses independently). + * + * The library is deinitialized when the last reference + * to a returned object is gone. This happens by + * calling igloo_ro_unref() on the last reference. + * + * All igloo_ro_*() functions can be used on this object. + */ +igloo_ro_t igloo_initialize(void); + #ifdef __cplusplus } #endif diff --git a/include/igloo/log.h b/include/igloo/log.h index 3016323..e5cdb07 100644 --- a/include/igloo/log.h +++ b/include/igloo/log.h @@ -47,7 +47,6 @@ extern "C" { #define IO_BUFFER_TYPE _IOLBF #endif -void igloo_log_initialize(void); int igloo_log_open_file(FILE *file); int igloo_log_open(const char *filename); int igloo_log_open_with_buffer(const char *filename, int size); @@ -60,7 +59,6 @@ int igloo_log_set_archive_timestamp(int id, int value); void igloo_log_flush(int log_id); void igloo_log_reopen(int log_id); void igloo_log_close(int log_id); -void igloo_log_shutdown(void); void igloo_log_write(int log_id, unsigned priority, const char *cat, const char *func, const char *fmt, ...); diff --git a/include/igloo/resolver.h b/include/igloo/resolver.h index c27521d..d55f2ec 100644 --- a/include/igloo/resolver.h +++ b/include/igloo/resolver.h @@ -43,9 +43,6 @@ extern "C" { ** */ -void igloo_resolver_initialize(void); -void igloo_resolver_shutdown(void); - char *igloo_resolver_getname(const char *ip, char *buff, int len); char *igloo_resolver_getip(const char *name, char *buff, int len); diff --git a/include/igloo/ro.h b/include/igloo/ro.h new file mode 100644 index 0000000..ae429bf --- /dev/null +++ b/include/igloo/ro.h @@ -0,0 +1,137 @@ +/* Copyright (C) 2018 Marvin Scholz + * Copyright (C) 2018 Philipp "ph3-der-loewe" Schafft + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _LIBIGLOO__RO_H_ +#define _LIBIGLOO__RO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "types.h" +#include "thread.h" + +/* Type used for callback called then the object is actually freed + * That is once all references to it are gone. + * + * This function must not try to deallocate or alter self. + */ +typedef void (*igloo_ro_free_t)(igloo_ro_t self); + +/* Type used for callback called then the object is created + * using the generic igloo_ro_new(). + * + * Additional parameters passed to igloo_ro_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 igloo_ro_unref() + * is called internally to clear the object. + */ +typedef int (*igloo_ro_new_t)(igloo_ro_t self, const igloo_ro_type_t *type, va_list ap); + +/* Meta type used to defined types. + * DO NOT use any of the members in here directly! + */ + +/* ---[ PRIVATE ]--- */ +/* + * Those types are defined here as they must be known to the compiler. + * Nobody should ever try to access them directly. + */ +struct igloo_ro_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() */ + igloo_ro_free_t type_freecb; + /* Callback to be callback by igloo_ro_new() */ + igloo_ro_new_t type_newcb; +}; +struct igloo_ro_base_tag { + /* Type of the object */ + const igloo_ro_type_t * type; + /* Reference counter */ + size_t refc; + /* Mutex for igloo_ro_*(). */ + igloo_mutex_t lock; + /* Name of the object. */ + char * name; + /* Associated objects */ + igloo_ro_t associated; +}; +int igloo_ro_new__return_zero(igloo_ro_t self, const igloo_ro_type_t *type, va_list ap); +/* ---[ END PRIVATE ]--- */ + +#ifdef igloo_HAVE_TYPE_ATTRIBUTE_TRANSPARENT_UNION +#define igloo_RO__GETBASE(x) (((igloo_ro_t)(x)).subtype__igloo_ro_base_t) +#define igloo_RO_NULL ((igloo_ro_t)(igloo_ro_base_t*)NULL) +#define igloo_RO_IS_NULL(x) (igloo_RO__GETBASE((x)) == NULL) +#define igloo_RO_TO_TYPE(x,type) (igloo_RO_IS_VALID((x),type) ? NULL : ((igloo_ro_t)(x)).subtype__ ## type) +#else +#define igloo_RO__GETBASE(x) ((igloo_ro_base_t*)(x)) +#define igloo_RO_NULL NULL +#define igloo_RO_IS_NULL(x) ((x) == NULL) +#define igloo_RO_TO_TYPE(x,type) ((type*)(x)) +#endif + +#define igloo_RO_GET_TYPE(x) (igloo_RO__GETBASE((x)) == NULL ? NULL : igloo_RO__GETBASE((x))->type) +#define igloo_RO_GET_TYPENAME(x) (igloo_RO_GET_TYPE((x)) == NULL ? NULL : igloo_RO_GET_TYPE((x))->type_name) +#define igloo_RO_IS_VALID(x,type) (!igloo_RO_IS_NULL((x)) && igloo_RO_GET_TYPE((x)) == (igloo_ro__type__ ## type)) + +/* Create a new refobject + * The type argument gives the type for the new object, + * the name for the object is given by name, and + * the associated refobject is given by associated. + */ + +igloo_ro_t igloo_ro_new__raw(const igloo_ro_type_t *type, const char *name, igloo_ro_t associated); +#define igloo_ro_new_raw(type, name, associated) igloo_RO_TO_TYPE(igloo_ro_new__raw((igloo_ro__type__ ## type), (name), (associated)), type) + +igloo_ro_t igloo_ro_new__simple(const igloo_ro_type_t *type, const char *name, igloo_ro_t associated, ...); +#define igloo_ro_new(type, ...) igloo_RO_TO_TYPE(igloo_ro_new__simple((igloo_ro__type__ ## type), NULL, igloo_RO_NULL, ## __VA_ARGS__), type) +#define igloo_ro_new_ext(type, name, associated, ...) igloo_RO_TO_TYPE(igloo_ro_new__simple((igloo_ro__type__ ## type), (name), (associated), ## __VA_ARGS__), type) + +/* This increases the reference counter of the object */ +int igloo_ro_ref(igloo_ro_t self); +/* This decreases the reference counter of the object. + * If the object's reference counter reaches zero the object is freed. + */ +int igloo_ro_unref(igloo_ro_t self); + +/* This gets the object's name */ +const char * igloo_ro_get_name(igloo_ro_t self); + +/* This gets the object's associated object. */ +igloo_ro_t igloo_ro_get_associated(igloo_ro_t self); +int igloo_ro_set_associated(igloo_ro_t self, igloo_ro_t associated); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/igloo/sock.h b/include/igloo/sock.h index 2404f88..b171bba 100644 --- a/include/igloo/sock.h +++ b/include/igloo/sock.h @@ -81,8 +81,6 @@ struct iovec #define igloo_sock_connect(h, p) igloo_sock_connect_wto(h, p, 0) /* Misc socket functions */ -void igloo_sock_initialize(void); -void igloo_sock_shutdown(void); char *igloo_sock_get_localip(char *buff, int len); int igloo_sock_error(void); int igloo_sock_recoverable(int error); diff --git a/include/igloo/thread.h b/include/igloo/thread.h index 33beafd..299bb68 100644 --- a/include/igloo/thread.h +++ b/include/igloo/thread.h @@ -140,11 +140,6 @@ typedef igloo_mutex_t igloo_spin_t; #define igloo_THREAD_DETACHED 1 #define igloo_THREAD_ATTACHED 0 -/* init/shutdown of the library */ -void igloo_thread_initialize(void); -void igloo_thread_initialize_with_log_id(int log_id); -void igloo_thread_shutdown(void); - /* creation, destruction, locking, unlocking, signalling and waiting */ igloo_thread_type *igloo_thread_create_c(char *name, void *(*start_routine)(void *), void *arg, int detached, int line, char *file); diff --git a/include/igloo/typedef.h b/include/igloo/typedef.h new file mode 100644 index 0000000..9ca0bac --- /dev/null +++ b/include/igloo/typedef.h @@ -0,0 +1,55 @@ +/* Copyright (C) 2018 Marvin Scholz + * Copyright (C) 2018 Philipp "ph3-der-loewe" Schafft + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _LIBIGLOO__TYPEDEF_H_ +#define _LIBIGLOO__TYPEDEF_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* This header includes only macros needed to define types. + * This header must be included before "types.h" and "ro.h" if used. + */ + +#define igloo_RO_TYPE(type) type * subtype__ ## type; + +#define igloo_RO__CONTROL_VERSION 1 +#define igloo_RO__DEFINE_TYPE(type, suffix, ...) \ +static const igloo_ro_type_t igloo_ro__typedef__ ## type = \ +{ \ + .control_length = sizeof(igloo_ro_type_t), \ + .control_version = igloo_RO__CONTROL_VERSION, \ + .type_length = sizeof(type), \ + .type_name = # type suffix \ + , ## __VA_ARGS__ \ +} + +#define igloo_RO_FORWARD_TYPE(type) extern const igloo_ro_type_t *igloo_ro__type__ ## type +#define igloo_RO_PUBLIC_TYPE(type, ...) igloo_RO__DEFINE_TYPE(type, "", ## __VA_ARGS__); const igloo_ro_type_t * igloo_ro__type__ ## type = &igloo_ro__typedef__ ## type +#define igloo_RO_PRIVATE_TYPE(type, ...) igloo_RO__DEFINE_TYPE(type, " (private)", ## __VA_ARGS__); static const igloo_ro_type_t * igloo_ro__type__ ## type = &igloo_ro__typedef__ ## type +#define igloo_RO_TYPEDECL_FREE(cb) .type_freecb = (cb) +#define igloo_RO_TYPEDECL_NEW(cb) .type_newcb = (cb) +#define igloo_RO_TYPEDECL_NEW_NOOP() .type_newcb = igloo_ro_new__return_zero + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/igloo/types.h b/include/igloo/types.h new file mode 100644 index 0000000..d3bde8b --- /dev/null +++ b/include/igloo/types.h @@ -0,0 +1,71 @@ +/* Copyright (C) 2018 Marvin Scholz + * Copyright (C) 2018 Philipp "ph3-der-loewe" Schafft + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _LIBIGLOO__TYPES_H_ +#define _LIBIGLOO__TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* For NULL */ +#include +/* For size_t and ssize_t */ +#include + +/* Included in case is not yet included */ +#include "typedef.h" + +/* + * This header includes forward declarations for several basic types. + */ + +typedef struct igloo_ro_type_tag igloo_ro_type_t; +typedef struct igloo_ro_base_tag igloo_ro_base_t; +igloo_RO_FORWARD_TYPE(igloo_ro_base_t); + +#ifdef igloo_HAVE_TYPE_ATTRIBUTE_TRANSPARENT_UNION +typedef union __attribute__ ((__transparent_union__)) { + /* Those are libigloo's own types */ + igloo_RO_TYPE(igloo_ro_base_t) + + /* Now we add the current compilation unit's private types if any */ +#ifdef igloo_RO_PRIVATETYPES + igloo_RO_PRIVATETYPES +#endif + + /* Next are the application's types if any */ +#ifdef igloo_RO_APPTYPES + igloo_RO_APPTYPES +#endif + + /* And finnally all the types that are used by dependencies if any */ +#ifdef igloo_RO_LIBTYPES + igloo_RO_LIBTYPES +#endif +} igloo_ro_t; +#else +typedef void * igloo_ro_t; +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/net/sock.c b/net/sock.c index cfb14f2..258ea1f 100644 --- a/net/sock.c +++ b/net/sock.c @@ -58,6 +58,7 @@ #include #include +#include "../src/private.h" /* for older C libraries */ #ifndef AI_NUMERICSERV diff --git a/src/libigloo.c b/src/libigloo.c index 8b13789..55ba916 100644 --- a/src/libigloo.c +++ b/src/libigloo.c @@ -1 +1,76 @@ +/* Copyright (C) 2018 Philipp "ph3-der-loewe" Schafft + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "../include/igloo/typedef.h" +typedef struct igloo_instance_tag igloo_instance_t; + +#define igloo_RO_PRIVATETYPES igloo_RO_TYPE(igloo_instance_t) + +#include "../include/igloo/ro.h" +#include "private.h" + +struct igloo_instance_tag { + igloo_ro_base_t __base; +}; + +static size_t igloo_initialize__refc; + +static void igloo_initialize__free(igloo_ro_t self) +{ + igloo_initialize__refc--; + if (igloo_initialize__refc) + return; + + igloo_resolver_shutdown(); + igloo_sock_shutdown(); + igloo_thread_shutdown(); + igloo_log_shutdown(); +} + +igloo_RO_PRIVATE_TYPE(igloo_instance_t, + igloo_RO_TYPEDECL_FREE(igloo_initialize__free) + ); + +igloo_ro_t igloo_initialize(void) +{ + igloo_instance_t *ret; + char name[128]; + + if (!igloo_initialize__refc) { + igloo_log_initialize(); + igloo_thread_initialize(); + igloo_sock_initialize(); + igloo_resolver_initialize(); + } + + snprintf(name, sizeof(name), "", igloo_initialize__refc); + + ret = igloo_ro_new_raw(igloo_instance_t, name, igloo_RO_NULL); + if (!ret) + return igloo_RO_NULL; + + igloo_initialize__refc++; + + return ret; +} diff --git a/src/ro.c b/src/ro.c new file mode 100644 index 0000000..675d647 --- /dev/null +++ b/src/ro.c @@ -0,0 +1,218 @@ +/* Copyright (C) 2018 Marvin Scholz + * Copyright (C) 2012 Philipp "ph3-der-loewe" Schafft + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +/* This is not static as it is used by igloo_RO_TYPEDECL_NEW_NOOP() */ +int igloo_ro_new__return_zero(igloo_ro_t self, const igloo_ro_type_t *type, va_list ap) +{ + (void)self, (void)type, (void)ap; + return 0; +} + +igloo_RO_PUBLIC_TYPE(igloo_ro_base_t, + igloo_RO_TYPEDECL_NEW_NOOP() + ); + +static inline int check_type(const igloo_ro_type_t *type) +{ + return type->control_length == sizeof(igloo_ro_type_t) && type->control_version == igloo_RO__CONTROL_VERSION && + type->type_length >= sizeof(igloo_ro_base_t); +} + +igloo_ro_t igloo_ro_new__raw(const igloo_ro_type_t *type, const char *name, igloo_ro_t associated) +{ + igloo_ro_base_t *base; + + if (!check_type(type)) + return igloo_RO_NULL; + + base = calloc(1, type->type_length); + if (!base) + return igloo_RO_NULL; + + base->type = type; + base->refc = 1; + + igloo_thread_mutex_create(&(base->lock)); + + if (name) { + base->name = strdup(name); + if (!base->name) { + igloo_ro_unref(base); + return igloo_RO_NULL; + } + } + + if (!igloo_RO_IS_NULL(associated)) { + if (igloo_ro_ref(associated) != 0) { + igloo_ro_unref(base); + return igloo_RO_NULL; + } + + base->associated = associated; + } + + return (igloo_ro_t)base; +} + +igloo_ro_t igloo_ro_new__simple(const igloo_ro_type_t *type, const char *name, igloo_ro_t associated, ...) +{ + igloo_ro_t ret; + int res; + va_list ap; + + if (!check_type(type)) + return igloo_RO_NULL; + + if (!type->type_newcb) + return igloo_RO_NULL; + + ret = igloo_ro_new__raw(type, name, associated); + if (igloo_RO_IS_NULL(ret)) + return igloo_RO_NULL; + + va_start(ap, associated); + res = type->type_newcb(ret, type, ap); + va_end(ap); + + if (res != 0) { + igloo_ro_unref(ret); + return igloo_RO_NULL; + } + + return ret; +} + +int igloo_ro_ref(igloo_ro_t self) +{ + igloo_ro_base_t *base = igloo_RO__GETBASE(self); + + if (!base) + return -1; + + igloo_thread_mutex_lock(&(base->lock)); + base->refc++; + igloo_thread_mutex_unlock(&(base->lock)); + + return 0; +} + +int igloo_ro_unref(igloo_ro_t self) +{ + igloo_ro_base_t *base = igloo_RO__GETBASE(self); + + if (!base) + return -1; + + igloo_thread_mutex_lock(&(base->lock)); + base->refc--; + + if (base->refc) { + igloo_thread_mutex_unlock(&(base->lock)); + return 0; + } + + if (base->type->type_freecb) + base->type->type_freecb(self); + + igloo_ro_unref(base->associated); + + if (base->name) + free(base->name); + + igloo_thread_mutex_unlock(&(base->lock)); + igloo_thread_mutex_destroy(&(base->lock)); + + free(base); + + return 0; +} + +const char * igloo_ro_get_name(igloo_ro_t self) +{ + igloo_ro_base_t *base = igloo_RO__GETBASE(self); + const char *ret; + + if (!base) + return NULL; + + igloo_thread_mutex_lock(&(base->lock)); + ret = base->name; + igloo_thread_mutex_unlock(&(base->lock)); + + return ret; +} + +igloo_ro_t igloo_ro_get_associated(igloo_ro_t self) +{ + igloo_ro_base_t *base = igloo_RO__GETBASE(self); + igloo_ro_t ret; + + if (!base) + return igloo_RO_NULL; + + igloo_thread_mutex_lock(&(base->lock)); + ret = base->associated; + if (!igloo_RO_IS_NULL(ret)) { + if (igloo_ro_ref(ret) != 0) { + igloo_thread_mutex_unlock(&(base->lock)); + return igloo_RO_NULL; + } + } + igloo_thread_mutex_unlock(&(base->lock)); + + return ret; +} + +int igloo_ro_set_associated(igloo_ro_t self, igloo_ro_t associated) +{ + igloo_ro_base_t *base = igloo_RO__GETBASE(self); + igloo_ro_t old; + + if (!base) + return 0; + + /* We can not set ourself to be our associated. */ + if (base == igloo_RO__GETBASE(associated)) + return -1; + + if (!igloo_RO_IS_NULL(associated)) { + if (igloo_ro_ref(associated) != 0) { + /* Could not get a reference on the new associated object. */ + return -1; + } + } + + igloo_thread_mutex_lock(&(base->lock)); + old = base->associated; + base->associated = associated; + igloo_thread_mutex_unlock(&(base->lock)); + + igloo_ro_unref(old); + + return 0; +}