Add function _init_once for intrusive shared pointer
This commit is contained in:
1 parent
5f0b6b9f26
commit
34c990e259
2 files changed
+69
-10
No files matched your search
@@ -4019,12 +4019,22 @@ TODO: Document shared resource
|
||||
|
||||
This header is for creating intrusive shared pointer.
|
||||
|
||||
#### ISHARED\_INTERFACE(name, type)
|
||||
#### ISHARED\_PTR\_INTERFACE(name, type)
|
||||
|
||||
Extend the definition of the structure of an object of type 'type' by adding the
|
||||
necessary interface to handle it as a shared pointer named 'name'.
|
||||
It shall be put within the structure definition of the object (See example).
|
||||
|
||||
#### ISHARED\_PTR\_STATIC\_INIT(name, type)
|
||||
|
||||
Provide the static initialization value of an object defined with a
|
||||
ISHARED\_PTR\_INTERFACE extra fields. It shall be used only for global
|
||||
variables with the \_init\_once function.
|
||||
|
||||
Usage:
|
||||
|
||||
struct mystruct variable = { ISHARED_PTR_STATIC_INIT(ishared_double, struct mystruct) };
|
||||
|
||||
#### ISHARED\_PTR\_DEF(name, type[, oplist])
|
||||
|
||||
Define the associated methods to handle the shared pointer named 'name'
|
||||
@@ -4060,6 +4070,7 @@ so that the CLEAR method doesn't try to free the objectslike this:
|
||||
|
||||
(NEW(0), DEL(0))
|
||||
|
||||
NEW & DEL operators shall be either both defined, or both disabled.
|
||||
|
||||
Example (dynamic):
|
||||
|
||||
@@ -4116,12 +4127,23 @@ This function is thread safe.
|
||||
|
||||
Allocate a new object, initialize it and return an initialized shared pointer to it.
|
||||
|
||||
The used allocation function is the ALLOC operator.
|
||||
In this case, it is assumed that the DEL operator has not been disabled.
|
||||
The used allocation function is the NEW operator.
|
||||
|
||||
This function is created only if the INIT method is defined in the oplist
|
||||
and if the NEW method has not been disabled in the oplist.
|
||||
|
||||
##### name\_t name\_init\_once(type *object)
|
||||
|
||||
Initialize the new object 'object' and return an initialized shared pointer to it.
|
||||
The INIT operator of 'object' is ensured to be called only once,
|
||||
even if multiple threads try to initialize it at the same time.
|
||||
Once the object is fully cleared, the initialization function may occur once again.
|
||||
|
||||
object shall be a global variable initialized with the ISHARED_PTR_STATIC_INIT macro.
|
||||
|
||||
This function is created only if the INIT method is defined in the oplist
|
||||
and if the NEW method has been disabled in the oplist.
|
||||
|
||||
##### void name\_clear(name\_t shared)
|
||||
|
||||
Clear the shared pointer, releasing ownership of the object
|
||||
|
||||
+44
-7
@@ -46,6 +46,11 @@ M_BEGIN_PROTECTED_CODE
|
||||
atomic_int M_C(name, _cpt)
|
||||
|
||||
|
||||
/* Value of the interface field for static intialization. */
|
||||
#define ISHARED_PTR_STATIC_INIT(name, type) \
|
||||
.M_C(name, _cpt) = ATOMIC_VAR_INIT(0)
|
||||
|
||||
|
||||
/* Define the intrusive shared pointer type and its static inline functions.
|
||||
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
|
||||
#define ISHARED_PTR_DEF(name, ...) \
|
||||
@@ -122,7 +127,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
{ \
|
||||
/* Initialize the type referenced by the pointer */ \
|
||||
if (M_LIKELY (ptr != NULL)) { \
|
||||
atomic_init(&ptr->M_C(name, _cpt), 1); \
|
||||
atomic_init(&ptr->M_C(name, _cpt), 2); \
|
||||
} \
|
||||
return ptr; \
|
||||
} \
|
||||
@@ -131,7 +136,7 @@ M_BEGIN_PROTECTED_CODE
|
||||
M_C(name, _init_set)(shared_t shared) \
|
||||
{ \
|
||||
if (M_LIKELY (shared != NULL)) { \
|
||||
int n = atomic_fetch_add(&(shared->M_C(name, _cpt)), 1); \
|
||||
int n = atomic_fetch_add(&(shared->M_C(name, _cpt)), 2); \
|
||||
(void) n; \
|
||||
} \
|
||||
return shared; \
|
||||
@@ -144,9 +149,41 @@ M_BEGIN_PROTECTED_CODE
|
||||
*ptr = M_C(name, _init_set)(shared); \
|
||||
} \
|
||||
\
|
||||
M_IF_METHOD(INIT, oplist)( \
|
||||
M_IF_DISABLED_METHOD(NEW, oplist) \
|
||||
( /* Nothing to do */, M_IF_METHOD(INIT, oplist) \
|
||||
( \
|
||||
( \
|
||||
/* This function is only for static object */ \
|
||||
static inline shared_t \
|
||||
M_C(name, _init_once)(type *shared) \
|
||||
{ \
|
||||
if (M_LIKELY (shared != NULL)) { \
|
||||
/* Pretty much like atomic_add, except the first one increment by 1, others by 2 */ \
|
||||
int o = atomic_load(&(shared->M_C(name, _cpt))); \
|
||||
int n; \
|
||||
do { \
|
||||
n = o + 1 + (o != 0); \
|
||||
} while (!atomic_compare_exchange_strong(&(shared->M_C(name, _cpt)), &o, n)); \
|
||||
if (o == 0) { \
|
||||
/* Partial initialization: _cpt is odd */ \
|
||||
/* Call the INIT function once */ \
|
||||
M_CALL_INIT(oplist, *shared); \
|
||||
/* Finish initialization: _cpt is even */ \
|
||||
atomic_fetch_add(&(shared->M_C(name, _cpt)), 1); \
|
||||
} else if ( (o&1) != 0) { \
|
||||
/* Not fully initialized yet: wait for initialization */ \
|
||||
m_core_backoff_ct bkoff; \
|
||||
m_core_backoff_init(bkoff); \
|
||||
/* Wait for _cpt to be _even */ \
|
||||
while ((atomic_load(&(shared->M_C(name, _cpt)))&1) != 0 ) { \
|
||||
m_core_backoff_wait(bkoff); \
|
||||
} \
|
||||
} \
|
||||
M_ASSERT( (atomic_load(&(shared->M_C(name, _cpt)))&1) == 0); \
|
||||
} \
|
||||
return shared; \
|
||||
} \
|
||||
, \
|
||||
/* This function is only for dynamic object */ \
|
||||
static inline shared_t \
|
||||
M_C(name, _init_new)(void) \
|
||||
{ \
|
||||
@@ -156,17 +193,17 @@ M_BEGIN_PROTECTED_CODE
|
||||
return NULL; \
|
||||
} \
|
||||
M_CALL_INIT(oplist, *ptr); \
|
||||
atomic_init (&ptr->M_C(name, _cpt), 1); \
|
||||
atomic_init (&ptr->M_C(name, _cpt), 2); \
|
||||
return ptr; \
|
||||
} \
|
||||
, /* End of INIT */) \
|
||||
/* End of NEW */) \
|
||||
, /* End of INIT */) \
|
||||
\
|
||||
static inline void \
|
||||
M_C(name, _clear)(shared_t shared) \
|
||||
{ \
|
||||
if (shared != NULL) { \
|
||||
if (atomic_fetch_sub(&(shared->M_C(name, _cpt)), 1) == 1) { \
|
||||
if (atomic_fetch_sub(&(shared->M_C(name, _cpt)), 2) == 2) { \
|
||||
M_CALL_CLEAR(oplist, *shared); \
|
||||
M_IF_DISABLED_METHOD(DEL, oplist)(, M_CALL_DEL(oplist, shared);) \
|
||||
} \
|
||||
|
||||
Reference in new issue
Block a user