Gwion coverage report


Directory: src/
File: src/lib/shred.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 241 285 84.6%
Functions: 24 35 68.6%
Branches: 37 80 46.2%

Line Branch Exec Source
1 #include <unistd.h>
2 #include "gwion_util.h"
3 #include "gwion_ast.h"
4 #include "gwion_env.h"
5 #include "gwion_thread.h"
6 #include "vm.h"
7 #include "instr.h"
8 #include "shreduler_private.h"
9 #include "gwion.h"
10 #include "object.h"
11 #include "operator.h"
12 #include "import.h"
13 #include "emit.h"
14 #include "specialid.h"
15 #include "gwi.h"
16 #include "ugen.h"
17
18 static m_int o_fork_thread, o_shred_cancel,
19 o_fork_done, o_fork_ev;
20
21 #define FORK_THREAD(o) *(THREAD_TYPE *)(o->data + o_fork_thread)
22
23 79 VM_Shred new_shred_base(const VM_Shred shred, const VM_Code code) {
24 79 const VM_Shred sh = new_vm_shred(shred->info->mp, code);
25 79 vmcode_addref(code);
26 79 sh->base = shred->base;
27 79 return sh;
28 }
29
30 1062 M_Object new_shred(const VM_Shred shred) {
31 const M_Object obj =
32 1062 new_object(shred->info->mp, shred->info->vm->gwion->type[et_shred]);
33 1062 ME(obj) = shred;
34 1062 return obj;
35 }
36
37 5 ANN static inline M_Object fork_object(const VM_Shred shred, const Type t) {
38 5 const Gwion gwion = shred->info->vm->gwion;
39 5 const M_Object o = new_object(gwion->mp, t);
40 10 *(M_Object *)(o->data + o_fork_ev) =
41 5 new_object(gwion->mp, gwion->type[et_event]);
42 5 vector_init(&EV_SHREDS(*(M_Object *)(o->data + o_fork_ev)));
43 5 return o;
44 }
45
46 5 ANN M_Object new_fork(const VM_Shred shred, const VM_Code code, const Type t) {
47 5 VM * parent = shred->info->vm;
48 5 const VM_Shred sh = new_shred_base(shred, code);
49 5 VM * vm = (sh->info->vm = gwion_cpy(parent));
50 5 vm->parent = parent;
51 5 const M_Object o = sh->info->me = fork_object(shred, t);
52 5 ME(o) = sh;
53 5 shreduler_add(vm->shreduler, sh);
54 5 return o;
55 }
56
57 2 static MFUN(gw_shred_exit) {
58 2 const VM_Shred s = ME(o);
59
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if((m_int)s->tick->prev != -1)
60 2 shreduler_remove(s->tick->shreduler, s, true);
61 2 }
62
63 5 static MFUN(vm_shred_id) {
64 5 const VM_Shred s = ME(o);
65 5 *(m_int *)RETURN = s->tick->xid;
66 5 }
67
68 1 static MFUN(vm_shred_is_running) {
69 1 const VM_Shred s = ME(o);
70
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
1 *(m_uint *)RETURN = ((m_int)s->tick->prev != -1 && (s->tick->prev || s->tick->next)) ? true : false;
71 1 }
72
73 1 static MFUN(vm_shred_is_done) {
74 1 *(m_uint *)RETURN = (m_int)ME(o)->tick->prev == -1;
75 1 }
76
77 22 static MFUN(shred_yield) {
78 22 const VM_Shred s = ME(o);
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if((m_int)s->tick->prev == -1) return;
80 22 const Shreduler sh = s->tick->shreduler;
81
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (s != shred) shreduler_remove(sh, s, false);
82 22 shredule(sh, s, GWION_EPSILON);
83 }
84
85 1 static SFUN(vm_shred_from_id) {
86 1 const m_int index = *(m_int *)MEM(0);
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (index > 0) {
88 const Vector v = &shred->tick->shreduler->active_shreds;
89 for (m_uint i = 0; i < vector_size(v); ++i) {
90 const VM_Shred s =
91 (VM_Shred)vector_at(v, i);
92 if (s->tick->xid == (m_uint)index) {
93 *(M_Object *)RETURN = s->info->me;
94 return;
95 }
96 }
97 }
98 1 xfun_handle(shred, "InvalidShredRequest");
99 }
100
101 static MFUN(shred_args) {
102 const VM_Shred s = ME(o);
103 *(m_uint *)RETURN = s->info->args.ptr ? vector_size(&s->info->args) : 0;
104 }
105
106 static MFUN(shred_arg) {
107 const VM_Shred s = ME(o);
108 const m_int idx = *(m_int *)MEM(SZ_INT);
109 if (s->info->args.ptr && idx >= 0 && (m_uint)idx < vector_size(&s->info->args)) {
110 const m_str str = (m_str)vector_at(&s->info->args, *(m_uint *)MEM(SZ_INT));
111 *(M_Object *)RETURN = new_string(shred->info->vm->gwion, str);
112 } else xfun_handle(shred, "InvalidShredArgumentRequest");
113 }
114
115 #ifndef BUILD_ON_WINDOWS
116 #define PATH_CHR '/'
117 #else
118 #define PATH_CHR '\\'
119 #endif
120
121 #define describe_name(name, src) \
122 static MFUN(shred##name##_name) { \
123 const VM_Shred s = ME(o); \
124 const m_str str = code_name((src), 0); \
125 *(m_uint *)RETURN = (m_uint)new_string(shred->info->vm->gwion, str); \
126 }
127 describe_name(, s->info->orig->name) describe_name(_code, s->code->name)
128
129 #define describe_path_and_dir(name, src) \
130 static MFUN(shred##name##_path) { \
131 const VM_Shred s = ME(o); \
132 const m_str str = code_name((src), 1); \
133 *(m_uint *)RETURN = (m_uint)new_string(shred->info->vm->gwion, str); \
134 } \
135 static MFUN(shred##name##_dir) { \
136 const VM_Shred s = ME(o); \
137 const m_str str = code_name((src), 1); \
138 const size_t len = strlen(str); \
139 char c[len + 1]; \
140 strcpy(c, str); \
141 size_t sz = len; \
142 while (sz) { \
143 if (c[sz] == PATH_CHR) { \
144 c[sz] = 0; \
145 break; \
146 } \
147 --sz; \
148 } \
149 *(m_uint *)RETURN = (m_uint)new_string(shred->info->vm->gwion, c); \
150 }
151 describe_path_and_dir(, s->info->orig->name)
152 describe_path_and_dir(_code, s->code->name)
153
154 425 static DTOR(shred_dtor) {
155 425 VM_Shred s = ME(o);
156 425 free_vm_shred(s);
157 425 }
158
159
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 static MFUN(shred_lock) { if(ME(o)->tick) MUTEX_LOCK(ME(o)->mutex); }
160
161
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 static MFUN(shred_unlock) { if(ME(o)->tick) MUTEX_UNLOCK(ME(o)->mutex); }
162
163 6 static void stop(const M_Object o) {
164 6 VM *vm = ME(o)->info->vm;
165 6 MUTEX_LOCK(vm->shreduler->mutex);
166 6 MUTEX_LOCK(ME(o)->mutex);
167 6 vm->shreduler->bbq->is_running = 0;
168 6 *(m_int *)(o->data + o_shred_cancel) = 1;
169 6 MUTEX_UNLOCK(ME(o)->mutex);
170 6 MUTEX_UNLOCK(vm->shreduler->mutex);
171 6 }
172
173 6 static inline void join(const M_Object o) {
174
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 if (FORK_THREAD(o)) {
175 5 THREAD_JOIN(FORK_THREAD(o));
176 5 FORK_THREAD(o) = 0;
177 }
178 6 }
179
180 1 static DTOR(fork_dtor) {
181 1 VM *parent = ME(o)->info->vm->parent;
182 // MUTEX_LOCK(parent->shreduler->mutex);
183 1 MUTEX_LOCK(ME(o)->mutex);
184 1 *(m_int *)(o->data + o_fork_done) = 1;
185 1 MUTEX_UNLOCK(ME(o)->mutex);
186 1 stop(o);
187 1 join(o);
188 // MUTEX_UNLOCK(parent->shreduler->mutex);
189 1 MUTEX_LOCK(parent->shreduler->mutex);
190 // MUTEX_LOCK(ME(o)->mutex);
191
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (parent->gwion->data->child.ptr) {
192 1 const m_int idx = vector_find(&parent->gwion->data->child, (vtype)o);
193
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (idx > -1) VPTR(&parent->gwion->data->child, idx) = 0;
194 }
195
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!parent->gwion->data->child2.ptr)
196 1 vector_init(&parent->gwion->data->child2);
197 1 vector_add(&parent->gwion->data->child2, (vtype)ME(o)->info->vm->gwion);
198 // MUTEX_UNLOCK(ME(o)->mutex);
199 1 MUTEX_UNLOCK(parent->shreduler->mutex);
200 1 vmcode_remref(ME(o)->code, ME(o)->info->vm->gwion);
201 1 }
202
203 1 static MFUN(fork_join) {
204
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (*(m_int *)(o->data + o_fork_done)) return;
205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!ME(o)->tick) return;
206 1 shred->info->me->ref++;
207 1 vector_add(&EV_SHREDS(*(M_Object *)(o->data + o_fork_ev)), (vtype)shred);
208 1 shreduler_remove(shred->tick->shreduler, shred, false);
209 }
210
211 2 static MFUN(shred_cancel) {
212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(!ME(o)->tick)return;
213 // vm_lock(ME(o)->info->vm);
214 2 MUTEX_LOCK(ME(o)->mutex);
215 2 *(m_int *)(o->data + o_shred_cancel) = *(m_int *)MEM(SZ_INT);
216 2 MUTEX_UNLOCK(ME(o)->mutex);
217 // vm_unlock(ME(o)->info->vm);
218 }
219
220 2 static MFUN(shred_test_cancel) {
221 2 MUTEX_LOCK(ME(o)->mutex);
222
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (*(m_int *)(o->data + o_shred_cancel)) {
223 1 MUTEX_UNLOCK(ME(o)->mutex);
224 1 vm_shred_exit(ME(o));
225 } else
226 1 MUTEX_UNLOCK(ME(o)->mutex);
227 2 }
228
229 static MFUN(fork_test_cancel) {
230 VM *parent = ME(o)->info->vm;
231 MUTEX_LOCK(parent->shreduler->mutex);
232 if (*(m_int *)(o->data + o_shred_cancel)) {
233 MUTEX_UNLOCK(parent->shreduler->mutex);
234 stop(o);
235 join(o);
236 _release(o, ME(o));
237 vm_shred_exit(ME(o));
238 } else
239 MUTEX_UNLOCK(parent->shreduler->mutex);
240 }
241
242 static MFUN(shred_now) {
243 VM *vm = ME(o)->info->vm;
244 while (vm->parent) vm = vm->parent;
245 MUTEX_LOCK(vm->shreduler->mutex);
246 *(m_float *)RETURN = vm->bbq->pos;
247 MUTEX_UNLOCK(vm->shreduler->mutex);
248 }
249
250 static MFUN(shred_blackhole) {
251 VM *vm = ME(o)->info->vm;
252 const UGen u = (UGen)vector_front(&vm->ugen);
253 M_Object blackhole = u->module.gen.data;
254 // adding ref for the moment
255 blackhole->ref++;
256 *(void**)RETURN = u->module.gen.data;
257 }
258
259 struct ThreadLauncher {
260 MUTEX_TYPE mutex;
261 THREAD_COND_TYPE cond;
262 VM * vm;
263 };
264
265 2880007 static inline int fork_running(VM *vm, const M_Object o) {
266 2880007 MUTEX_LOCK(ME(o)->mutex);
267 2880007 const int cancel = *(m_int *)(o->data + o_shred_cancel);
268 2880007 MUTEX_UNLOCK(ME(o)->mutex);
269
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2880003 times.
2880007 if(cancel)return false;
270 2880003 MUTEX_LOCK(vm->shreduler->mutex);
271 2880003 const int ret = vm->bbq->is_running;
272 2880003 MUTEX_UNLOCK(vm->shreduler->mutex);
273 2880003 return ret;
274 }
275
276 5 static ANN THREAD_FUNC(fork_run) {
277 5 struct ThreadLauncher *tl = data;
278 5 VM * vm = tl->vm;
279 5 MUTEX_TYPE mutex = tl->mutex;
280 5 const M_Object me = vm->shreduler->list->self->info->me;
281 5 MUTEX_COND_LOCK(mutex);
282 5 THREAD_COND_SIGNAL(tl->cond);
283 5 MUTEX_COND_UNLOCK(mutex);
284 // THREAD_COND_CLEANUP(tl->cond);
285 // MUTEX_CLEANUP(tl->mutex);
286
2/2
✓ Branch 1 taken 2880002 times.
✓ Branch 2 taken 5 times.
2880007 while (fork_running(vm, me)) {
287 2880002 vm_run_audio(vm);
288 2880002 ++vm->bbq->pos;
289 }
290 5 gwion_end_child(ME(me), vm->gwion);
291 5 vm_lock(vm);
292 // MUTEX_LOCK(vm->shreduler->mutex);
293 // MUTEX_LOCK(vm->parent->shreduler->mutex);
294 5 MUTEX_LOCK(ME(me)->mutex);
295
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (!*(m_int *)(me->data + o_shred_cancel) &&
296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 me->type_ref != vm->gwion->type[et_fork])
297 memcpy(me->data + vm->gwion->type[et_fork]->nspc->offset, ME(me)->reg,
298 ((Type)vector_front(&me->type_ref->info->tuple->types))->size);
299 5 *(m_int *)(me->data + o_fork_done) = 1;
300 5 MUTEX_UNLOCK(ME(me)->mutex);
301
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (!*(m_int *)(me->data + o_shred_cancel))
302 1 broadcast(*(M_Object *)(me->data + o_fork_ev));
303 5 vm_unlock(vm);
304 // MUTEX_UNLOCK(vm->parent->shreduler->mutex);
305 // MUTEX_UNLOCK(vm->shreduler->mutex);
306 5 THREAD_RETURN(0);
307 }
308
309 5 ANN void fork_launch(const M_Object o) {
310 MUTEX_TYPE mutex;
311 5 MUTEX_SETUP(mutex);
312 THREAD_COND_TYPE cond;
313 5 THREAD_COND_SETUP(cond);
314 5 struct ThreadLauncher tl = {
315 5 .mutex = mutex, .cond = cond, .vm = ME(o)->info->vm};
316 5 ++o->ref;
317 5 MUTEX_COND_LOCK(mutex);
318 5 THREAD_CREATE(FORK_THREAD(o), fork_run, &tl);
319 5 THREAD_COND_WAIT(cond, mutex);
320 5 MUTEX_COND_UNLOCK(mutex);
321 5 THREAD_COND_CLEANUP(cond);
322 5 MUTEX_CLEANUP(mutex);
323 5 }
324
325 5 ANN void fork_clean(const VM_Shred shred, const Vector v) {
326
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
10 for (m_uint i = 0; i < vector_size(v); ++i) {
327 5 const M_Object o = (M_Object)vector_at(v, i);
328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!o) continue;
329 5 stop(o);
330 }
331
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
10 for (m_uint i = 0; i < vector_size(v); ++i) {
332 5 const M_Object o = (M_Object)vector_at(v, i);
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!o) continue;
334 5 join(o);
335 }
336
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
10 for (m_uint i = 0; i < vector_size(v); ++i) {
337 5 const M_Object o = (M_Object)vector_at(v, i);
338
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!o) continue;
339 5 _release(o, shred);
340 }
341 5 vector_release(v);
342 5 v->ptr = NULL;
343 5 }
344
345 638 GWION_IMPORT(shred) {
346 638 const Type t_shred = gwi_class_ini(gwi, "Shred", NULL);
347 638 gwi_class_xtor(gwi, NULL, shred_dtor);
348
349 638 t_shred->nspc->offset += SZ_INT;
350
351 638 gwi_item_ini(gwi, "int", "cancel");
352 638 GWI_BB((o_shred_cancel = gwi_item_end(gwi, ae_flag_const, num, 0)))
353
354 638 gwi_func_ini(gwi, "void", "exit");
355 638 GWI_BB(gwi_func_end(gwi, gw_shred_exit, ae_flag_none))
356
357 638 gwi_func_ini(gwi, "bool", "running");
358 638 GWI_BB(gwi_func_end(gwi, vm_shred_is_running, ae_flag_none))
359
360 638 gwi_func_ini(gwi, "bool", "done");
361 638 GWI_BB(gwi_func_end(gwi, vm_shred_is_done, ae_flag_none))
362
363 638 gwi_func_ini(gwi, "int", "id");
364 638 GWI_BB(gwi_func_end(gwi, vm_shred_id, ae_flag_none))
365
366 638 gwi_func_ini(gwi, "Shred", "fromId");
367 638 gwi_func_arg(gwi, "int", "xid");
368 638 GWI_BB(gwi_func_end(gwi, vm_shred_from_id, ae_flag_static))
369
370 638 gwi_func_ini(gwi, "void", "yield");
371 638 GWI_BB(gwi_func_end(gwi, shred_yield, ae_flag_none))
372
373 638 gwi_func_ini(gwi, "int", "args");
374 638 GWI_BB(gwi_func_end(gwi, shred_args, ae_flag_none))
375
376 638 gwi_func_ini(gwi, "string", "arg");
377 638 gwi_func_arg(gwi, "int", "n");
378 638 GWI_BB(gwi_func_end(gwi, shred_arg, ae_flag_none))
379
380 638 gwi_func_ini(gwi, "string", "name");
381 638 GWI_BB(gwi_func_end(gwi, shred_name, ae_flag_none))
382
383 638 gwi_func_ini(gwi, "string", "path");
384 638 GWI_BB(gwi_func_end(gwi, shred_path, ae_flag_none))
385
386 638 gwi_func_ini(gwi, "string", "dir");
387 638 GWI_BB(gwi_func_end(gwi, shred_dir, ae_flag_none))
388
389 638 gwi_func_ini(gwi, "string", "code_name");
390 638 GWI_BB(gwi_func_end(gwi, shred_code_name, ae_flag_none))
391
392 638 gwi_func_ini(gwi, "string", "code_path");
393 638 GWI_BB(gwi_func_end(gwi, shred_code_path, ae_flag_none))
394
395 638 gwi_func_ini(gwi, "string", "code_dir");
396 638 GWI_BB(gwi_func_end(gwi, shred_code_dir, ae_flag_none))
397
398 638 gwi_func_ini(gwi, "void", "set_cancel");
399 638 gwi_func_arg(gwi, "int", "n");
400 638 GWI_BB(gwi_func_end(gwi, shred_cancel, ae_flag_none))
401 638 gwi_func_ini(gwi, "void", "test_cancel");
402 638 GWI_BB(gwi_func_end(gwi, shred_test_cancel, ae_flag_none))
403 638 gwi_func_ini(gwi, "void", "lock");
404 638 GWI_BB(gwi_func_end(gwi, shred_lock, ae_flag_none))
405 638 gwi_func_ini(gwi, "void", "unlock");
406 638 GWI_BB(gwi_func_end(gwi, shred_unlock, ae_flag_none))
407 638 gwi_func_ini(gwi, "float", "get_now");
408 638 GWI_BB(gwi_func_end(gwi, shred_now, ae_flag_none))
409
410 638 gwi_func_ini(gwi, "UGen", "get_blackhole");
411 638 GWI_BB(gwi_func_end(gwi, shred_blackhole, ae_flag_none))
412
413
414 638 GWI_BB(gwi_class_end(gwi))
415 638 SET_FLAG(t_shred, abstract | ae_flag_final);
416 638 gwi->gwion->type[et_shred] = t_shred;
417
418 638 struct SpecialId_ spid = {.type = t_shred, .exec = RegPushMe, .is_const = 1};
419 638 gwi_specialid(gwi, "me", &spid);
420
421 638 const Type t_fork = gwi_class_ini(gwi, "Fork", "Shred");
422 638 gwi_class_xtor(gwi, NULL, fork_dtor);
423 638 gwi->gwion->type[et_fork] = t_fork;
424 638 o_fork_thread = t_fork->nspc->offset;
425 638 t_fork->nspc->offset += SZ_INT;
426
427 638 gwi_item_ini(gwi, "int", "is_done");
428 638 GWI_BB((o_fork_done = gwi_item_end(gwi, ae_flag_const, num, 0)))
429 638 gwi_item_ini(gwi, "Event", "ev");
430 638 GWI_BB((o_fork_ev = gwi_item_end(gwi, ae_flag_const, num, 0)))
431 638 gwi_func_ini(gwi, "void", "join");
432 638 GWI_BB(gwi_func_end(gwi, fork_join, ae_flag_none))
433 638 gwi_func_ini(gwi, "void", "test_cancel");
434 638 GWI_BB(gwi_func_end(gwi, fork_test_cancel, ae_flag_none))
435 638 GWI_BB(gwi_class_end(gwi))
436 638 SET_FLAG(t_fork, abstract | ae_flag_final);
437
438 638 const Type t_typed = gwi_class_ini(gwi, "TypedFork:[A]", "Fork");
439 638 gwi_item_ini(gwi, "A", "retval");
440 638 GWI_BB(gwi_item_end(gwi, ae_flag_const, num, 0))
441 638 GWI_BB(gwi_class_end(gwi))
442 638 SET_FLAG(t_typed, abstract | ae_flag_final);
443 638 return GW_OK;
444 }
445