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