Add support of C++ for workers.

This commit is contained in:
Patrick Pelissier committed 2017-12-16 20:54:17 +01:00
1 parent 9020baf364
commit 8aa3c86ce9
3 files changed
+59 -9

No files matched your search

+2 -2
View File
@@ -3350,8 +3350,8 @@ by an asynchronous worker.
cannot use return / goto to go outside the flow).
'input' is the list of input variables of the 'core' block within "( )".
'output' is the list of output variables of the 'core' block within "( )".
This macro needs either GCC (for nested function) or CLANG (for blocks) to
work.
This macro needs either GCC (for nested function) or CLANG (for blocks)
or a C++11 compiler (for lambda and functional) to work.
NOTE1: Even if nested functions are used for GCC, it doesn't generate
a trampoline and the stack doesn't need to be executable.
+55 -5
View File
@@ -49,32 +49,52 @@
So you need to compile with "-fblocks" and link with "-lBlocksRuntime"
if you use clang & want to use the MACRO version.
if C++, you will use Lambda function (and std::function) instead
(We don't support pre-C++11 compiler).
Otherwise we go for nested function for the MACRO version.
*/
#if defined(__has_extension) && !defined(WORKER_CLANG_BLOCK)
#ifdef __cplusplus
# define WORKER_CPP_FUNCTION 1
# include <functional>
#elif defined(__has_extension) && !defined(WORKER_CLANG_BLOCK)
# if __has_extension(blocks)
# define WORKER_CLANG_BLOCK 1
# define WORKER_CLANG_BLOCK 1
# endif
#endif
#ifndef WORKER_CLANG_BLOCK
# define WORKER_CLANG_BLOCK 0
#endif
#ifndef WORKER_CPP_FUNCTION
# define WORKER_CPP_FUNCTION 0
#endif
/* Control that not both options are selected at the same times.
Note: there are not really incompatible, but if we use C++ we shall go to
lambda directly (there is no need to support blocks)! */
#if WORKER_CLANG_BLOCK && WORKER_CPP_FUNCTION
# error WORKER_CPP_FUNCTION and WORKER_CLANG_BLOCK are both defined (not supported).
#endif
/* This type defines a work order */
typedef struct {
typedef struct work_order_s {
struct worker_block_s *block;
void * data;
void (*func) (void *data);
#if WORKER_CLANG_BLOCK
void (^blockFunc)(void *data);
#endif
#if WORKER_CPP_FUNCTION
std::function<void(void*)> function;
#endif
} worker_order_t;
/* Define the macros needed to initialize an order.
* * MACRO to be used to send an empty order to stop the thread
* * MACRO to complete the not-used fields
*/
#if WORKER_CLANG_BLOCK
#if WORKER_CLANG_BLOCK || WORKER_CPP_FUNCTION
# define WORKER_EMPTY_ORDER { NULL, NULL, NULL, NULL }
# define WORKER_EXTRA_ORDER , NULL
#else
@@ -83,7 +103,7 @@ typedef struct {
#endif
/* This type defines a worker */
typedef struct {
typedef struct worker_thread_s {
m_thread_t id;
} worker_thread_t;
@@ -150,6 +170,12 @@ workeri_thread(void *arg)
if (w.func == NULL)
w.blockFunc(w.data);
else
#endif
#if WORKER_CPP_FUNCTION
//printf ("Running %s f=%p b=%p\n", (w.function == NULL) ? "Lambda" : "Function", w.func, w.blockFunc);
if (w.function)
w.function(w.data);
else
#endif
w.func(w.data);
worker_queue_pop_release(g->queue_g);
@@ -242,6 +268,25 @@ worker_spawn_block(worker_t g, worker_block_t block, void (^func)(void *data), v
}
#endif
#if WORKER_CPP_FUNCTION
/* Spawn or not the given work order to workers,
or do it ourself if no worker is available */
static inline void
worker_spawn_function(worker_t g, worker_block_t block, std::function<void(void *data)> func, void *data)
{
const worker_order_t w = { block, data, NULL, func };
if (M_UNLIKELY (!worker_queue_full_p(g->queue_g))
&& worker_queue_push (g->queue_g, w) == true) {
//printf ("Sending data to thread as block: %p (block: %d / %d)\n", data, block->num_spawn, block->num_terminated_spawn);
atomic_fetch_add (&block->num_spawn, 1);
return;
}
//printf ("Running data ourself as block: %p\n", data);
/* No thread available. Call the function ourself */
func (data);
}
#endif
/* Wait for all work orders to be finished */
static inline void
worker_sync(worker_block_t block)
@@ -271,12 +316,17 @@ worker_count(worker_t g)
WORKER_DEF_DATA(_input, _output) \
WORKER_DEF_SUBBLOCK(_input, _output, _core) \
worker_spawn_block ((_worker), (_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
#elif WORKER_CPP_FUNCTION
// TODO: Explicit pass all arguments by reference.
#define WORKER_SPAWN(_worker, _block, _input, _core, _output) \
worker_spawn_function ((_worker), (_block), [&](void *param) {(void)param ; _core } , NULL)
#else
#define WORKER_SPAWN(_worker, _block, _input, _core, _output) \
WORKER_DEF_DATA(_input, _output) \
WORKER_DEF_SUBFUNC(_input, _output, _core) \
worker_spawn ((_worker), (_block), WORKER_SPAWN_SUBFUNC_NAME, &WORKER_SPAWN_DATA_NAME)
#endif
#define WORKER_SPAWN_STRUCT_NAME M_C(worker_data_s_, __LINE__)
#define WORKER_SPAWN_DATA_NAME M_C(worker_data_, __LINE__)
#define WORKER_SPAWN_SUBFUNC_NAME M_C(worker_subfunc_, __LINE__)
+2 -2
View File
@@ -31,7 +31,7 @@ struct fib2_s {
int x, n;
};
static void subfunc_1 (void *data) {
struct fib2_s *f = data;
struct fib2_s *f = M_ASSIGN_CAST (struct fib2_s *, data);
f->x = fib (f->n );
}
static int fib(int n)
@@ -58,7 +58,7 @@ static void test1(void)
worker_clear(w_g);
}
#if defined(__GNUC__) && (!defined(__clang__) || WORKER_CLANG_BLOCK)
#if defined(__GNUC__) && (!defined(__clang__) || WORKER_CLANG_BLOCK || WORKER_CPP_FUNCTION)
/* The macro version will generate warnings about shadow variables.
There is no way to avoid this. */