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