eĿlipsis
a language independent preprocessor
 
Loading...
Searching...
No Matches
ellipsis-once.h File Reference

Simple TU initialization and cleanup handling with dependencies. More...

#include <stdlib.h>
#include <threads.h>
Include dependency graph for ellipsis-once.h:

Go to the source code of this file.

Macros

#define _ONCE_AT_QUICK_EXIT_I(NAME, ...)
 
#define _ONCE_ATEXIT_I(NAME, ...)
 
#define _ONCE_DECLARE(NAME)
 
#define _ONCE_DEFINE_I(NAME, ...)
 
#define _ONCE_DEFINE_STRONG_I(NAME, ...)
 
#define _ONCE_DEPEND_I(NAME, ...)
 
#define _ONCE_DEPEND_WEAK_I(NAME, ...)
 
#define ONCE_AT_QUICK_EXIT(...)   _ONCE_AT_QUICK_EXIT(__VA_ARGS__)
 Define optional cleanup code that goes with feature named NAME for quick_exit
 
#define ONCE_ATEXIT(...)   _ONCE_ATEXIT(__VA_ARGS__)
 Define optional cleanup code that goes with feature named NAME for atexit
 
#define ONCE_DEFINE(...)   _ONCE_DEFINE(__VA_ARGS__)
 Define the initialization code that goes with feature named NAME
 
#define ONCE_DEFINE_STRONG(...)   _ONCE_DEFINE_STRONG(__VA_ARGS__)
 Similar to ONCE_DEFINE but triggers unconditionally if the platform supports this.
 
#define ONCE_DEPEND(...)   _ONCE_DEPEND(__VA_ARGS__)
 Declare that this TU depends on a initialization and cleanup feature named NAME
 
#define ONCE_DEPEND_WEAK(...)   _ONCE_DEPEND_WEAK(__VA_ARGS__)
 Similar to ONCE_DEPEND but only triggers if ONCE_DEFINE_STRONG is not able to guarantee unconditional initialization.
 
Internal macros
#define _ONCE_AT_QUICK_EXIT(...)   _ONCE_AT_QUICK_EXIT_I(__VA_ARGS__ __VA_OPT__(,) __UNIT__,)
 
#define _ONCE_AT_QUICK_EXIT_CALLBACK(NAME)   NAME ∷_Once∷at_quick_exit∷callback
 
#define _ONCE_AT_QUICK_EXIT_POINTER(NAME)   NAME ∷_Once∷at_quick_exit∷pointer
 
#define _ONCE_ATEXIT(...)   _ONCE_ATEXIT_I(__VA_ARGS__ __VA_OPT__(,) __UNIT__,)
 
#define _ONCE_ATEXIT_CALLBACK(NAME)   NAME ∷_Once∷atexit∷callback
 
#define _ONCE_ATEXIT_POINTER(NAME)   NAME ∷_Once∷atexit∷pointer
 
#define _ONCE_CALLBACK(NAME)   NAME ∷_Once∷init∷callback
 
#define _ONCE_DEFINE(...)   _ONCE_DEFINE_I(__VA_ARGS__ __VA_OPT__(,) __UNIT__,)
 
#define _ONCE_DEFINE_STRONG(...)   _ONCE_DEFINE_STRONG_I(__VA_ARGS__ __VA_OPT__(,) __UNIT__,)
 
#define _ONCE_DEPEND(...)   _ONCE_DEPEND_I(__VA_ARGS__ __VA_OPT__(,) __UNIT__,)
 
#define _ONCE_DEPEND_WEAK(...)   _ONCE_DEPEND_WEAK_I(__VA_ARGS__ __VA_OPT__(,) __UNIT__,)
 
#define _ONCE_DOTTY_ARC(A, B)   "ONCE_DEPEND_MARKER: " A " -> " B
 
#define _ONCE_DOTTY_FILE   __FILE__
 
#define _ONCE_DOTTY_NODE(A, ...)   "ONCE_DEPEND_MARKER: " A " [" #__VA_ARGS__ "]"
 
#define _ONCE_INIT(NAME)   NAME ∷_Once∷init
 
#define _ONCE_IS_STRONG   extern
 
#define _ONCE_STRONG_FLAG(NAME)   NAME ∷_Once∷strong
 
#define _ONCE_STRONG_INIT
 
#define _ONCE_USER(NAME)   NAME ∷_Once∷init∷user
 

Detailed Description

Simple TU initialization and cleanup handling with dependencies.

This is a header only library as a small wrapper around call_once and atexit. It has just a handful user interfaces. For triggered dependencies these are

For unconditional dependencies (that should always run) there are

To fully work ONCE_DEFINE_STRONG needs compiler magic, here we use a gnu feature. ONCE_DEPEND_WEAK then triggers a dependency just as ONCE_DEPEND but only if running code unconditionally at startup is not supported. Otherwise this is a no-op.

Currently there is no detection of dependency cycles, but a graph can be extracted from the strings of the binary. It should only have cycles between a symbolic dependency and the TU in which is found.

There is a script called dot_extract.sh that filters the string of the executable to obtain the graph, which basically looks as follows:

echo "digraph \"$1\" {"
strings $1 | sed '
/ONCE_DEPEND_MARKER:/!d
s!ONCE_DEPEND_MARKER:!\t!
s![a-zA-Z_][-+./a-zA-Z0-9_]*!"&"!g
**'
**echo "}"
static char const strings[]
A big char array that contains all the strings together with their null termination.
Definition ellipsis-xml-entities.c:40

Macro Definition Documentation

◆ _ONCE_AT_QUICK_EXIT

#define _ONCE_AT_QUICK_EXIT (   ...)    _ONCE_AT_QUICK_EXIT_I(__VA_ARGS__ __VA_OPT__(,) __UNIT__,)

◆ _ONCE_AT_QUICK_EXIT_CALLBACK

#define _ONCE_AT_QUICK_EXIT_CALLBACK (   NAME)    NAME ∷_Once∷at_quick_exit∷callback

◆ _ONCE_AT_QUICK_EXIT_I

#define _ONCE_AT_QUICK_EXIT_I (   NAME,
  ... 
)

◆ _ONCE_AT_QUICK_EXIT_POINTER

#define _ONCE_AT_QUICK_EXIT_POINTER (   NAME)    NAME ∷_Once∷at_quick_exit∷pointer

◆ _ONCE_ATEXIT

#define _ONCE_ATEXIT (   ...)    _ONCE_ATEXIT_I(__VA_ARGS__ __VA_OPT__(,) __UNIT__,)

◆ _ONCE_ATEXIT_CALLBACK

#define _ONCE_ATEXIT_CALLBACK (   NAME)    NAME ∷_Once∷atexit∷callback

◆ _ONCE_ATEXIT_I

#define _ONCE_ATEXIT_I (   NAME,
  ... 
)

◆ _ONCE_ATEXIT_POINTER

#define _ONCE_ATEXIT_POINTER (   NAME)    NAME ∷_Once∷atexit∷pointer

◆ _ONCE_CALLBACK

#define _ONCE_CALLBACK (   NAME)    NAME ∷_Once∷init∷callback

◆ _ONCE_DECLARE

#define _ONCE_DECLARE (   NAME)

◆ _ONCE_DEFINE

#define _ONCE_DEFINE (   ...)    _ONCE_DEFINE_I(__VA_ARGS__ __VA_OPT__(,) __UNIT__,)

◆ _ONCE_DEFINE_I

#define _ONCE_DEFINE_I (   NAME,
  ... 
)

◆ _ONCE_DEFINE_STRONG

#define _ONCE_DEFINE_STRONG (   ...)    _ONCE_DEFINE_STRONG_I(__VA_ARGS__ __VA_OPT__(,) __UNIT__,)

◆ _ONCE_DEFINE_STRONG_I

#define _ONCE_DEFINE_STRONG_I (   NAME,
  ... 
)

◆ _ONCE_DEPEND

#define _ONCE_DEPEND (   ...)    _ONCE_DEPEND_I(__VA_ARGS__ __VA_OPT__(,) __UNIT__,)

◆ _ONCE_DEPEND_I

#define _ONCE_DEPEND_I (   NAME,
  ... 
)

◆ _ONCE_DEPEND_WEAK

#define _ONCE_DEPEND_WEAK (   ...)    _ONCE_DEPEND_WEAK_I(__VA_ARGS__ __VA_OPT__(,) __UNIT__,)

◆ _ONCE_DEPEND_WEAK_I

#define _ONCE_DEPEND_WEAK_I (   NAME,
  ... 
)

◆ _ONCE_DOTTY_ARC

#define _ONCE_DOTTY_ARC (   A,
 
)    "ONCE_DEPEND_MARKER: " A " -> " B

◆ _ONCE_DOTTY_FILE

#define _ONCE_DOTTY_FILE   __FILE__

◆ _ONCE_DOTTY_NODE

#define _ONCE_DOTTY_NODE (   A,
  ... 
)    "ONCE_DEPEND_MARKER: " A " [" #__VA_ARGS__ "]"

◆ _ONCE_INIT

#define _ONCE_INIT (   NAME)    NAME ∷_Once∷init

◆ _ONCE_IS_STRONG

#define _ONCE_IS_STRONG   extern

◆ _ONCE_STRONG_FLAG

#define _ONCE_STRONG_FLAG (   NAME)    NAME ∷_Once∷strong

◆ _ONCE_STRONG_INIT

#define _ONCE_STRONG_INIT

◆ _ONCE_USER

#define _ONCE_USER (   NAME)    NAME ∷_Once∷init∷user

◆ ONCE_AT_QUICK_EXIT

#define ONCE_AT_QUICK_EXIT (   ...)    _ONCE_AT_QUICK_EXIT(__VA_ARGS__)

Define optional cleanup code that goes with feature named NAME for quick_exit

Use this as a prefix to a function definition such as in

// do your stuff
}
#define ONCE_AT_QUICK_EXIT(...)
Define optional cleanup code that goes with feature named NAME for quick_exit
Definition ellipsis-once.h:292

This creates some symbols with internal linkage in the current TU. For this to work ONCE_DEFINE(toto) has to be defined in the same TU. The other way around, this is not mandatory: ONCE_DEFINE(toto) can work without having ONCE_AT_QUICK_EXIT(toto).

Technically this creates a functions and a function pointer is then used with at_quick_exit. All implicitly defined symbols have internal linkage.

◆ ONCE_ATEXIT

#define ONCE_ATEXIT (   ...)    _ONCE_ATEXIT(__VA_ARGS__)

Define optional cleanup code that goes with feature named NAME for atexit

Use this as a prefix to a function definition such as in

ONCE_ATEXIT(toto) {
// do your stuff
}
#define ONCE_ATEXIT(...)
Define optional cleanup code that goes with feature named NAME for atexit
Definition ellipsis-once.h:269

This creates some symbols with internal linkage in the current TU. For this to work ONCE_DEFINE(toto) has to be defined in the same TU. The other way around, this is not mandatory: ONCE_DEFINE(toto) can work without having ONCE_ATEXIT(toto).

Technically this creates a functions and a function pointer is then used with atexit. All implicitly defined symbols have internal linkage.

◆ ONCE_DEFINE

#define ONCE_DEFINE (   ...)    _ONCE_DEFINE(__VA_ARGS__)

Define the initialization code that goes with feature named NAME

Use this as a prefix to a function definition such as in

ONCE_DEFINE(toto) {
ONCE_DEPEND(tata);
// do your stuff
}
#define ONCE_DEFINE(...)
Define the initialization code that goes with feature named NAME
Definition ellipsis-once.h:246
#define ONCE_DEPEND(...)
Declare that this TU depends on a initialization and cleanup feature named NAME
Definition ellipsis-once.h:220

This creates some symbols with internal linkage and one external symbol, but with a naming that is not portable between different implementations.

Technically this creates separate functions and a once_flag that are then used with call_once.

Use this, even in the same TU, as ONCE_DEPEND(toto) to be sure that your initialization code is guaranteed to have run before any of your other code.

◆ ONCE_DEFINE_STRONG

#define ONCE_DEFINE_STRONG (   ...)    _ONCE_DEFINE_STRONG(__VA_ARGS__)

Similar to ONCE_DEFINE but triggers unconditionally if the platform supports this.

◆ ONCE_DEPEND

#define ONCE_DEPEND (   ...)    _ONCE_DEPEND(__VA_ARGS__)

Declare that this TU depends on a initialization and cleanup feature named NAME

Use this in block scope to refer to the one external symbol that can be used by other TU to indicate a dependency of this TU here.

The external name is not portable between different implementations.

Under the hood that is a simple function call of a void function.

This can be placed anywhere where a declaration is allowed.

◆ ONCE_DEPEND_WEAK

#define ONCE_DEPEND_WEAK (   ...)    _ONCE_DEPEND_WEAK(__VA_ARGS__)

Similar to ONCE_DEPEND but only triggers if ONCE_DEFINE_STRONG is not able to guarantee unconditional initialization.

This can be placed anywhere where a declaration is allowed.