added cmsis_core, furi, mlib and nanobake implemented basic app structure from furi implemented basic placeholder apps
256 lines
16 KiB
C
256 lines
16 KiB
C
/*
|
|
* M*LIB - INTRUSIVE SHARED PTR Module
|
|
*
|
|
* Copyright (c) 2017-2023, 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"
|
|
|
|
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 intialization (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 intialization (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)), \
|
|
OPLIST(oplist), \
|
|
SUBTYPE(M_F(name, _subtype_ct)) \
|
|
)
|
|
|
|
|
|
/******************************** INTERNAL ***********************************/
|
|
|
|
// Deferred evaluatioin
|
|
#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(sizeof(type)); \
|
|
return NULL; \
|
|
} \
|
|
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
|