#ifndef PMIX_OBJECT_H
#define PMIX_OBJECT_H
#include "src/include/pmix_config.h"
#include "pmix_common.h"
#include <assert.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
BEGIN_C_DECLS
#if PMIX_ENABLE_DEBUG
# define PMIX_OBJ_MAGIC_ID ((0xdeafbeedULL << 32) + 0xdeafbeedULL)
#endif
#define PMIX_NEW_HAS_ARITY_HELPER(_1, _2, N, ...) N
#define PMIX_NEW_HAS_ARITY_IMPL(...) \
PMIX_NEW_HAS_ARITY_HELPER(__VA_ARGS__)
#define PMIX_CONSTRUCT_HAS_ARITY_HELPER(_1, _2, _3, N, ...) N
#define PMIX_CONSTRUCT_HAS_ARITY_IMPL(...) \
PMIX_CONSTRUCT_HAS_ARITY_HELPER(__VA_ARGS__)
#define PMIX_NEW_HAS_ARGS_SOURCE() TMA, NO_TMA, ERROR
#define PMIX_CONSTRUCT_HAS_ARGS_SOURCE() TMA, NO_TMA, ERROR, ERROR
#define PMIX_OBJ_HAS_ARGS(...) \
PMIX_NEW_HAS_ARITY_IMPL(__VA_ARGS__, PMIX_NEW_HAS_ARGS_SOURCE())
#define PMIX_CONSTRUCT_HAS_ARGS(...) \
PMIX_CONSTRUCT_HAS_ARITY_IMPL(__VA_ARGS__, PMIX_CONSTRUCT_HAS_ARGS_SOURCE())
#define PMIX_NEW_DISAMBIGUATE2(has_args, ...) \
PMIX_NEW_ ## has_args (__VA_ARGS__)
#define PMIX_NEW_DISAMBIGUATE(has_args, ...) \
PMIX_NEW_DISAMBIGUATE2(has_args, __VA_ARGS__)
#define PMIX_CONSTRUCT_DISAMBIGUATE2(has_args, ...) \
PMIX_CONSTRUCT_ ## has_args (__VA_ARGS__)
#define PMIX_CONSTRUCT_DISAMBIGUATE(has_args, ...) \
PMIX_CONSTRUCT_DISAMBIGUATE2(has_args, __VA_ARGS__)
typedef struct pmix_object_t pmix_object_t;
typedef struct pmix_class_t pmix_class_t;
typedef void (*pmix_construct_t)(pmix_object_t *);
typedef void (*pmix_destruct_t)(pmix_object_t *);
typedef struct pmix_tma {
void *(*tma_malloc)(struct pmix_tma *, size_t);
void *(*tma_calloc)(struct pmix_tma *, size_t, size_t);
void *(*tma_realloc)(struct pmix_tma *, void *, size_t);
char *(*tma_strdup)(struct pmix_tma *, const char *s);
void *(*tma_memmove)(struct pmix_tma *tma, const void *src, size_t n);
void (*tma_free)(struct pmix_tma *, void *);
void *data_context;
void **data_ptr;
} pmix_tma_t;
static inline void *pmix_tma_malloc(pmix_tma_t *tma, size_t size)
{
if (NULL != tma) {
return tma->tma_malloc(tma, size);
} else {
return malloc(size);
}
}
static inline void *pmix_tma_calloc(pmix_tma_t *tma, size_t nmemb, size_t size)
{
if (NULL != tma) {
return tma->tma_calloc(tma, nmemb, size);
} else {
return calloc(nmemb, size);
}
}
static inline void *pmix_tma_realloc(pmix_tma_t *tma, void *ptr, size_t size)
{
if (NULL != tma) {
return tma->tma_realloc(tma, ptr, size);
} else {
return realloc(ptr, size);
}
}
static inline char *pmix_tma_strdup(pmix_tma_t *tma, const char *src)
{
if (NULL != tma) {
return tma->tma_strdup(tma, src);
} else {
return strdup(src);
}
}
static inline void pmix_tma_free(pmix_tma_t *tma, void *ptr)
{
if (NULL != tma) {
tma->tma_free(tma, ptr);
} else {
free(ptr);
}
}
struct pmix_class_t {
const char *cls_name;
pmix_class_t *cls_parent;
pmix_construct_t cls_construct;
pmix_destruct_t cls_destruct;
int cls_initialized;
int cls_depth;
pmix_construct_t *cls_construct_array;
pmix_destruct_t *cls_destruct_array;
size_t cls_sizeof;
};
PMIX_EXPORT extern int pmix_class_init_epoch;
#if PMIX_ENABLE_DEBUG
# define PMIX_OBJ_STATIC_INIT(BASE_CLASS) \
{ \
.obj_magic_id = PMIX_OBJ_MAGIC_ID, \
.obj_class = PMIX_CLASS(BASE_CLASS), \
.obj_lock = PTHREAD_MUTEX_INITIALIZER, \
.obj_reference_count = 1, \
.obj_tma = { \
.tma_malloc = NULL, \
.tma_calloc = NULL, \
.tma_realloc = NULL, \
.tma_strdup = NULL, \
.tma_memmove = NULL, \
.tma_free = NULL, \
.data_context = NULL, \
.data_ptr = NULL \
}, \
.cls_init_file_name = __FILE__, \
.cls_init_lineno = __LINE__ \
}
#else
# define PMIX_OBJ_STATIC_INIT(BASE_CLASS) \
{ \
.obj_class = PMIX_CLASS(BASE_CLASS), \
.obj_lock = PTHREAD_MUTEX_INITIALIZER, \
.obj_reference_count = 1, \
.obj_tma = { \
.tma_malloc = NULL, \
.tma_calloc = NULL, \
.tma_realloc = NULL, \
.tma_strdup = NULL, \
.tma_memmove = NULL, \
.tma_free = NULL, \
.data_context = NULL, \
.data_ptr = NULL \
} \
}
#endif
struct pmix_object_t {
#if PMIX_ENABLE_DEBUG
uint64_t obj_magic_id;
#endif
pthread_mutex_t obj_lock;
pmix_class_t *obj_class;
int32_t obj_reference_count;
pmix_tma_t obj_tma;
#if PMIX_ENABLE_DEBUG
const char *cls_init_file_name;
int cls_init_lineno;
#endif
};
#define PMIX_CLASS(NAME) (&(NAME##_class))
#define PMIX_CLASS_INSTANCE(NAME, PARENT, CONSTRUCTOR, DESTRUCTOR) \
pmix_class_t NAME##_class = {#NAME, \
PMIX_CLASS(PARENT), \
(pmix_construct_t) CONSTRUCTOR, \
(pmix_destruct_t) DESTRUCTOR, \
0, \
0, \
NULL, \
NULL, \
sizeof(NAME)}
#define PMIX_CLASS_DECLARATION(NAME) extern pmix_class_t NAME##_class
static inline pmix_object_t *pmix_obj_new_tma(pmix_class_t *cls, pmix_tma_t *tma);
#if PMIX_ENABLE_DEBUG
static inline pmix_object_t *pmix_obj_new_debug_tma(pmix_class_t *type, pmix_tma_t *tma,
const char *file, int line)
{
pmix_object_t *object = pmix_obj_new_tma(type, tma);
if (NULL != object) {
object->obj_magic_id = PMIX_OBJ_MAGIC_ID;
object->cls_init_file_name = file;
object->cls_init_lineno = line;
}
return object;
}
#define PMIX_NEW_NO_TMA(type) \
((type *)pmix_obj_new_debug_tma(PMIX_CLASS(type), NULL, __FILE__, __LINE__))
#define PMIX_NEW_TMA(type, tma) \
((type *)pmix_obj_new_debug_tma(PMIX_CLASS(type), (tma), __FILE__, __LINE__))
#else
#define PMIX_NEW_NO_TMA(type) ((type *)pmix_obj_new_tma(PMIX_CLASS(type), NULL))
#define PMIX_NEW_TMA(type, tma) ((type *)pmix_obj_new_tma(PMIX_CLASS(type), (tma)))
#endif
#define PMIX_NEW(...) \
PMIX_NEW_DISAMBIGUATE(PMIX_OBJ_HAS_ARGS(__VA_ARGS__), __VA_ARGS__)
#if PMIX_ENABLE_DEBUG
# define PMIX_RETAIN(object) \
do { \
assert(NULL != ((pmix_object_t *) (object))->obj_class); \
assert(PMIX_OBJ_MAGIC_ID == ((pmix_object_t *) (object))->obj_magic_id); \
pmix_obj_update((pmix_object_t *) (object), 1); \
assert(((pmix_object_t *) (object))->obj_reference_count >= 0); \
} while (0)
#else
# define PMIX_RETAIN(object) pmix_obj_update((pmix_object_t *) (object), 1)
#endif
#if PMIX_ENABLE_DEBUG
# define PMIX_REMEMBER_FILE_AND_LINENO(OBJECT, FILE, LINENO) \
do { \
((pmix_object_t *) (OBJECT))->cls_init_file_name = FILE; \
((pmix_object_t *) (OBJECT))->cls_init_lineno = LINENO; \
} while (0)
# define PMIX_SET_MAGIC_ID(OBJECT, VALUE) \
do { \
((pmix_object_t *) (OBJECT))->obj_magic_id = (VALUE); \
} while (0)
#else
# define PMIX_REMEMBER_FILE_AND_LINENO(OBJECT, FILE, LINENO)
# define PMIX_SET_MAGIC_ID(OBJECT, VALUE)
#endif
#if PMIX_ENABLE_DEBUG
# define PMIX_RELEASE(object) \
do { \
pmix_object_t *_obj = (pmix_object_t *) object; \
assert(NULL != _obj->obj_class); \
assert(PMIX_OBJ_MAGIC_ID == _obj->obj_magic_id); \
if (0 == pmix_obj_update(_obj, -1)) { \
PMIX_SET_MAGIC_ID((object), 0); \
pmix_obj_run_destructors(_obj); \
PMIX_REMEMBER_FILE_AND_LINENO(object, __FILE__, __LINE__); \
if (NULL != _obj->obj_tma.tma_free) { \
pmix_tma_free(&_obj->obj_tma, object); \
} \
else { \
free(object); \
} \
object = NULL; \
} \
} while (0)
#else
# define PMIX_RELEASE(object) \
do { \
pmix_object_t *_obj = (pmix_object_t *) object; \
if (0 == pmix_obj_update(_obj, -1)) { \
pmix_obj_run_destructors(_obj); \
if (NULL != _obj->obj_tma.tma_free) { \
pmix_tma_free(&_obj->obj_tma, object); \
} \
else { \
free(object); \
} \
object = NULL; \
} \
} while (0)
#endif
static inline void pmix_obj_construct_tma(pmix_object_t *obj, pmix_tma_t *tma)
{
if (NULL == tma) {
obj->obj_tma.tma_malloc = NULL;
obj->obj_tma.tma_calloc = NULL;
obj->obj_tma.tma_realloc = NULL;
obj->obj_tma.tma_strdup = NULL;
obj->obj_tma.tma_memmove = NULL;
obj->obj_tma.tma_free = NULL;
obj->obj_tma.data_context = NULL;
obj->obj_tma.data_ptr = NULL;
} else {
obj->obj_tma = *tma;
}
}
#define PMIX_CONSTRUCT_INTERNAL_TMA(object, type, t) \
do { \
PMIX_SET_MAGIC_ID((object), PMIX_OBJ_MAGIC_ID); \
if (pmix_class_init_epoch != (type)->cls_initialized) { \
pmix_class_initialize((type)); \
} \
((pmix_object_t *) (object))->obj_class = (type); \
((pmix_object_t *) (object))->obj_reference_count = 1; \
pmix_obj_construct_tma(((pmix_object_t *) (object)), (t)); \
pmix_obj_run_constructors((pmix_object_t *) (object)); \
PMIX_REMEMBER_FILE_AND_LINENO(object, __FILE__, __LINE__); \
} while (0)
#define PMIX_CONSTRUCT_TMA(object, type, t) \
do { \
PMIX_CONSTRUCT_INTERNAL_TMA((object), PMIX_CLASS(type), (t)); \
} while (0)
#define PMIX_CONSTRUCT_NO_TMA(object, type) \
do { \
PMIX_CONSTRUCT_TMA(object, type, NULL); \
} while (0)
#define PMIX_CONSTRUCT(...) \
PMIX_CONSTRUCT_DISAMBIGUATE(PMIX_CONSTRUCT_HAS_ARGS(__VA_ARGS__), __VA_ARGS__)
#if PMIX_ENABLE_DEBUG
# define PMIX_DESTRUCT(object) \
do { \
assert(PMIX_OBJ_MAGIC_ID == ((pmix_object_t *) (object))->obj_magic_id); \
PMIX_SET_MAGIC_ID((object), 0); \
pmix_obj_run_destructors((pmix_object_t *) (object)); \
PMIX_REMEMBER_FILE_AND_LINENO(object, __FILE__, __LINE__); \
} while (0)
#else
# define PMIX_DESTRUCT(object) \
do { \
pmix_obj_run_destructors((pmix_object_t *) (object)); \
PMIX_REMEMBER_FILE_AND_LINENO(object, __FILE__, __LINE__); \
} while (0)
#endif
PMIX_CLASS_DECLARATION(pmix_object_t);
PMIX_EXPORT void pmix_class_initialize(pmix_class_t *cls);
PMIX_EXPORT int pmix_class_finalize(void);
static inline void pmix_obj_run_constructors(pmix_object_t *object)
{
pmix_construct_t *cls_construct;
assert(NULL != object->obj_class);
cls_construct = object->obj_class->cls_construct_array;
while (NULL != *cls_construct) {
(*cls_construct)(object);
cls_construct++;
}
}
static inline void pmix_obj_run_destructors(pmix_object_t *object)
{
pmix_destruct_t *cls_destruct;
assert(NULL != object->obj_class);
cls_destruct = object->obj_class->cls_destruct_array;
while (NULL != *cls_destruct) {
(*cls_destruct)(object);
cls_destruct++;
}
}
static inline pmix_object_t *pmix_obj_new_tma(pmix_class_t *cls, pmix_tma_t *tma)
{
pmix_object_t *object;
assert(cls->cls_sizeof >= sizeof(pmix_object_t));
object = (pmix_object_t *) pmix_tma_malloc(tma, cls->cls_sizeof);
if (pmix_class_init_epoch != cls->cls_initialized) {
pmix_class_initialize(cls);
}
if (NULL != object) {
#if PMIX_ENABLE_DEBUG
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
# if PMIX_HAVE_PTHREAD_MUTEX_ERRORCHECK_NP
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
# elif PMIX_HAVE_PTHREAD_MUTEX_ERRORCHECK
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
# endif
pthread_mutex_init(&object->obj_lock, &attr);
pthread_mutexattr_destroy(&attr);
#else
pthread_mutex_init(&object->obj_lock, NULL);
#endif
object->obj_class = cls;
object->obj_reference_count = 1;
if (NULL == tma) {
object->obj_tma.tma_malloc = NULL;
object->obj_tma.tma_calloc = NULL;
object->obj_tma.tma_realloc = NULL;
object->obj_tma.tma_strdup = NULL;
object->obj_tma.tma_free = NULL;
object->obj_tma.data_context = NULL;
object->obj_tma.data_ptr = NULL;
} else {
object->obj_tma = *tma;
}
pmix_obj_run_constructors(object);
}
return object;
}
static inline int pmix_obj_update(pmix_object_t *object, int inc) __pmix_attribute_always_inline__;
static inline int pmix_obj_update(pmix_object_t *object, int inc)
{
int ret = pthread_mutex_lock(&object->obj_lock);
if (ret == EDEADLK) {
errno = ret;
perror("pthread_mutex_lock()");
abort();
}
ret = (object->obj_reference_count += inc);
pthread_mutex_unlock(&object->obj_lock);
return ret;
}
static inline pmix_tma_t *
pmix_obj_get_tma(
pmix_object_t *obj
) {
if (obj->obj_tma.tma_malloc) {
return &obj->obj_tma;
}
return NULL;
}
END_C_DECLS
#endif