Remove obsolete m-i-shared.h header

This commit is contained in:
Patrick Pelissier committed 2025-05-07 21:57:53 +02:00
1 parent 7e8cb07a6c
commit 25dcdeed69
4 files changed
-588

No files matched your search

-179
View File
@@ -197,7 +197,6 @@ Finally, headers for compatibility with non C11 compilers:
The following headers are obsolete and will be removed in the next major release:
* [m-concurrent.h](#m-concurrent): header for transforming a container into a concurrent container (thread safe),
* [m-i-shared.h](#m-i-shared): header for creating intrusive shared pointer of generic type (Thread Safe).
* [m-mempool.h](#m-mempool): header for creating specialized & fast memory allocator,
Each containers define their iterators (if it is meaningful).
@@ -5085,184 +5084,6 @@ Create a new shared object initialized with its `INIT_SET` operator on the given
This method is created only if the `INIT_SET` operator is defined.
_________________
### M-I-SHARED
> [!NOTE]
> This header is obsolete: M-SHARED-PTR should be used instead.
This header is for creating intrusive shared pointer.
#### `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 (provided that the interface is used as the first element of the structure):
```C
struct mystruct variable = { ISHARED_PTR_STATIC_INIT(ishared_double, struct mystruct) };
```
#### `ISHARED_PTR_STATIC_DESIGNATED_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.
It uses designated initializers to set the right fields.
Usage:
```C
struct mystruct variable = {ISHARED_PTR_STATIC_DESIGNATED_INIT(ishared_double, struct mystruct) };
```
#### `ISHARED_PTR_DEF(name, type[, oplist])`
#### `ISHARED_PTR_DEF_AS(name, name_t, type[, oplist])`
Define the associated methods to handle the shared pointer named `name`
as `static inline` functions.
A shared pointer is a mechanism to keep tracks of all `users` of an object
and performs an automatic destruction of the object whenever all users release
their need on this object.
The destruction of the object is thread safe and occurs when the last user
of the object releases it. The destruction of the object implies:
* calling the `CLEAR` operator to clear the object,
* calling the `DEL` operator to release the memory used by the object
(if the method has not been disabled).
The object oplist is expected to have the following operators (`CLEAR` and `DEL`),
otherwise default methods are used. If there is no given oplist, the default
operators are also used. The created methods will use the operators to init, set
and clear the contained object.
There are designed to work with buffers with policy `BUFFER_PUSH_INIT_POP_MOVE`
to send a shared pointer across multiple threads.
It is recommended to use the intrusive shared pointer over the standard one if
possible. They are faster and cleaner.
The default is to use heap allocated entities, which are allocated by `NEW` and
freed by `DEL`.
It can be used for statically allocated entities. However, in this case,
you shall disable the operator `NEW` and `DEL` when expanding the oplist
so that the destruction doesn't try to free the objects, like this:
```C
(NEW(0), DEL(0))
```
`NEW` and `DEL` operators shall be either both defined, or both disabled.
`ISHARED_PTR_DEF_AS` is the same as `ISHARED_PTR_DEF` except the name of the type `name_t`
is provided.
Example (dynamic):
```C
typedef struct mystruct_s {
ISHARED_PTR_INTERFACE(ishared_mystruct, struct mystruct_s);
char *message;
} mystruct_t;
static inline void mystruct_init(mystruct_t *p) { p->message = NULL; }
static inline void mystruct_clear(mystruct_t *p) { free(p->message); }
ISHARED_PTR_DEF(ishared_mystruct, mystruct_t, (INIT(mystruct_init), CLEAR(mystruct_clear M_IPTR)))
void f(void) {
mystruct_t *p = ishared_mystruct_init_new();
p->message = strdup ("Hello");
buffer_mystruct_push(g_buff1, p);
buffer_mystruct_push(g_buff2, p);
ishared_mystruct_clear(p);
}
```
#### Created types
The following types are automatically defined by the previous definition macro if not provided by the user:
##### `name_t`
It will define name_t as a pointer to shared counted object.
This is a synonymous to a pointer to the object.
#### Specialized methods
The following specialized methods are automatically created by the previous definition macro:
##### `name_t name_init(type *object)`
Return a shared pointer to `object` which owns `object`.
It initializes the private fields of `object` handling the shared pointer,
returning the same pointer to the object from a value point of view,
but with the shared pointer field initialized.
As a consequence, the shared pointer part of `object` shall not have been initialized yet.
The other part of `object` may or may not be initialized before calling this method.
##### `name_t name_init_set(name_t shared)`
Return a new shared pointer to the same object than the one pointed by `shared`,
incrementing the ownership of the object.
This function is thread safe.
##### `name_t name_init_new(void)`
Allocate a new object, initialize it and return an initialized shared pointer to it.
The used allocation function is the `NEW` operator.
This method is only created if the `INIT` and `NEW` methods are provided and not disabled.
##### `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 method is only created if the `INIT` and `NEW` methods are provided and not disabled.
##### `void name_clear(name_t shared)`
Clear the `shared` pointer, releasing ownership of the object
and destroying the shared object if no longer
any other `shared` pointers own it.
This function is thread safe.
##### `void name_clear_ptr(name_t *shared)`
Clear the shared pointer `*shared`, releasing ownership of the object
and destroying the shared object if no longer
any other `shared` pointers own it.
This function is thread safe.
Afterwards, `*shared` is set to NULL.
##### `void name_set(name_t *shared1, name_t shared2)`
Update the shared pointer `*shared1` to point to the same object than
the shared pointer `shared2`.
Destroy the shared object pointed by `*shared1` if no longer any other shared
pointers own it, set the shared pointer `shared` to the same object
than the one pointed by `src`.
This function is thread safe.
_________________
### M-I-LIST
-1
View File
@@ -15,7 +15,6 @@
#include "m-generic.h"
#include "m-genint.h"
#include "m-i-list.h"
#include "m-i-shared.h"
#include "m-list.h"
#include "m-mempool.h"
#include "m-prioqueue.h"
-258
View File
@@ -1,258 +0,0 @@
/*
* M*LIB - INTRUSIVE SHARED PTR Module
*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef MSTARLIB_I_SHARED_PTR_H
#define MSTARLIB_I_SHARED_PTR_H
#include "m-core.h"
#include "m-atomic.h"
#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L
#warning The header m-i-shared.h is obsolete. Use m-shared-ptr header instead.
#endif
M_BEGIN_PROTECTED_CODE
/* Define the oplist of a intrusive shared pointer.
USAGE: ISHARED_OPLIST(name [, oplist_of_the_type]) */
#define M_ISHARED_PTR_OPLIST(...) \
M_ISHAR3D_PTR_OPLIST_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((__VA_ARGS__, M_BASIC_OPLIST), \
(__VA_ARGS__ )))
/* Interface to add to a structure to allow intrusive support.
name: name of the intrusive shared pointer.
type: name of the type of the structure (aka. struct test_s) - not used currently.
NOTE: There can be only one interface of this kind in a type! */
#define M_ISHARED_PTR_INTERFACE(name, type) \
atomic_int M_F(name, _cpt)
/* Value of the interface field for static initialization (Uses C99 designated element). */
#define M_ISHARED_PTR_STATIC_DESIGNATED_INIT(name, type) \
.M_F(name, _cpt) = M_ATOMIC_VAR_INIT(0)
/* Value of the interface field for static initialization (Uses C89 designated element). */
#define M_ISHARED_PTR_STATIC_INIT(name, type) \
M_ATOMIC_VAR_INIT(0)
/* Define the intrusive shared pointer type and its M_INLINE functions.
USAGE: ISHARED_PTR_DEF(name, type, [, oplist]) */
#define M_ISHARED_PTR_DEF(name, ...) \
M_ISHARED_PTR_DEF_AS(name, M_F(name,_t), __VA_ARGS__)
/* Define the intrusive shared pointer type and its M_INLINE functions
as the name name_t
USAGE: ISHARED_PTR_DEF_AS(name, name_t, type, [, oplist]) */
#define M_ISHARED_PTR_DEF_AS(name, name_t, ...) \
M_BEGIN_PROTECTED_CODE \
M_ISHAR3D_PTR_DEF_P1(M_IF_NARGS_EQ1(__VA_ARGS__) \
((name, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)(), name_t ), \
(name, __VA_ARGS__ , name_t ))) \
M_END_PROTECTED_CODE
/*****************************************************************************/
/******************************** INTERNAL ***********************************/
/*****************************************************************************/
// Deferred evaluation
#define M_ISHAR3D_PTR_OPLIST_P1(arg) M_ISHAR3D_PTR_OPLIST_P2 arg
/* Validation of the given oplist */
#define M_ISHAR3D_PTR_OPLIST_P2(name, oplist) \
M_IF_OPLIST(oplist)(M_ISHAR3D_PTR_OPLIST_P3, M_ISHAR3D_PTR_OPLIST_FAILURE)(name, oplist)
/* Prepare a clean compilation failure */
#define M_ISHAR3D_PTR_OPLIST_FAILURE(name, oplist) \
((M_LIB_ERROR(ARGUMENT_OF_ISHARED_PTR_OPLIST_IS_NOT_AN_OPLIST, name, oplist)))
// Define the oplist
#define M_ISHAR3D_PTR_OPLIST_P3(name, oplist) ( \
INIT(M_INIT_DEFAULT), \
INIT_SET(API_4(M_F(name, _init_set))), \
SET(M_F(name, _set) M_IPTR), \
CLEAR(M_F(name, _clear)), \
RESET(M_F(name, _reset) M_IPTR), \
NAME(name), \
TYPE(M_F(name, _ct)), GENTYPE(struct M_F(name,_s)*), \
OPLIST(oplist), \
SUBTYPE(M_F(name, _subtype_ct)) \
)
/******************************** INTERNAL ***********************************/
// Deferred evaluation
#define M_ISHAR3D_PTR_DEF_P1(arg) M_ID( M_ISHAR3D_PTR_DEF_P2 arg )
/* Validate the oplist before going further */
#define M_ISHAR3D_PTR_DEF_P2(name, type, oplist, shared_t) \
M_IF_OPLIST(oplist)(M_ISHAR3D_PTR_DEF_P3, M_ISHAR3D_PTR_DEF_FAILURE)(name, type, oplist, shared_t)
/* Stop processing with a compilation failure */
#define M_ISHAR3D_PTR_DEF_FAILURE(name, type, oplist, shared_t) \
M_STATIC_FAILURE(M_LIB_NOT_AN_OPLIST, "(ISHARED_PTR_DEF): the given argument is not a valid oplist: " #oplist)
#define M_ISHAR3D_PTR_DEF_P3(name, type, oplist, shared_t) \
M_ISHAR3D_PTR_DEF_TYPE(name, type, oplist, shared_t) \
M_CHECK_COMPATIBLE_OPLIST(name, 1, type, oplist) \
M_ISHAR3D_PTR_DEF_CORE(name, type, oplist, shared_t) \
/* Define the types */
#define M_ISHAR3D_PTR_DEF_TYPE(name, type, oplist, shared_t) \
\
/* The shared pointer is only a pointer to the type */ \
typedef type *shared_t; \
\
/* Define internal types for oplist */ \
typedef shared_t M_F(name, _ct); \
typedef type M_F(name, _subtype_ct); \
/* Define the core functions */
#define M_ISHAR3D_PTR_DEF_CORE(name, type, oplist, shared_t) \
\
M_INLINE shared_t \
M_F(name, _init)(type *ptr) \
{ \
/* Initialize the type referenced by the pointer */ \
if (M_LIKELY (ptr != NULL)) { \
atomic_init(&ptr->M_F(name, _cpt), 2); \
} \
return ptr; \
} \
\
M_INLINE shared_t \
M_F(name, _init_set)(shared_t shared) \
{ \
if (M_LIKELY (shared != NULL)) { \
int n = atomic_fetch_add(&(shared->M_F(name, _cpt)), 2); \
(void) n; \
} \
return shared; \
} \
\
M_IF_METHOD(INIT, oplist)( \
M_IF_DISABLED_METHOD(NEW, oplist) \
( \
/* This function is only for static object */ \
M_INLINE shared_t \
M_F(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_F(name, _cpt))); \
int n; \
do { \
n = o + 1 + (o != 0); \
} while (!atomic_compare_exchange_strong(&(shared->M_F(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_F(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_F(name, _cpt)))&1) != 0 ) { \
m_core_backoff_wait(bkoff); \
} \
} \
M_ASSERT( (atomic_load(&(shared->M_F(name, _cpt)))&1) == 0); \
} \
return shared; \
} \
, \
/* This function is only for dynamic object */ \
M_INLINE shared_t \
M_F(name, _init_new)(void) \
{ \
type *ptr = M_CALL_NEW(oplist, type); \
if (M_UNLIKELY_NOMEM (ptr == NULL)) { \
M_MEMORY_FULL(type, 1); \
} \
M_CALL_INIT(oplist, *ptr); \
atomic_init (&ptr->M_F(name, _cpt), 2); \
return ptr; \
} \
/* End of NEW */) \
, /* End of INIT */) \
\
M_INLINE void \
M_F(name, _clear)(shared_t shared) \
{ \
if (shared != NULL) { \
if (atomic_fetch_sub(&(shared->M_F(name, _cpt)), 2) == 2) { \
M_CALL_CLEAR(oplist, *shared); \
M_IF_DISABLED_METHOD(DEL, oplist)(, M_CALL_DEL(oplist, shared);) \
} \
} \
} \
\
M_INLINE void \
M_F(name, _clear_ptr)(shared_t *shared) \
{ \
M_ASSERT(shared != NULL); \
M_F(name, _clear)(*shared); \
*shared = NULL; \
} \
\
M_INLINE void \
M_F(name, _reset)(shared_t *shared) \
{ \
M_F(name, _clear)(*shared); \
*shared = NULL; \
} \
\
M_INLINE void \
M_F(name, _set)(shared_t *ptr, shared_t shared) \
{ \
M_ASSERT (ptr != NULL); \
if (M_LIKELY (*ptr != shared)) { \
M_F(name, _clear)(*ptr); \
*ptr = M_F(name, _init_set)(shared); \
} \
} \
\
M_END_PROTECTED_CODE
/******************************** INTERNAL ***********************************/
#if M_USE_SMALL_NAME
#define ISHARED_PTR_OPLIST M_ISHARED_PTR_OPLIST
#define ISHARED_PTR_INTERFACE M_ISHARED_PTR_INTERFACE
#define ISHARED_PTR_STATIC_DESIGNATED_INIT M_ISHARED_PTR_STATIC_DESIGNATED_INIT
#define ISHARED_PTR_STATIC_INIT M_ISHARED_PTR_STATIC_INIT
#define ISHARED_PTR_DEF M_ISHARED_PTR_DEF
#define ISHARED_PTR_DEF_AS M_ISHARED_PTR_DEF_AS
#endif
#endif
-150
View File
@@ -1,150 +0,0 @@
/*
* Copyright (c) 2017-2025, Patrick Pelissier
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* + Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* + Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test-obj.h"
#include "m-i-shared.h"
#include "m-thread.h"
#include "coverage.h"
typedef struct ishared_s {
ISHARED_PTR_INTERFACE(ishared1, struct ishared_s);
ISHARED_PTR_INTERFACE(ishared2, struct ishared_s);
int data[100];
} ishared_t[1];
static bool ishared_init_sleep = false;
static void ishared_init_data(struct ishared_s *x)
{
for(int i = 0 ; i < 100; i++)
x->data[i] = i * i;
if (ishared_init_sleep) {
// Slow down init
m_thread_sleep(100);
}
}
static void ishared_test(struct ishared_s *x)
{
for(int i = 0 ; i < 100; i++) {
assert (x->data[i] == i*i);
}
}
START_COVERAGE
ISHARED_PTR_DEF(ishared1, struct ishared_s, (INIT(API_2(ishared_init_data))))
ISHARED_PTR_DEF(ishared2, struct ishared_s, (INIT(API_2(ishared_init_data)), NEW(0), DEL(0)) )
END_COVERAGE
/*ISHARED_PTR_DEF_AS(SharedDouble, SharedDouble, double) */
static void test_single(void)
{
ishared1_t p1, p2;
p1 = ishared1_init_new();
ishared_test(p1);
p2 = ishared1_init_set(p1);
ishared_test(p2);
ishared1_clear(p1);
ishared_test(p2);
p1 = ishared1_init(NULL);
ishared1_set(&p1, p2);
ishared1_reset(&p2);
assert(p2 == NULL);
ishared_test(p1);
ishared1_clear(p1);
p1 = ishared1_init_set(p2);
assert(p1 == NULL);
ishared1_clear(p1);
ishared1_clear(p2);
struct ishared_s *x = (struct ishared_s *) malloc(sizeof (struct ishared_s));
assert(x != NULL);
ishared_init_data(x);
p1 = ishared1_init(x);
ishared_test(p1);
ishared1_clear(p1);
}
static struct ishared_s g_var = {
ISHARED_PTR_STATIC_INIT(ishared1, struct ishared_s),
ISHARED_PTR_STATIC_INIT(ishared2, struct ishared_s),
{ 0 }
};
static void test_static(void)
{
ishared2_t p1, p2;
p1 = ishared2_init_once(NULL);
assert(p1 == NULL);
p1 = ishared2_init_once(&g_var);
ishared_test(p1);
p2 = ishared2_init_once(&g_var);
ishared_test(p2);
ishared2_clear(p1);
ishared_test(p2);
ishared2_clear(p2);
}
#define MAX_THREAD 128
#define MAX_VAR 5
#define VAL(x) { ISHARED_PTR_STATIC_INIT(ishared1, struct ishared_s), ISHARED_PTR_STATIC_INIT(ishared2, struct ishared_s), { 0 } }
static struct ishared_s g_tab[MAX_VAR] = {
M_MAP_C(VAL, M_SEQ(1, MAX_VAR))
};
static void func(void *arg)
{
int id = (int)(intptr_t) arg;
int v = id % MAX_VAR;
ishared2_t p = ishared2_init_once(&g_tab[v]);
for(int i = 0; i < 100; i++) {
ishared_test(p);
}
ishared2_clear(p);
}
static void test_shared(void)
{
m_thread_t id[MAX_THREAD];
ishared_init_sleep = true;
for(int i = 0; i < MAX_THREAD; i++) {
m_thread_create(id[i], func, (void*) (intptr_t) i);
}
for(int i = 0; i < MAX_THREAD; i++) {
m_thread_join(id[i]);
}
ishared_init_sleep = false;
}
int main(void)
{
test_single();
test_static();
test_shared();
exit(0);
}