11#define TASK_ARGS_TYPE(name) COARGS_##name
13#define TASK_ARGSDELAY_NAME(name) COARGSDELAY_##name
14#define TASK_ARGSDELAY(name) struct TASK_ARGSDELAY_NAME(name)
16#define TASK_ARGSCOND_NAME(name) COARGSCOND_##name
17#define TASK_ARGSCOND(name) struct TASK_ARGSCOND_NAME(name)
19#define TASK_IFACE_NAME(iface, suffix) COTASKIFACE_##iface##_##suffix
20#define TASK_IFACE_ARGS_TYPE(iface) TASK_IFACE_NAME(iface, ARGS)
21#define TASK_IFACE_ARGS_SIZED_PTR_TYPE(iface) TASK_IFACE_NAME(iface, ARGS_SPTR)
22#define TASK_INDIRECT_TYPE(iface) TASK_IFACE_NAME(iface)
24#define TASK_IFACE_SARGS(iface, ...) \
25 ((TASK_IFACE_ARGS_SIZED_PTR_TYPE(iface)) { \
26 .size = sizeof(TASK_IFACE_ARGS_TYPE(iface)), \
27 .ptr (&(TASK_IFACE_ARGS_TYPE(iface)) { __VA_ARGS__ }) \
30#define DEFINE_TASK_INTERFACE(iface, argstruct) \
31 typedef TASK_ARGS_STRUCT(argstruct) TASK_IFACE_ARGS_TYPE(iface); \
33 TASK_IFACE_ARGS_TYPE(iface) *ptr; \
35 } TASK_IFACE_ARGS_SIZED_PTR_TYPE(iface); \
37 CoTaskFunc _cotask_##iface##_thunk; \
38 } TASK_INDIRECT_TYPE(iface)
40#define DEFINE_TASK_INTERFACE_WITH_BASE(iface, ibase, argstruct) \
42 TASK_IFACE_ARGS_TYPE(ibase) base; \
43 TASK_ARGS_STRUCT(argstruct); \
44 } TASK_IFACE_ARGS_TYPE(iface); \
47 TASK_IFACE_ARGS_SIZED_PTR_TYPE(ibase) base; \
49 TASK_IFACE_ARGS_TYPE(iface) *ptr; \
53 } TASK_IFACE_ARGS_SIZED_PTR_TYPE(iface); \
56 TASK_INDIRECT_TYPE(ibase) base; \
57 CoTaskFunc _cotask_##iface##_thunk; \
58 CoTaskFunc _cotask_##ibase##_thunk; \
60 } TASK_INDIRECT_TYPE(iface) \
62#define TASK_INDIRECT_TYPE_ALIAS(task) TASK_IFACE_NAME(task, HANDLEALIAS)
64#define ARGS (*_cotask_args)
66#define TASK_ARGS_STRUCT(argstruct) struct {struct argstruct ; }
68#define TASK_COMMON_PRIVATE_DECLARATIONS(name) \
69 static void COTASK_##name(TASK_ARGS_TYPE(name) *_cotask_args)
71#define TASK_COMMON_DECLARATIONS(name, argstype, handletype, linkage) \
72 linkage char COTASK_UNUSED_CHECK_##name; \
73 typedef handletype TASK_INDIRECT_TYPE_ALIAS(name); \
74 typedef argstype TASK_ARGS_TYPE(name); \
75 struct TASK_ARGSDELAY_NAME(name) { \
77 TASK_ARGS_TYPE(name) real_args; \
79 struct TASK_ARGSCOND_NAME(name) { \
82 TASK_ARGS_TYPE(name) real_args; \
84 linkage void *COTASKTHUNK_##name(void *arg, size_t arg_size); \
85 linkage void *COTASKTHUNK_DELAYED_##name(void *arg, size_t arg_size); \
86 linkage void *COTASKTHUNK_COND_##name(void *arg, size_t arg_size) \
88#define TASK_COMMON_THUNK_DEFINITIONS(name, linkage) \
89 linkage void *COTASKTHUNK_##name(void *arg, size_t arg_size) { \
90 TASK_ARGS_TYPE(name) args_copy = { }; \
91 memcpy(&args_copy, arg, arg_size); \
92 COTASK_##name(&args_copy); \
95 linkage void *COTASKTHUNKDELAY_##name(void *arg, size_t arg_size) { \
96 TASK_ARGSDELAY(name) args_copy = { }; \
97 memcpy(&args_copy, arg, arg_size); \
98 if (args_copy.delay < 0) return NULL; \
99 WAIT(args_copy.delay); \
100 COTASK_##name(&args_copy.real_args); \
103 linkage void *COTASKTHUNKCOND_##name(void *arg, size_t arg_size) { \
104 TASK_ARGSCOND(name) args_copy = { }; \
105 memcpy(&args_copy, arg, arg_size); \
106 if (WAIT_EVENT(args_copy.event).event_status == CO_EVENT_SIGNALED || args_copy.unconditional) { \
107 COTASK_##name(&args_copy.real_args); \
112#define TASK_COMMON_BEGIN_BODY_DEFINITION(name, linkage) \
113 linkage void COTASK_##name(TASK_ARGS_TYPE(name) *_cotask_args)
115#define DECLARE_TASK_EXPLICIT(name, argstype, handletype, linkage) \
116 TASK_COMMON_DECLARATIONS(name, argstype, handletype, linkage)
118#define DEFINE_TASK_EXPLICIT(name, linkage) \
119 TASK_COMMON_PRIVATE_DECLARATIONS(name); \
120 TASK_COMMON_THUNK_DEFINITIONS(name, linkage) \
121 TASK_COMMON_BEGIN_BODY_DEFINITION(name, linkage)
123#define DECLARE_TASK(name, ...) \
124 MACRO_OVERLOAD_HASARGS(DECLARE_TASK_, __VA_ARGS__)(name, ##__VA_ARGS__)
125#define DECLARE_TASK_1(name, ...) \
126 DECLARE_TASK_EXPLICIT(name, TASK_ARGS_STRUCT(__VA_ARGS__), void, static)
127#define DECLARE_TASK_0(name) DECLARE_TASK_1(name, { })
129#define DECLARE_TASK_WITH_INTERFACE(name, iface) \
130 DECLARE_TASK_EXPLICIT(name, TASK_IFACE_ARGS_TYPE(iface), TASK_INDIRECT_TYPE(iface), static)
132#define DEFINE_TASK(name) \
133 DEFINE_TASK_EXPLICIT(name, static)
135#define TASK(name, ...) \
136 DECLARE_TASK(name, ##__VA_ARGS__); \
139#define TASK_WITH_INTERFACE(name, iface) \
140 DECLARE_TASK_WITH_INTERFACE(name, iface); \
143#define DECLARE_EXTERN_TASK(name, ...) \
144 MACRO_OVERLOAD_HASARGS(DECLARE_EXTERN_TASK_, __VA_ARGS__ )(name, ##__VA_ARGS__)
145#define DECLARE_EXTERN_TASK_1(name, ...) \
146 DECLARE_TASK_EXPLICIT(name, TASK_ARGS_STRUCT(__VA_ARGS__), void, extern)
147#define DECLARE_EXTERN_TASK_0(name) \
148 DECLARE_EXTERN_TASK_1(name, { })
150#define DECLARE_EXTERN_TASK_WITH_INTERFACE(name, iface) \
151 DECLARE_TASK_EXPLICIT(name, TASK_IFACE_ARGS_TYPE(iface), TASK_INDIRECT_TYPE(iface), extern)
153#define DEFINE_EXTERN_TASK(name) \
154 char COTASK_UNUSED_CHECK_##name; \
155 DEFINE_TASK_EXPLICIT(name, extern)
157#define INVOKE_TASK(_task, ...) \
158 _internal_INVOKE_TASK(THIS_SCHED, cosched_new_task, _task, ##__VA_ARGS__)
159#define INVOKE_SUBTASK(_task, ...) \
160 _internal_INVOKE_TASK(THIS_SCHED, cosched_new_subtask, _task, ##__VA_ARGS__)
161#define SCHED_INVOKE_TASK(_sched, _task, ...) \
162 _internal_INVOKE_TASK(_sched, cosched_new_task, _task, ##__VA_ARGS__)
164#define _internal_INVOKE_TASK(sched, task_constructor, name, ...) ( \
165 (void)COTASK_UNUSED_CHECK_##name, \
168 COTASKTHUNK_##name, \
169 (&(TASK_ARGS_TYPE(name)) { __VA_ARGS__ }), \
170 sizeof(TASK_ARGS_TYPE(name)) \
174#define INVOKE_TASK_DELAYED(_delay, _task, ...) \
175 _internal_INVOKE_TASK_DELAYED(THIS_SCHED, cosched_new_task, _delay, _task, ##__VA_ARGS__)
176#define INVOKE_SUBTASK_DELAYED(_delay, _task, ...) \
177 _internal_INVOKE_TASK_DELAYED(THIS_SCHED, cosched_new_subtask, _delay, _task, ##__VA_ARGS__)
178#define SCHED_INVOKE_TASK_DELAYED(_sched, _delay, _task, ...) \
179 _internal_INVOKE_TASK_DELAYED(_sched, cosched_new_task, _delay, _task, ##__VA_ARGS__)
181#define _internal_INVOKE_TASK_DELAYED(sched, task_constructor, _delay, name, ...) ( \
182 (void)COTASK_UNUSED_CHECK_##name, \
185 COTASKTHUNKDELAY_##name, \
186 (&(TASK_ARGSDELAY(name)) { \
187 .real_args = { __VA_ARGS__ }, \
190 sizeof(TASK_ARGSDELAY(name)) \
194#define INVOKE_TASK_WHEN(_event, _task, ...) \
195 _internal_INVOKE_TASK_ON_EVENT(THIS_SCHED, cosched_new_task, false, _event, _task, ##__VA_ARGS__)
196#define INVOKE_SUBTASK_WHEN(_event, _task, ...) \
197 _internal_INVOKE_TASK_ON_EVENT(THIS_SCHED, cosched_new_subtask, false, _event, _task, ##__VA_ARGS__)
198#define SCHED_INVOKE_TASK_WHEN(_sched, _event, _task, ...) \
199 _internal_INVOKE_TASK_ON_EVENT(_sched, cosched_new_task, false, _event, _task, ##__VA_ARGS__)
201#define INVOKE_TASK_AFTER(_event, _task, ...) \
202 _internal_INVOKE_TASK_ON_EVENT(THIS_SCHED, cosched_new_task, true, _event, _task, ## __VA_ARGS__)
203#define INVOKE_SUBTASK_AFTER(_event, _task, ...) \
204 _internal_INVOKE_TASK_ON_EVENT(THIS_SCHED, cosched_new_subtask, true, _event, _task, ## __VA_ARGS__)
205#define SCHED_INVOKE_TASK_AFTER(_sched, _event, _task, ...) \
206 _internal_INVOKE_TASK_ON_EVENT(_sched, cosched_new_task, true, _event, _task, ##__VA_ARGS__)
208#define _internal_INVOKE_TASK_ON_EVENT(sched, task_constructor, is_unconditional, _event, name, ...) ( \
209 (void)COTASK_UNUSED_CHECK_##name, \
212 COTASKTHUNKCOND_##name, \
213 (&(TASK_ARGSCOND(name)) { \
214 .real_args = { __VA_ARGS__ }, \
216 .unconditional = is_unconditional \
218 sizeof(TASK_ARGSCOND(name)) \
222#define CANCEL_TASK_WHEN(_event, _task) INVOKE_TASK_WHEN(_event, _cancel_task_helper, _task)
223#define CANCEL_TASK_AFTER(_event, _task) INVOKE_TASK_AFTER(_event, _cancel_task_helper, _task)
227#define CANCEL_TASK(boxed_task) cotask_cancel(cotask_unbox(boxed_task))
229#define TASK_INDIRECT(iface, task) ( \
230 (void)COTASK_UNUSED_CHECK_##task, \
231 (TASK_INDIRECT_TYPE_ALIAS(task)) { ._cotask_##iface##_thunk = COTASKTHUNK_##task } \
234#define TASK_INDIRECT_INIT(iface, task) \
235 { ._cotask_##iface##_thunk = COTASKTHUNK_##task } \
237#define INVOKE_TASK_INDIRECT_(sched, task_constructor, iface, taskhandle, ...) ( \
240 taskhandle._cotask_##iface##_thunk, \
241 (&(TASK_IFACE_ARGS_TYPE(iface)) { __VA_ARGS__ }), \
242 sizeof(TASK_IFACE_ARGS_TYPE(iface)) \
246#define SCHED_INVOKE_TASK_INDIRECT(_sched, _iface, _handle, ...) \
247 INVOKE_TASK_INDIRECT_(_sched, cosched_new_task, _iface, _handle, ##__VA_ARGS__)
248#define INVOKE_TASK_INDIRECT(_iface, _handle, ...) \
249 INVOKE_TASK_INDIRECT_(THIS_SCHED, cosched_new_task, _iface, _handle, ##__VA_ARGS__)
250#define INVOKE_SUBTASK_INDIRECT(_iface, _handle, ...) \
251 INVOKE_TASK_INDIRECT_(THIS_SCHED, cosched_new_subtask, iface, _handle, ##__VA_ARGS__)
253#define THIS_TASK cotask_box(cotask_active())
254#define TASK_EVENTS(task) cotask_get_events(cotask_unbox(task))
255#define TASK_MALLOC(size) cotask_malloc(cotask_active(), size)
257#define THIS_SCHED cotask_get_sched(cotask_active())
259#define TASK_HOST_ENT() \
260 cotask_host_entity(cotask_active())
261#define TASK_HOST_EVENTS(events_array) ({ \
262 (events_array) = cotask_malloc(cotask_active(), sizeof(*(events_array))); \
263 cotask_host_events(cotask_active(), sizeof(*events_array)/sizeof(CoEvent), &((events_array)->_first_event_)); \
266#define YIELD cotask_yield(NULL)
267#define WAIT(delay) cotask_wait(delay)
268#define WAIT_EVENT(e) cotask_wait_event(e)
269#define WAIT_EVENT_OR_DIE(e) cotask_wait_event_or_die(e)
270#define WAIT_EVENT_ONCE(e) cotask_wait_event_once(e)
271#define STALL cotask_wait(INT_MAX)
272#define AWAIT_SUBTASKS cotask_wait_substasks()
274#define NOT_NULL_OR_DIE(expr) ({ \
275 auto _not_null_ptr = (expr); \
276 if (_not_null_ptr == NULL) { \
277 cotask_cancel(cotask_active()); \
281#define TASK_BIND(ent) \
282 cotask_bind_to_entity(cotask_active(), (ent))
Une BoxedTask est une référence faible a une task.
Definition cotask.h:25
#define DECLARE_EXTERN_TASK(name,...)
Definition tasks.h:143