178 lines3.4 KB
1#include "task.h"
2#include <assert.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <time.h>
6#include <errno.h>
7#include <math.h>
8#include <string.h>
9#include "timespec_utils.h"
10#include "coroutine_names_def.h"
11
12
13_Cor_thread_local Task *current_task;
14
15
16static void
17_Task_SetResult(
18 Future *fut,
19 bool canceled,
20 void *res
21){
22 (void)fut;
23 (void)canceled;
24 (void)res;
25 // only the task can set it's future's result
26 assert(false);
27}
28
29
30Future_vfptrs_t Task_vfptrs = {
31 (void(*)(Future *fut))&Task_dtor,
32 &_Future_Await,
33 &_Task_SetResult,
34};
35
36
37static void *
38Task_entry(void *me){
39 Task *tsk = (Task *)me;
40 void *res = NULL;
41 assert(current_task == NULL);
42 current_task = tsk;
43 bool canceled = tsk->entry(tsk->param, &res);
44 current_task = NULL;
45 _Future_SetResult(&tsk->base, canceled, res);
46 return res;
47}
48
49
50static void
51Task_ctor_(
52 Task *tsk,
53 Coroutine *cor
54){
55 assert(Coroutine_IsStarted());
56 Future_ctor(&tsk->base);
57 tsk->base.vfptrs = &Task_vfptrs;
58 tsk->cor = cor;
59 tsk->cor_owned = false;
60 tsk->awaiting_future = NULL;
61 tsk->canceled = false;
62 tsk->cancel_value = NULL;
63 if (current_task){
64 Coroutine_Continue(tsk->cor, tsk, false);
65 }
66}
67
68
69void
70Task_ctor(
71 Task *tsk,
72 size_t min_stack,
73 size_t min_stack_headroom,
74 Task_Entry entry,
75 void *param
76){
77 assert(Coroutine_IsStarted());
78 Task_ctor_(tsk, Coroutine_New(min_stack, min_stack_headroom, Task_entry));
79 tsk->cor_owned = true;
80 tsk->entry = entry;
81 tsk->param = param;
82 if (current_task){
83 Coroutine_Continue(tsk->cor, tsk, false);
84 }
85}
86
87
88void
89Task_dtor(
90 Task *tsk
91){
92 if (tsk->cor_owned){
93 Coroutine_Delete(tsk->cor);
94 }
95 Future_dtor(&tsk->base);
96}
97
98
99Task *
100Task_New(
101 size_t min_stack,
102 size_t min_stack_headroom,
103 Task_Entry entry,
104 void *param
105){
106 Task *tsk = malloc(sizeof(Task));
107 Task_ctor(tsk, min_stack, min_stack_headroom, entry, param);
108 return tsk;
109}
110
111
112void
113Task_Delete(
114 Task *tsk
115){
116 Future_Delete(&tsk->base);
117}
118
119
120void
121Task_Cancel(
122 Task *tsk,
123 void *cancel_value
124){
125 if (!tsk->canceled){
126 tsk->canceled = true;
127 tsk->cancel_value = cancel_value;
128 Future *awaiting_future = tsk->awaiting_future;
129 if (awaiting_future){
130 Future_SetResult(awaiting_future, true, NULL);
131 }
132 }
133}
134
135
136struct Task_Run_Params {
137 size_t min_stack;
138 size_t min_stack_headroom;
139 Task_Entry start;
140 void *value;
141 void **res;
142};
143
144static Coroutine_Err
145Task_Runner(
146 void *_params,
147 Coroutine *root
148){
149 struct Task_Run_Params *params = (struct Task_Run_Params *)_params;
150
151 Task roottsk;
152 Task_ctor_(&roottsk, root);
153 current_task = &roottsk;
154 Task childtask;
155 Task_ctor(&childtask, params->min_stack, params->min_stack_headroom, params->start, params->value);
156 Coroutine_Err err = Task_Await(&childtask, params->res);
157 Task_dtor(&childtask);
158 current_task = NULL;
159 Task_dtor(&roottsk);
160 return err;
161}
162
163bool
164Task_Run(
165 size_t min_stack,
166 size_t min_stack_headroom,
167 Task_Entry start,
168 void *value,
169 void **res
170){
171 if (current_task){
172 return Coroutine_Err_SystemRunning;
173 }
174 struct Task_Run_Params params = {min_stack, min_stack_headroom, start, value, res};
175 return Coroutine_RunSystem(0, COROUTINE_STARTUP_STACK_SIZE, Task_Runner, &params);
176}
177#include "coroutine_names_undef.h"
178