137 lines2.7 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 _Task_SetResult(
16 Future *fut,
17 bool canceled,
18 void *res
19){
20 (void)fut;
21 (void)canceled;
22 (void)res;
23 // only the task can set it's future's result
24 assert(false);
25}
26
27
28Future_vfptrs_t Task_vfptrs = {
29 (void(*)(Future *fut))&Task_dtor,
30 &_Future_Await,
31 &_Task_SetResult,
32};
33
34
35static void *Task_entry(void *me){
36 Task *tsk = (Task *)me;
37 void *res = NULL;
38 assert(current_task == NULL);
39 current_task = tsk;
40 bool canceled = tsk->entry(tsk->param, &res);
41 current_task = NULL;
42 _Future_SetResult(&tsk->base, canceled, res);
43 return res;
44}
45
46
47void Task_ctor(
48 Task *tsk,
49 size_t stack_size,
50 Task_Entry entry,
51 void *param
52){
53 assert(Coroutine_IsStarted());
54 Future_ctor(&tsk->base);
55 tsk->base.vfptrs = &Task_vfptrs;
56 tsk->entry = entry;
57 tsk->param = param;
58 tsk->cor = Coroutine_New(stack_size, Task_entry);
59 tsk->awaiting_future = NULL;
60 tsk->canceled = false;
61 tsk->cancel_value = NULL;
62 if (current_task){
63 Coroutine_Continue(tsk->cor, tsk, false);
64 }
65}
66
67
68void Task_dtor(
69 Task *tsk
70){
71 Coroutine_Delete(tsk->cor);
72 Future_dtor(&tsk->base);
73}
74
75
76Task *Task_New(
77 size_t stack_size,
78 Task_Entry entry,
79 void *param
80){
81 Task *tsk = malloc(sizeof(Task));
82 Task_ctor(tsk, stack_size, entry, param);
83 return tsk;
84}
85
86
87void Task_Delete(
88 Task *tsk
89){
90 Future_Delete(&tsk->base);
91}
92
93
94void Task_Cancel(
95 Task *tsk,
96 void *cancel_value
97){
98 if (!tsk->canceled){
99 tsk->canceled = true;
100 tsk->cancel_value = cancel_value;
101 Future *awaiting_future = tsk->awaiting_future;
102 if (awaiting_future){
103 Future_SetResult(awaiting_future, true, NULL);
104 }
105 }
106}
107
108
109struct Task_Run_Params {
110 size_t stack_size;
111 Task_Entry start;
112 void *value;
113 void **res;
114};
115
116static Coroutine_Err Task_Runner(void *_params)
117{
118 struct Task_Run_Params *params = (struct Task_Run_Params *)_params;
119
120 Task tsk;
121 Task_ctor(&tsk, params->stack_size, params->start, params->value);
122 Coroutine_Err err = Coroutine_Run_Coroutine(tsk.cor, &tsk);
123 if (!err){
124 err = Future_GetResult(&tsk.base, params->res);
125 }
126 Task_dtor(&tsk);
127 return err;
128}
129
130bool Task_Run(size_t stack_size, Task_Entry start, void *value, void **res){
131 if (current_task){
132 return Coroutine_Err_SystemRunning;
133 }
134 struct Task_Run_Params params = {stack_size, start, value, res};
135 return Coroutine_RunSystem(Task_Runner, &params);
136}
137