9 months ago |
37 |
1 |
#include "asleep.h" | ||
2 |
#include "task.h" | ||||
3 |
#include <assert.h> | ||||
4 |
#include <stdio.h> | ||||
5 |
#include <stdlib.h> | ||||
6 |
#include <errno.h> | ||||
7 |
#include <math.h> | ||||
8 |
#include <string.h> | ||||
8 months ago |
9 |
#include "cor_platform.h" | |||
9 months ago |
37 |
10 |
|||
11 |
|||||
12 |
typedef struct Loop_Timer { | ||||
8 months ago |
13 |
int64_t when; | |||
9 months ago |
37 |
14 |
Future *who; | ||
15 |
} Loop_Timer; | ||||
16 |
|||||
17 |
typedef struct _ASleep { | ||||
8 months ago |
18 |
_Cor_Mutex mutex; | |||
9 months ago |
37 |
19 |
unsigned users; | ||
20 |
Loop_Timer *sleepers; | ||||
21 |
int lo; | ||||
22 |
int hi; | ||||
23 |
int max; | ||||
8 months ago |
24 |
_Cor_Semaphore sem; | |||
9 months ago |
37 |
25 |
bool sleeploop_cancel; | ||
26 |
pthread_t sleeploop; | ||||
27 |
bool started; | ||||
28 |
} _ASleep; | ||||
29 |
|||||
30 |
static _ASleep asleep; | ||||
31 |
|||||
32 |
static void *ASleep_Sleeper(void *param); | ||||
33 |
|||||
34 |
static void ASleep_ctor( | ||||
35 |
_ASleep *me | ||||
36 |
){ | ||||
37 |
int r; | ||||
38 |
|||||
39 |
me->sleepers = NULL; | ||||
40 |
me->lo = 0; | ||||
41 |
me->hi = 0; | ||||
42 |
me->max = 0; | ||||
43 |
|||||
8 months ago |
44 |
_Cor_Mutex_ctor(&me->mutex); | |||
45 |
_Cor_Semaphore_ctor(&me->sem); | ||||
9 months ago |
37 |
46 |
me->sleeploop_cancel = false; | ||
47 |
r = pthread_create(&me->sleeploop, NULL, ASleep_Sleeper, me); | ||||
48 |
assert(r == 0); | ||||
49 |
me->started = true; | ||||
50 |
} | ||||
51 |
|||||
52 |
|||||
53 |
|||||
54 |
static void ASleep_dtor( | ||||
55 |
_ASleep *me | ||||
56 |
){ | ||||
57 |
int r; | ||||
58 |
me->started = false; | ||||
59 |
me->sleeploop_cancel = true; | ||||
8 months ago |
60 |
_Cor_Semaphore_Signal(&me->sem); | |||
9 months ago |
37 |
61 |
r = pthread_join(me->sleeploop, NULL); | ||
62 |
assert(r == 0); | ||||
8 months ago |
63 |
_Cor_Sempahore_dtor(&me->sem); | |||
64 |
_Cor_Mutex_dtor(&me->mutex); | ||||
9 months ago |
37 |
65 |
free(me->sleepers); | ||
66 |
} | ||||
67 |
|||||
68 |
|||||
69 |
void ASleep_StartSystem(){ | ||||
70 |
ASleep_ctor(&asleep); | ||||
71 |
} | ||||
72 |
|||||
73 |
|||||
74 |
void ASleep_StopSystem(){ | ||||
75 |
ASleep_dtor(&asleep); | ||||
76 |
} | ||||
77 |
|||||
78 |
|||||
79 |
static void ASleep_AddSleeper( | ||||
80 |
_ASleep *me, | ||||
8 months ago |
81 |
int64_t when, | |||
9 months ago |
37 |
82 |
Future *who | ||
83 |
){ | ||||
8 months ago |
84 |
_Cor_Mutex_Lock(&me->mutex); | |||
9 months ago |
37 |
85 |
|||
86 |
int nsleepers; | ||||
87 |
if (me->lo <= me->hi){ | ||||
88 |
int nsleepers = me->hi - me->lo; | ||||
89 |
// ensure there's always an empty slot so that lo == hi always means no sleepers | ||||
90 |
if (nsleepers+1 >= me->max) { | ||||
91 |
me->max = (me->max == 0) ? 4 : me->max * 2; | ||||
92 |
me->sleepers = realloc(me->sleepers, me->max * sizeof(Loop_Timer)); | ||||
93 |
assert(me->sleepers); | ||||
94 |
} | ||||
95 |
} else { | ||||
96 |
nsleepers = me->hi + me->max - me->lo; | ||||
97 |
// ensure there's always an empty slot so that lo == hi always means no sleepers | ||||
98 |
if (nsleepers+1 >= me->max) { | ||||
99 |
int oldmax = me->max; | ||||
100 |
me->max = (me->max == 0) ? 4 : me->max * 2; | ||||
101 |
me->sleepers = realloc(me->sleepers, me->max * sizeof(Loop_Timer)); | ||||
102 |
assert(me->sleepers); | ||||
103 |
memmove(&me->sleepers[me->lo], &me->lo + me->max - oldmax, sizeof(*me->sleepers) * oldmax - me->lo); | ||||
104 |
me->lo += me->max - oldmax; | ||||
105 |
} | ||||
106 |
} | ||||
107 |
|||||
108 |
// insertion sort - we're assuming there's not going to be many sleepers active at once | ||||
109 |
int i; | ||||
110 |
int nexti; | ||||
111 |
for (i = me->hi; i != me->lo; i = nexti){ | ||||
112 |
nexti = i-1; | ||||
113 |
if (i < 0){ | ||||
114 |
nexti += me->max; | ||||
115 |
} | ||||
8 months ago |
116 |
if (me->sleepers[nexti].when <= when){ | |||
9 months ago |
37 |
117 |
break; | ||
118 |
} | ||||
119 |
me->sleepers[i] = me->sleepers[nexti]; | ||||
120 |
} | ||||
121 |
me->sleepers[i].when = when; | ||||
122 |
me->sleepers[i].who = who; | ||||
123 |
me->hi += 1; | ||||
124 |
if (me->hi >= me->max){ | ||||
125 |
me->hi -= me->max; | ||||
126 |
} | ||||
127 |
|||||
8 months ago |
128 |
_Cor_Mutex_Unlock(&me->mutex); | |||
129 |
_Cor_Semaphore_Signal(&me->sem); | ||||
9 months ago |
37 |
130 |
} | ||
131 |
|||||
132 |
|||||
133 |
static void ASleep_RemoveSleeper( | ||||
134 |
_ASleep *me, | ||||
8 months ago |
135 |
int64_t when, | |||
9 months ago |
37 |
136 |
Future *who | ||
137 |
){ | ||||
8 months ago |
138 |
_Cor_Mutex_Lock(&me->mutex); | |||
9 months ago |
37 |
139 |
|||
140 |
int i; | ||||
141 |
for (i = me->lo; i != me->hi; ){ | ||||
8 months ago |
142 |
if (me->sleepers[i].when == when && me->sleepers[i].who == who){ | |||
9 months ago |
37 |
143 |
int previ = i; | ||
144 |
i += 1; | ||||
145 |
if (i >= me->max){ | ||||
146 |
i -= me->max; | ||||
147 |
} | ||||
148 |
for (; i != me->hi; ){ | ||||
149 |
me->sleepers[previ] = me->sleepers[i]; | ||||
150 |
previ = i; | ||||
151 |
i += 1; | ||||
152 |
if (i >= me->max){ | ||||
153 |
i -= me->max; | ||||
154 |
} | ||||
155 |
} | ||||
156 |
me->hi = previ; | ||||
157 |
break; | ||||
158 |
} | ||||
159 |
i += 1; | ||||
160 |
if (i >= me->max){ | ||||
161 |
i -= me->max; | ||||
162 |
} | ||||
163 |
} | ||||
164 |
|||||
8 months ago |
165 |
_Cor_Mutex_Unlock(&me->mutex); | |||
166 |
_Cor_Semaphore_Signal(&me->sem); | ||||
9 months ago |
37 |
167 |
} | ||
168 |
|||||
169 |
|||||
170 |
static void *ASleep_Sleeper( | ||||
171 |
void *param | ||||
172 |
){ | ||||
173 |
_ASleep *me = (_ASleep *)param; | ||||
174 |
|||||
175 |
while (!me->sleeploop_cancel){ | ||||
8 months ago |
176 |
_Cor_Mutex_Lock(&me->mutex); | |||
177 |
bool got_one; | ||||
9 months ago |
37 |
178 |
if (me->lo != me->hi){ | ||
8 months ago |
179 |
int64_t when = me->sleepers[0].when; | |||
180 |
_Cor_Mutex_Unlock(&me->mutex); | ||||
181 |
got_one = _Cor_Semaphore_Wait(&me->sem, when); | ||||
9 months ago |
37 |
182 |
} else { | ||
8 months ago |
183 |
_Cor_Mutex_Unlock(&me->mutex); | |||
184 |
got_one = _Cor_Semaphore_Wait(&me->sem, -1); | ||||
9 months ago |
37 |
185 |
} | ||
8 months ago |
186 |
if (!got_one){ | |||
187 |
// timed out, so... | ||||
188 |
// issue any due timers | ||||
189 |
int64_t now = _Cor_Realtime_Now(); | ||||
190 |
while(me->lo != me->hi && me->sleepers[me->lo].when <= now) { | ||||
191 |
Future *fut = me->sleepers[me->lo].who; | ||||
192 |
me->lo += 1; | ||||
193 |
if (me->lo >= me->max){ | ||||
194 |
me->lo -= me->max; | ||||
195 |
} | ||||
196 |
_Cor_Mutex_Unlock(&me->mutex); | ||||
197 |
Future_SetResult(fut, false, NULL); | ||||
198 |
_Cor_Mutex_Lock(&me->mutex); | ||||
199 |
now = _Cor_Realtime_Now(); | ||||
9 months ago |
37 |
200 |
} | ||
8 months ago |
201 |
_Cor_Mutex_Unlock(&me->mutex); | |||
9 months ago |
37 |
202 |
} | ||
203 |
} | ||||
204 |
|||||
205 |
return NULL; | ||||
206 |
} | ||||
207 |
|||||
208 |
|||||
209 |
// value is a pointer to a float delay in seconds | ||||
210 |
bool ASleep( | ||||
211 |
float delay, | ||||
212 |
void **value | ||||
213 |
){ | ||||
214 |
assert(current_task && asleep.started); | ||||
215 |
if (delay < 0){ | ||||
216 |
delay = 0; | ||||
217 |
} | ||||
8 months ago |
218 |
int64_t endtime = _Cor_Realtime_Now() + (int64_t)(delay * 1000000000); | |||
9 months ago |
37 |
219 |
|||
220 |
Future fut; | ||||
221 |
Future_ctor(&fut); | ||||
222 |
ASleep_AddSleeper(&asleep, endtime, &fut); | ||||
223 |
bool res = Future_Await(&fut, value); | ||||
224 |
ASleep_RemoveSleeper(&asleep, endtime, &fut); | ||||
225 |
Future_dtor(&fut); | ||||
226 |
|||||
227 |
return res; | ||||
228 |
} | ||||
229 |