1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2020 Joël Krähemann
3 *
4 * This file is part of GSequencer.
5 *
6 * GSequencer is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GSequencer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GSequencer. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <ags/thread/ags_thread.h>
21
22 #include <ags/object/ags_application_context.h>
23 #include <ags/object/ags_main_loop.h>
24 #include <ags/object/ags_config.h>
25 #include <ags/object/ags_connectable.h>
26 #include <ags/object/ags_marshal.h>
27
28 #include <ags/thread/ags_concurrency_provider.h>
29 #include <ags/thread/ags_task_launcher.h>
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <math.h>
35
36 #include <ags/i18n.h>
37
38 #include <errno.h>
39
40 void ags_thread_class_init(AgsThreadClass *thread);
41 void ags_thread_connectable_interface_init(AgsConnectableInterface *connectable);
42 void ags_thread_init(AgsThread *thread);
43 void ags_thread_set_property(GObject *gobject,
44 guint prop_id,
45 const GValue *value,
46 GParamSpec *param_spec);
47 void ags_thread_get_property(GObject *gobject,
48 guint prop_id,
49 GValue *value,
50 GParamSpec *param_spec);
51 void ags_thread_finalize(GObject *gobject);
52
53 AgsUUID* ags_thread_get_uuid(AgsConnectable *connectable);
54 gboolean ags_thread_has_resource(AgsConnectable *connectable);
55 gboolean ags_thread_is_ready(AgsConnectable *connectable);
56 void ags_thread_add_to_registry(AgsConnectable *connectable);
57 void ags_thread_remove_from_registry(AgsConnectable *connectable);
58 xmlNode* ags_thread_list_resource(AgsConnectable *connectable);
59 xmlNode* ags_thread_xml_compose(AgsConnectable *connectable);
60 void ags_thread_xml_parse(AgsConnectable *connectable,
61 xmlNode *node);
62 gboolean ags_thread_is_connected(AgsConnectable *connectable);
63 void ags_thread_connect(AgsConnectable *connectable);
64 void ags_thread_disconnect(AgsConnectable *connectable);
65
66 guint ags_thread_real_clock(AgsThread *thread);
67
68 void ags_thread_real_start(AgsThread *thread);
69 void ags_thread_real_stop(AgsThread *thread);
70
71 void* ags_thread_loop(void *ptr);
72
73 /**
74 * SECTION:ags_thread
75 * @short_description: threads
76 * @title: AgsThread
77 * @section_id:
78 * @include: ags/thread/ags_thread.h
79 *
80 * The #AgsThread base class. It supports organizing them within a tree,
81 * perform syncing and frequencies.
82 */
83
84 enum{
85 PROP_0,
86 PROP_FREQUENCY,
87 PROP_MAX_PRECISION,
88 PROP_DELAY,
89 };
90
91 enum{
92 CLOCK,
93 START,
94 RUN,
95 STOP,
96 LAST_SIGNAL,
97 };
98
99 static gpointer ags_thread_parent_class = NULL;
100 static guint thread_signals[LAST_SIGNAL];
101
102 static GPrivate ags_thread_key;
103
104 static gboolean ags_thread_global_use_sync_counter = TRUE;
105
106 GType
ags_thread_get_type()107 ags_thread_get_type()
108 {
109 static volatile gsize g_define_type_id__volatile = 0;
110
111 if(g_once_init_enter (&g_define_type_id__volatile)){
112 GType ags_type_thread = 0;
113
114 const GTypeInfo ags_thread_info = {
115 sizeof (AgsThreadClass),
116 NULL, /* base_init */
117 NULL, /* base_finalize */
118 (GClassInitFunc) ags_thread_class_init,
119 NULL, /* class_finalize */
120 NULL, /* class_data */
121 sizeof (AgsThread),
122 0, /* n_preallocs */
123 (GInstanceInitFunc) ags_thread_init,
124 };
125
126 const GInterfaceInfo ags_connectable_interface_info = {
127 (GInterfaceInitFunc) ags_thread_connectable_interface_init,
128 NULL, /* interface_finalize */
129 NULL, /* interface_data */
130 };
131
132 ags_type_thread = g_type_register_static(G_TYPE_OBJECT,
133 "AgsThread",
134 &ags_thread_info,
135 0);
136
137 g_type_add_interface_static(ags_type_thread,
138 AGS_TYPE_CONNECTABLE,
139 &ags_connectable_interface_info);
140
141 g_once_init_leave(&g_define_type_id__volatile, ags_type_thread);
142 }
143
144 return g_define_type_id__volatile;
145 }
146
147 GType
ags_thread_flags_get_type()148 ags_thread_flags_get_type()
149 {
150 static volatile gsize g_flags_type_id__volatile;
151
152 if(g_once_init_enter (&g_flags_type_id__volatile)){
153 static const GFlagsValue values[] = {
154 { AGS_THREAD_ADDED_TO_REGISTRY, "AGS_THREAD_ADDED_TO_REGISTRY", "thread-added-to-registry" },
155 { AGS_THREAD_CONNECTED, "AGS_THREAD_CONNECTED", "thread-connected" },
156 { AGS_THREAD_UNREF_ON_EXIT, "AGS_THREAD_UNREF_ON_EXIT", "thread-unref-on-exit" },
157 { AGS_THREAD_IMMEDIATE_SYNC, "AGS_THREAD_IMMEDIATE_SYNC", "thread-immediate-sync" },
158 { AGS_THREAD_INTERMEDIATE_PRE_SYNC, "AGS_THREAD_INTERMEDIATE_PRE_SYNC", "thread-intermediate-pre-sync" },
159 { AGS_THREAD_INTERMEDIATE_POST_SYNC, "AGS_THREAD_INTERMEDIATE_POST_SYNC", "thread-intermediate-post-sync" },
160 { AGS_THREAD_START_SYNCED_FREQ, "AGS_THREAD_START_SYNCED_FREQ", "thread-start-synced-freq" },
161 { AGS_THREAD_MARK_SYNCED, "AGS_THREAD_MARK_SYNCED", "thread-mark-synced" },
162 { AGS_THREAD_TIME_ACCOUNTING, "AGS_THREAD_TIME_ACCOUNTING", "thread-time-accounting" },
163 { 0, NULL, NULL }
164 };
165
166 GType g_flags_type_id = g_flags_register_static(g_intern_static_string("AgsThreadFlags"), values);
167
168 g_once_init_leave (&g_flags_type_id__volatile, g_flags_type_id);
169 }
170
171 return g_flags_type_id__volatile;
172 }
173
174 GType
ags_thread_status_flags_get_type()175 ags_thread_status_flags_get_type()
176 {
177 static volatile gsize g_flags_type_id__volatile;
178
179 if(g_once_init_enter (&g_flags_type_id__volatile)){
180 static const GFlagsValue values[] = {
181 { AGS_THREAD_STATUS_RT_SETUP, "AGS_THREAD_STATUS_RT_SETUP", "thread-status-rt-setup" },
182 { AGS_THREAD_STATUS_INITIAL_SYNC, "AGS_THREAD_STATUS_INITIAL_SYNC", "thread-status-initial-sync" },
183 { AGS_THREAD_STATUS_INITIAL_RUN, "AGS_THREAD_STATUS_INITIAL_RUN", "thread-status-initial-run" },
184 { AGS_THREAD_STATUS_IS_CHAOS_TREE, "AGS_THREAD_STATUS_IS_CHAOS_TREE", "thread-status-is-chaos-tree" },
185 { AGS_THREAD_STATUS_START_WAIT, "AGS_THREAD_STATUS_START_WAIT", "thread-status-start-wait" },
186 { AGS_THREAD_STATUS_START_DONE, "AGS_THREAD_STATUS_START_DONE", "thread-status-start-done" },
187 { AGS_THREAD_STATUS_READY, "AGS_THREAD_STATUS_READY", "thread-status-ready" },
188 { AGS_THREAD_STATUS_WAITING, "AGS_THREAD_STATUS_WAITING", "thread-status-waiting" },
189 { AGS_THREAD_STATUS_RUNNING, "AGS_THREAD_STATUS_RUNNING", "thread-status-running" },
190 { AGS_THREAD_STATUS_LOCKED, "AGS_THREAD_STATUS_LOCKED", "thread-status-locked" },
191 { AGS_THREAD_STATUS_BUSY, "AGS_THREAD_STATUS_BUSY", "thread-status-busy" },
192 { AGS_THREAD_STATUS_SYNCED, "AGS_THREAD_STATUS_SYNCED", "thread-status-synced" },
193 { AGS_THREAD_STATUS_SYNCED_FREQ, "AGS_THREAD_STATUS_SYNCED_FREQ", "thread-status-synced-freq" },
194 { 0, NULL, NULL }
195 };
196
197 GType g_flags_type_id = g_flags_register_static(g_intern_static_string("AgsThreadStatusFlags"), values);
198
199 g_once_init_leave (&g_flags_type_id__volatile, g_flags_type_id);
200 }
201
202 return g_flags_type_id__volatile;
203 }
204
205 GType
ags_thread_sync_tic_flags_get_type()206 ags_thread_sync_tic_flags_get_type()
207 {
208 static volatile gsize g_flags_type_id__volatile;
209
210 if(g_once_init_enter (&g_flags_type_id__volatile)){
211 static const GFlagsValue values[] = {
212 { AGS_THREAD_SYNC_TIC_WAIT_0, "AGS_THREAD_SYNC_TIC_WAIT_0", "thread-sync-tic-wait-0" },
213 { AGS_THREAD_SYNC_TIC_DONE_0, "AGS_THREAD_SYNC_TIC_DONE_0", "thread-sync-tic-done-0" },
214 { AGS_THREAD_SYNC_TIC_WAIT_1, "AGS_THREAD_SYNC_TIC_WAIT_1", "thread-sync-tic-wait-1" },
215 { AGS_THREAD_SYNC_TIC_DONE_1, "AGS_THREAD_SYNC_TIC_DONE_1", "thread-sync-tic-done-1" },
216 { AGS_THREAD_SYNC_TIC_WAIT_2, "AGS_THREAD_SYNC_TIC_WAIT_2", "thread-sync-tic-wait-2" },
217 { AGS_THREAD_SYNC_TIC_DONE_2, "AGS_THREAD_SYNC_TIC_DONE_2", "thread-sync-tic-done-2" },
218 { AGS_THREAD_SYNC_TIC_WAIT_3, "AGS_THREAD_SYNC_TIC_WAIT_3", "thread-sync-tic-wait-3" },
219 { AGS_THREAD_SYNC_TIC_DONE_3, "AGS_THREAD_SYNC_TIC_DONE_3", "thread-sync-tic-done-3" },
220 { AGS_THREAD_SYNC_TIC_WAIT_4, "AGS_THREAD_SYNC_TIC_WAIT_4", "thread-sync-tic-wait-4" },
221 { AGS_THREAD_SYNC_TIC_DONE_4, "AGS_THREAD_SYNC_TIC_DONE_4", "thread-sync-tic-done-4" },
222 { AGS_THREAD_SYNC_TIC_WAIT_5, "AGS_THREAD_SYNC_TIC_WAIT_5", "thread-sync-tic-wait-5" },
223 { AGS_THREAD_SYNC_TIC_DONE_5, "AGS_THREAD_SYNC_TIC_DONE_5", "thread-sync-tic-done-5" },
224 { AGS_THREAD_SYNC_TIC_WAIT_6, "AGS_THREAD_SYNC_TIC_WAIT_6", "thread-sync-tic-wait-6" },
225 { AGS_THREAD_SYNC_TIC_DONE_6, "AGS_THREAD_SYNC_TIC_DONE_6", "thread-sync-tic-done-6" },
226 { AGS_THREAD_SYNC_TIC_WAIT_7, "AGS_THREAD_SYNC_TIC_WAIT_7", "thread-sync-tic-wait-7" },
227 { AGS_THREAD_SYNC_TIC_DONE_7, "AGS_THREAD_SYNC_TIC_DONE_7", "thread-sync-tic-done-7" },
228 { AGS_THREAD_SYNC_TIC_WAIT_8, "AGS_THREAD_SYNC_TIC_WAIT_8", "thread-sync-tic-wait-8" },
229 { AGS_THREAD_SYNC_TIC_DONE_8, "AGS_THREAD_SYNC_TIC_DONE_8", "thread-sync-tic-done-8" },
230 { 0, NULL, NULL }
231 };
232
233 GType g_flags_type_id = g_flags_register_static(g_intern_static_string("AgsThreadSyncTicFlags"), values);
234
235 g_once_init_leave (&g_flags_type_id__volatile, g_flags_type_id);
236 }
237
238 return g_flags_type_id__volatile;
239 }
240
241 void
ags_thread_class_init(AgsThreadClass * thread)242 ags_thread_class_init(AgsThreadClass *thread)
243 {
244 GObjectClass *gobject;
245 GParamSpec *param_spec;
246
247 ags_thread_parent_class = g_type_class_peek_parent(thread);
248
249 /* GObject */
250 gobject = (GObjectClass *) thread;
251
252 gobject->set_property = ags_thread_set_property;
253 gobject->get_property = ags_thread_get_property;
254
255 gobject->finalize = ags_thread_finalize;
256
257 /* properties */
258 /**
259 * AgsThread:frequency:
260 *
261 * The frequency to run at in Hz.
262 *
263 * Since: 3.0.0
264 */
265 param_spec = g_param_spec_double("frequency",
266 i18n_pspec("frequency as JIFFIE"),
267 i18n_pspec("frequency as JIFFIE"),
268 0.01,
269 AGS_THREAD_DEFAULT_MAX_PRECISION,
270 AGS_THREAD_DEFAULT_JIFFIE,
271 G_PARAM_READABLE | G_PARAM_WRITABLE);
272 g_object_class_install_property(gobject,
273 PROP_FREQUENCY,
274 param_spec);
275
276 /**
277 * AgsThread:max-precision:
278 *
279 * The max-frequency to run at in Hz.
280 *
281 * Since: 3.0.0
282 */
283 param_spec = g_param_spec_double("max-precision",
284 i18n_pspec("max precision as JIFFIE"),
285 i18n_pspec("The max precision as JIFFIE"),
286 0.01,
287 AGS_THREAD_MAX_PRECISION,
288 AGS_THREAD_DEFAULT_MAX_PRECISION,
289 G_PARAM_READABLE | G_PARAM_WRITABLE);
290 g_object_class_install_property(gobject,
291 PROP_MAX_PRECISION,
292 param_spec);
293
294 /**
295 * AgsThread:delay:
296 *
297 * The delay until next tic.
298 *
299 * Since: 3.0.0
300 */
301 param_spec = g_param_spec_double("delay",
302 i18n_pspec("delay"),
303 i18n_pspec("The delay until next tic"),
304 1.0,
305 AGS_THREAD_DEFAULT_MAX_PRECISION,
306 1.0,
307 G_PARAM_READABLE | G_PARAM_WRITABLE);
308 g_object_class_install_property(gobject,
309 PROP_DELAY,
310 param_spec);
311
312 /* AgsThread */
313 thread->clock = ags_thread_real_clock;
314
315 thread->start = ags_thread_real_start;
316 thread->run = NULL;
317 thread->stop = ags_thread_real_stop;
318
319 /* signals */
320 /**
321 * AgsThread::clock:
322 * @thread: the #AgsThread
323 *
324 * The ::clock() signal is invoked every thread tic.
325 *
326 * Returns: the number of cycles to perform
327 *
328 * Since: 3.0.0
329 */
330 thread_signals[CLOCK] =
331 g_signal_new("clock",
332 G_TYPE_FROM_CLASS (thread),
333 G_SIGNAL_RUN_LAST,
334 G_STRUCT_OFFSET (AgsThreadClass, clock),
335 NULL, NULL,
336 ags_cclosure_marshal_UINT__VOID,
337 G_TYPE_UINT, 0);
338
339
340 /**
341 * AgsThread::start:
342 * @thread: the #AgsThread
343 *
344 * The ::start() signal is invoked as thread started.
345 *
346 * Since: 3.0.0
347 */
348 thread_signals[START] =
349 g_signal_new("start",
350 G_TYPE_FROM_CLASS (thread),
351 G_SIGNAL_RUN_LAST,
352 G_STRUCT_OFFSET (AgsThreadClass, start),
353 NULL, NULL,
354 g_cclosure_marshal_VOID__VOID,
355 G_TYPE_NONE, 0);
356
357 /**
358 * AgsThread::run:
359 * @thread: the #AgsThread
360 *
361 * The ::run() signal is invoked during run loop.
362 *
363 * Since: 3.0.0
364 */
365 thread_signals[RUN] =
366 g_signal_new("run",
367 G_TYPE_FROM_CLASS (thread),
368 G_SIGNAL_RUN_LAST,
369 G_STRUCT_OFFSET (AgsThreadClass, run),
370 NULL, NULL,
371 g_cclosure_marshal_VOID__VOID,
372 G_TYPE_NONE, 0);
373
374 /**
375 * AgsThread::stop:
376 * @thread: the #AgsThread
377 *
378 * The ::stop() signal is invoked as @thread stopped.
379 *
380 * Since: 3.0.0
381 */
382 thread_signals[STOP] =
383 g_signal_new("stop",
384 G_TYPE_FROM_CLASS (thread),
385 G_SIGNAL_RUN_LAST,
386 G_STRUCT_OFFSET (AgsThreadClass, stop),
387 NULL, NULL,
388 g_cclosure_marshal_VOID__VOID,
389 G_TYPE_NONE, 0);
390 }
391
392 void
ags_thread_connectable_interface_init(AgsConnectableInterface * connectable)393 ags_thread_connectable_interface_init(AgsConnectableInterface *connectable)
394 {
395 connectable->get_uuid = ags_thread_get_uuid;
396 connectable->has_resource = ags_thread_has_resource;
397
398 connectable->is_ready = ags_thread_is_ready;
399 connectable->add_to_registry = ags_thread_add_to_registry;
400 connectable->remove_from_registry = ags_thread_remove_from_registry;
401
402 connectable->list_resource = ags_thread_list_resource;
403 connectable->xml_compose = ags_thread_xml_compose;
404 connectable->xml_parse = ags_thread_xml_parse;
405
406 connectable->is_connected = ags_thread_is_connected;
407 connectable->connect = ags_thread_connect;
408 connectable->disconnect = ags_thread_disconnect;
409
410 connectable->connect_connection = NULL;
411 connectable->disconnect_connection = NULL;
412 }
413
414 void
ags_thread_init(AgsThread * thread)415 ags_thread_init(AgsThread *thread)
416 {
417 AgsConfig *config;
418
419 gchar *str;
420
421 int err;
422
423 config = ags_config_get_instance();
424
425 /* the obj mutex */
426 g_rec_mutex_init(&(thread->obj_mutex));
427
428 /* flags and status flags */
429 thread->my_flags = 0;
430
431 g_atomic_int_set(&(thread->status_flags),
432 0);
433
434 g_atomic_int_set(&(thread->sync_tic_flags),
435 0);
436
437 /* uuid */
438 thread->uuid = ags_uuid_alloc();
439 ags_uuid_generate(thread->uuid);
440
441 /* clock */
442 g_atomic_int_set(&(thread->current_sync_tic), 0);
443
444 thread->delay = 1.0;
445
446 thread->tic_delay = 0.0;
447
448 thread->frequency = AGS_THREAD_DEFAULT_JIFFIE;
449
450 thread->max_precision = AGS_THREAD_DEFAULT_MAX_PRECISION;
451
452 /* max precision */
453 str = ags_config_get_value(config,
454 AGS_CONFIG_THREAD,
455 "max-precision");
456
457 if(str != NULL){
458 thread->max_precision = g_ascii_strtod(str,
459 NULL);
460
461 g_free(str);
462 }
463
464 /* the wait mutex and cond */
465 g_mutex_init(&(thread->wait_mutex));
466
467 g_cond_init(&(thread->wait_cond));
468
469 /* thread, tic mutex and cond */
470 thread->thread = NULL;
471
472 g_mutex_init(&(thread->tic_mutex));
473
474 g_cond_init(&(thread->tic_cond));
475
476 /* start notify */
477 thread->start_queue = NULL;
478
479 g_mutex_init(&(thread->start_mutex));
480
481 g_cond_init(&(thread->start_cond));
482
483 /* tree */
484 thread->parent = NULL;
485
486 thread->next = NULL;
487 thread->prev = NULL;
488
489 thread->children = NULL;
490 }
491
492 void
ags_thread_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)493 ags_thread_set_property(GObject *gobject,
494 guint prop_id,
495 const GValue *value,
496 GParamSpec *param_spec)
497 {
498 AgsThread *thread;
499
500 GRecMutex *thread_mutex;
501
502 thread = AGS_THREAD(gobject);
503
504 /* get thread mutex */
505 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
506
507 switch(prop_id){
508 case PROP_FREQUENCY:
509 {
510 gdouble frequency;
511
512 frequency = g_value_get_double(value);
513
514 ags_thread_set_frequency(thread,
515 frequency);
516 }
517 break;
518 case PROP_MAX_PRECISION:
519 {
520 gdouble max_precision;
521
522 max_precision = g_value_get_double(value);
523
524 ags_thread_set_max_precision(thread,
525 max_precision);
526 }
527 break;
528 case PROP_DELAY:
529 {
530 gdouble delay;
531
532 delay = g_value_get_double(value);
533
534 ags_thread_set_delay(thread, delay);
535 }
536 break;
537 default:
538 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
539 break;
540 }
541 }
542
543 void
ags_thread_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)544 ags_thread_get_property(GObject *gobject,
545 guint prop_id,
546 GValue *value,
547 GParamSpec *param_spec)
548 {
549 AgsThread *thread;
550
551 GRecMutex *thread_mutex;
552
553 thread = AGS_THREAD(gobject);
554
555 /* get thread mutex */
556 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
557
558 switch(prop_id){
559 case PROP_FREQUENCY:
560 {
561 g_rec_mutex_lock(thread_mutex);
562
563 g_value_set_double(value, thread->frequency);
564
565 g_rec_mutex_unlock(thread_mutex);
566 }
567 break;
568 case PROP_MAX_PRECISION:
569 {
570 g_rec_mutex_lock(thread_mutex);
571
572 g_value_set_double(value, thread->max_precision);
573
574 g_rec_mutex_unlock(thread_mutex);
575 }
576 break;
577 case PROP_DELAY:
578 {
579 g_rec_mutex_lock(thread_mutex);
580
581 g_value_set_double(value, thread->delay);
582
583 g_rec_mutex_unlock(thread_mutex);
584 }
585 break;
586 default:
587 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
588 break;
589 }
590 }
591
592 void
ags_thread_finalize(GObject * gobject)593 ags_thread_finalize(GObject *gobject)
594 {
595 AgsThread *thread, *parent;
596
597 GThread *thread_ptr;
598
599 gboolean running;
600 gboolean do_exit;
601
602 thread = AGS_THREAD(gobject);
603
604 #ifdef AGS_DEBUG
605 g_message("fin");
606 #endif
607
608 if(thread == ags_thread_self()){
609 do_exit = TRUE;
610 }else{
611 do_exit = FALSE;
612 }
613
614 thread_ptr = thread->thread;
615
616 running = ags_thread_test_status_flags(thread, AGS_THREAD_STATUS_RUNNING);
617
618 #ifdef AGS_DEBUG
619 g_message("fin %s", G_OBJECT_TYPE_NAME(gobject));
620 #endif
621
622 //FIXME:JK: may dead-lock
623 g_list_free(thread->start_queue);
624
625 if((parent = thread->parent) != NULL){
626 g_rec_mutex_lock(AGS_THREAD_GET_OBJ_MUTEX(parent));
627
628 parent->start_queue = g_list_remove(parent->start_queue,
629 thread);
630
631 g_rec_mutex_unlock(AGS_THREAD_GET_OBJ_MUTEX(parent));
632
633 ags_thread_remove_child(parent,
634 thread);
635 }
636
637 /* UUID */
638 ags_uuid_free(thread->uuid);
639
640 /* call parent */
641 G_OBJECT_CLASS(ags_thread_parent_class)->finalize(gobject);
642
643 if(do_exit){
644 g_thread_exit(NULL);
645 }
646 }
647
648 AgsUUID*
ags_thread_get_uuid(AgsConnectable * connectable)649 ags_thread_get_uuid(AgsConnectable *connectable)
650 {
651 AgsThread *thread;
652
653 AgsUUID *ptr;
654
655 GRecMutex *thread_mutex;
656
657 thread = AGS_THREAD(connectable);
658
659 /* get thread mutex */
660 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
661
662 /* get UUID */
663 g_rec_mutex_lock(thread_mutex);
664
665 ptr = thread->uuid;
666
667 g_rec_mutex_unlock(thread_mutex);
668
669 return(ptr);
670 }
671
672 gboolean
ags_thread_has_resource(AgsConnectable * connectable)673 ags_thread_has_resource(AgsConnectable *connectable)
674 {
675 return(FALSE);
676 }
677
678 gboolean
ags_thread_is_ready(AgsConnectable * connectable)679 ags_thread_is_ready(AgsConnectable *connectable)
680 {
681 AgsThread *thread;
682
683 gboolean is_ready;
684
685 thread = AGS_THREAD(connectable);
686
687 /* check is added */
688 is_ready = ags_thread_test_flags(thread, AGS_THREAD_ADDED_TO_REGISTRY);
689
690 return(is_ready);
691 }
692
693 void
ags_thread_add_to_registry(AgsConnectable * connectable)694 ags_thread_add_to_registry(AgsConnectable *connectable)
695 {
696 AgsThread *thread;
697
698 if(ags_connectable_is_ready(connectable)){
699 return;
700 }
701
702 thread = AGS_THREAD(connectable);
703
704 ags_thread_set_flags(thread, AGS_THREAD_ADDED_TO_REGISTRY);
705 }
706
707 void
ags_thread_remove_from_registry(AgsConnectable * connectable)708 ags_thread_remove_from_registry(AgsConnectable *connectable)
709 {
710 if(!ags_connectable_is_ready(connectable)){
711 return;
712 }
713
714 //TODO:JK: implement me
715 }
716
717 xmlNode*
ags_thread_list_resource(AgsConnectable * connectable)718 ags_thread_list_resource(AgsConnectable *connectable)
719 {
720 xmlNode *node;
721
722 node = NULL;
723
724 //TODO:JK: implement me
725
726 return(node);
727 }
728
729 xmlNode*
ags_thread_xml_compose(AgsConnectable * connectable)730 ags_thread_xml_compose(AgsConnectable *connectable)
731 {
732 xmlNode *node;
733
734 node = NULL;
735
736 //TODO:JK: implement me
737
738 return(node);
739 }
740
741 void
ags_thread_xml_parse(AgsConnectable * connectable,xmlNode * node)742 ags_thread_xml_parse(AgsConnectable *connectable,
743 xmlNode *node)
744 {
745 //TODO:JK: implement me
746 }
747
748 gboolean
ags_thread_is_connected(AgsConnectable * connectable)749 ags_thread_is_connected(AgsConnectable *connectable)
750 {
751 AgsThread *thread;
752
753 gboolean is_connected;
754
755 thread = AGS_THREAD(connectable);
756
757 /* check is connected */
758 is_connected = ags_thread_test_flags(thread, AGS_THREAD_CONNECTED);
759
760 return(is_connected);
761 }
762
763 void
ags_thread_connect(AgsConnectable * connectable)764 ags_thread_connect(AgsConnectable *connectable)
765 {
766 AgsThread *thread;
767 AgsThread *children, *current_child, *next_child;
768
769 if(ags_connectable_is_connected(connectable)){
770 return;
771 }
772
773 thread = AGS_THREAD(connectable);
774
775 ags_thread_set_flags(thread, AGS_THREAD_CONNECTED);
776
777 /* recursive connect */
778 children = ags_thread_children(thread);
779
780 if(children != NULL){
781 current_child = children;
782 g_object_ref(current_child);
783
784 while(current_child != NULL){
785 ags_connectable_connect(AGS_CONNECTABLE(current_child));
786
787 /* iterate */
788 next_child = ags_thread_next(current_child);
789
790 g_object_unref(current_child);
791
792 current_child = next_child;
793 }
794
795 g_object_unref(children);
796 }
797 }
798
799 void
ags_thread_disconnect(AgsConnectable * connectable)800 ags_thread_disconnect(AgsConnectable *connectable)
801 {
802 AgsThread *thread;
803 AgsThread *children, *current_child, *next_child;
804
805 if(!ags_connectable_is_connected(connectable)){
806 return;
807 }
808
809 thread = AGS_THREAD(connectable);
810
811 ags_thread_unset_flags(thread, AGS_THREAD_CONNECTED);
812
813 /* recursive connect */
814 children = ags_thread_children(thread);
815
816 if(children != NULL){
817 current_child = children;
818 g_object_ref(current_child);
819
820 while(current_child != NULL){
821 ags_connectable_disconnect(AGS_CONNECTABLE(current_child));
822
823 /* iterate */
824 next_child = ags_thread_next(current_child);
825
826 g_object_unref(current_child);
827
828 current_child = next_child;
829 }
830
831 g_object_unref(children);
832 }
833 }
834
835 /**
836 * ags_thread_global_get_use_sync_counter:
837 *
838 * Get global config value use sync counter.
839 *
840 * Returns: if %TRUE use sync counter, else not
841 *
842 * Since: 3.0.0
843 */
844 gboolean
ags_thread_global_get_use_sync_counter()845 ags_thread_global_get_use_sync_counter()
846 {
847 gboolean use_sync_counter;
848
849 // g_rec_mutex_lock(ags_thread_get_class_mutex());
850
851 use_sync_counter = ags_thread_global_use_sync_counter;
852
853 // g_rec_mutex_unlock(ags_thread_get_class_mutex());
854
855 return(use_sync_counter);
856 }
857
858 /**
859 * ags_thread_test_flags:
860 * @thread: the #AgsThread
861 * @flags: the flags
862 *
863 * Test @flags to be set on @thread.
864 *
865 * Returns: %TRUE if flags are set, else %FALSE
866 *
867 * Since: 3.0.0
868 */
869 gboolean
ags_thread_test_flags(AgsThread * thread,guint flags)870 ags_thread_test_flags(AgsThread *thread, guint flags)
871 {
872 gboolean retval;
873
874 GRecMutex *thread_mutex;
875
876 if(!AGS_IS_THREAD(thread)){
877 return(FALSE);
878 }
879
880 /* get thread mutex */
881 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
882
883 /* test flags */
884 g_rec_mutex_lock(thread_mutex);
885
886 retval = ((flags & (thread->my_flags)) != 0) ? TRUE: FALSE;
887
888 g_rec_mutex_unlock(thread_mutex);
889
890 return(retval);
891 }
892
893 /**
894 * ags_thread_set_flags:
895 * @thread: the #AgsThread
896 * @flags: the flags
897 *
898 * Set flags.
899 *
900 * Since: 3.0.0
901 */
902 void
ags_thread_set_flags(AgsThread * thread,guint flags)903 ags_thread_set_flags(AgsThread *thread, guint flags)
904 {
905 GRecMutex *thread_mutex;
906
907 if(!AGS_IS_THREAD(thread)){
908 return;
909 }
910
911 /* get thread mutex */
912 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
913
914 /* set flags */
915 g_rec_mutex_lock(thread_mutex);
916
917 thread->my_flags |= flags;
918
919 g_rec_mutex_unlock(thread_mutex);
920 }
921
922 /**
923 * ags_thread_unset_flags:
924 * @thread: the #AgsThread
925 * @flags: the flags
926 *
927 * Unset flags.
928 *
929 * Since: 3.0.0
930 */
931 void
ags_thread_unset_flags(AgsThread * thread,guint flags)932 ags_thread_unset_flags(AgsThread *thread, guint flags)
933 {
934 GRecMutex *thread_mutex;
935
936 if(!AGS_IS_THREAD(thread)){
937 return;
938 }
939
940 /* get thread mutex */
941 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
942
943 /* set flags */
944 g_rec_mutex_lock(thread_mutex);
945
946 thread->my_flags &= (~flags);
947
948 g_rec_mutex_unlock(thread_mutex);
949 }
950
951 /**
952 * ags_thread_test_status_flags:
953 * @thread: the #AgsThread
954 * @status_flags: the status flags
955 *
956 * Test @status_flags to be set on @thread.
957 *
958 * Returns: %TRUE if status flags are set, else %FALSE
959 *
960 * Since: 3.0.0
961 */
962 gboolean
ags_thread_test_status_flags(AgsThread * thread,guint status_flags)963 ags_thread_test_status_flags(AgsThread *thread, guint status_flags)
964 {
965 gboolean retval;
966
967 if(!AGS_IS_THREAD(thread)){
968 return(FALSE);
969 }
970
971 retval = ((status_flags & (g_atomic_int_get(&(thread->status_flags)))) != 0) ? TRUE: FALSE;
972
973 return(retval);
974 }
975
976 /**
977 * ags_thread_set_status_flags:
978 * @thread: the #AgsThread
979 * @status_flags: the status flags
980 *
981 * Set status flags.
982 *
983 * Since: 3.0.0
984 */
985 void
ags_thread_set_status_flags(AgsThread * thread,guint status_flags)986 ags_thread_set_status_flags(AgsThread *thread, guint status_flags)
987 {
988 if(!AGS_IS_THREAD(thread)){
989 return;
990 }
991
992 g_atomic_int_or(&(thread->status_flags), status_flags);
993 }
994
995 /**
996 * ags_thread_unset_status_flags:
997 * @thread: the #AgsThread
998 * @status_flags: the status flags
999 *
1000 * Unset status flags.
1001 *
1002 * Since: 3.0.0
1003 */
1004 void
ags_thread_unset_status_flags(AgsThread * thread,guint status_flags)1005 ags_thread_unset_status_flags(AgsThread *thread, guint status_flags)
1006 {
1007 if(!AGS_IS_THREAD(thread)){
1008 return;
1009 }
1010
1011 g_atomic_int_and(&(thread->status_flags), (~status_flags));
1012 }
1013
1014 /**
1015 * ags_thread_clear_status_flags:
1016 * @thread: the #AgsThread
1017 *
1018 * Clear status flags.
1019 *
1020 * Since: 3.0.0
1021 */
1022 void
ags_thread_clear_status_flags(AgsThread * thread)1023 ags_thread_clear_status_flags(AgsThread *thread)
1024 {
1025 if(!AGS_IS_THREAD(thread)){
1026 return;
1027 }
1028
1029 g_atomic_int_set(&(thread->status_flags), 0);
1030 }
1031
1032 /**
1033 * ags_thread_test_sync_tic_flags:
1034 * @thread: the #AgsThread
1035 * @sync_tic_flags: the sync-tic flags
1036 *
1037 * Test @sync_tic_flags to be set on @thread.
1038 *
1039 * Returns: %TRUE if sync-tic flags are set, else %FALSE
1040 *
1041 * Since: 3.0.0
1042 */
1043 gboolean
ags_thread_test_sync_tic_flags(AgsThread * thread,guint sync_tic_flags)1044 ags_thread_test_sync_tic_flags(AgsThread *thread, guint sync_tic_flags)
1045 {
1046 gboolean retval;
1047
1048 if(!AGS_IS_THREAD(thread)){
1049 return(FALSE);
1050 }
1051
1052 retval = ((sync_tic_flags & (g_atomic_int_get(&(thread->sync_tic_flags)))) != 0) ? TRUE: FALSE;
1053
1054 return(retval);
1055 }
1056
1057 /**
1058 * ags_thread_set_sync_tic_flags:
1059 * @thread: the #AgsThread
1060 * @sync_tic_flags: the sync-tic flags
1061 *
1062 * Set sync-tic flags.
1063 *
1064 * Since: 3.0.0
1065 */
1066 void
ags_thread_set_sync_tic_flags(AgsThread * thread,guint sync_tic_flags)1067 ags_thread_set_sync_tic_flags(AgsThread *thread, guint sync_tic_flags)
1068 {
1069 if(!AGS_IS_THREAD(thread)){
1070 return;
1071 }
1072
1073 g_atomic_int_or(&(thread->sync_tic_flags), sync_tic_flags);
1074 }
1075
1076 /**
1077 * ags_thread_unset_sync_tic_flags:
1078 * @thread: the #AgsThread
1079 * @sync_tic_flags: the sync-tic flags
1080 *
1081 * Unset sync-tic flags.
1082 *
1083 * Since: 3.0.0
1084 */
1085 void
ags_thread_unset_sync_tic_flags(AgsThread * thread,guint sync_tic_flags)1086 ags_thread_unset_sync_tic_flags(AgsThread *thread, guint sync_tic_flags)
1087 {
1088 if(!AGS_IS_THREAD(thread)){
1089 return;
1090 }
1091
1092 g_atomic_int_and(&(thread->sync_tic_flags), (~sync_tic_flags));
1093 }
1094
1095 /**
1096 * ags_thread_clear_sync_tic_flags:
1097 * @thread: the #AgsThread
1098 *
1099 * Clear sync-tic flags.
1100 *
1101 * Since: 3.0.0
1102 */
1103 void
ags_thread_clear_sync_tic_flags(AgsThread * thread)1104 ags_thread_clear_sync_tic_flags(AgsThread *thread)
1105 {
1106 if(!AGS_IS_THREAD(thread)){
1107 return;
1108 }
1109
1110 g_atomic_int_set(&(thread->sync_tic_flags), 0);
1111 }
1112
1113 /**
1114 * ags_thread_set_current_sync_tic:
1115 * @thread: the #AgsThread
1116 * @current_sync_tic: the current sync-tic
1117 *
1118 * Set current sync-tic.
1119 *
1120 * Since: 3.0.0
1121 */
1122 void
ags_thread_set_current_sync_tic(AgsThread * thread,guint current_sync_tic)1123 ags_thread_set_current_sync_tic(AgsThread *thread, guint current_sync_tic)
1124 {
1125 if(!AGS_IS_THREAD(thread)){
1126 return;
1127 }
1128
1129 g_atomic_int_set(&(thread->current_sync_tic), current_sync_tic);
1130 }
1131
1132 /**
1133 * ags_thread_get_current_sync_tic:
1134 * @thread: the #AgsThread
1135 *
1136 * Get current sync-tic.
1137 *
1138 * Returns: the current sync-tic
1139 *
1140 * Since: 3.0.0
1141 */
1142 guint
ags_thread_get_current_sync_tic(AgsThread * thread)1143 ags_thread_get_current_sync_tic(AgsThread *thread)
1144 {
1145 guint current_sync_tic;
1146
1147 if(!AGS_IS_THREAD(thread)){
1148 return(G_MAXUINT);
1149 }
1150
1151 current_sync_tic = g_atomic_int_get(&(thread->current_sync_tic));
1152
1153 return(current_sync_tic);
1154 }
1155
1156 /**
1157 * ags_thread_set_delay:
1158 * @thread: the #AgsThread
1159 * @delay: the delay
1160 *
1161 * Set delay.
1162 *
1163 * Since: 3.0.0
1164 */
1165 void
ags_thread_set_delay(AgsThread * thread,gdouble delay)1166 ags_thread_set_delay(AgsThread *thread, gdouble delay)
1167 {
1168 GRecMutex *thread_mutex;
1169
1170 if(!AGS_IS_THREAD(thread)){
1171 return;
1172 }
1173
1174 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1175
1176 g_rec_mutex_lock(thread_mutex);
1177
1178 thread->delay = delay;
1179
1180 g_rec_mutex_unlock(thread_mutex);
1181 }
1182
1183 /**
1184 * ags_thread_get_delay:
1185 * @thread: the #AgsThread
1186 *
1187 * Get delay.
1188 *
1189 * Returns: the delay
1190 *
1191 * Since: 3.0.0
1192 */
1193 gdouble
ags_thread_get_delay(AgsThread * thread)1194 ags_thread_get_delay(AgsThread *thread)
1195 {
1196 gdouble delay;
1197
1198 GRecMutex *thread_mutex;
1199
1200 if(!AGS_IS_THREAD(thread)){
1201 return(0.0);
1202 }
1203
1204 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1205
1206 g_rec_mutex_lock(thread_mutex);
1207
1208 delay = thread->delay;
1209
1210 g_rec_mutex_unlock(thread_mutex);
1211
1212 return(delay);
1213 }
1214
1215 /**
1216 * ags_thread_set_frequency:
1217 * @thread: the #AgsThread
1218 * @frequency: the frequency
1219 *
1220 * Set frequency.
1221 *
1222 * Since: 3.0.0
1223 */
1224 void
ags_thread_set_frequency(AgsThread * thread,gdouble frequency)1225 ags_thread_set_frequency(AgsThread *thread, gdouble frequency)
1226 {
1227 GRecMutex *thread_mutex;
1228
1229 if(!AGS_IS_THREAD(thread)){
1230 return;
1231 }
1232
1233 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1234
1235 g_rec_mutex_lock(thread_mutex);
1236
1237 if(frequency == thread->frequency){
1238 g_rec_mutex_unlock(thread_mutex);
1239
1240 return;
1241 }
1242
1243 thread->frequency = frequency;
1244
1245 thread->delay = (guint) ceil((AGS_THREAD_HERTZ_JIFFIE / thread->frequency) / (AGS_THREAD_HERTZ_JIFFIE / thread->max_precision));
1246 thread->tic_delay = 0.0;
1247
1248 if(ags_thread_test_flags(thread, AGS_THREAD_INTERMEDIATE_POST_SYNC)){
1249 thread->tic_delay = thread->delay;
1250 }else if(ags_thread_test_flags(thread, AGS_THREAD_INTERMEDIATE_PRE_SYNC)){
1251 thread->tic_delay = 1.0;
1252 }else{
1253 thread->tic_delay = 0.0;
1254 }
1255
1256 g_rec_mutex_unlock(thread_mutex);
1257 }
1258
1259 /**
1260 * ags_thread_get_frequency:
1261 * @thread: the #AgsThread
1262 *
1263 * Get frequency.
1264 *
1265 * Returns: the frequency
1266 *
1267 * Since: 3.0.0
1268 */
1269 gdouble
ags_thread_get_frequency(AgsThread * thread)1270 ags_thread_get_frequency(AgsThread *thread)
1271 {
1272 gdouble frequency;
1273
1274 GRecMutex *thread_mutex;
1275
1276 if(!AGS_IS_THREAD(thread)){
1277 return(-1.0);
1278 }
1279
1280 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1281
1282 g_rec_mutex_lock(thread_mutex);
1283
1284 frequency = thread->frequency;
1285
1286 g_rec_mutex_unlock(thread_mutex);
1287
1288 return(frequency);
1289 }
1290
1291 /**
1292 * ags_thread_set_max_precision:
1293 * @thread: the #AgsThread
1294 * @max_precision: the max-precision
1295 *
1296 * Set max-precision.
1297 *
1298 * Since: 3.0.0
1299 */
1300 void
ags_thread_set_max_precision(AgsThread * thread,gdouble max_precision)1301 ags_thread_set_max_precision(AgsThread *thread, gdouble max_precision)
1302 {
1303 gdouble old_max_precision;
1304
1305 GRecMutex *thread_mutex;
1306
1307 if(!AGS_IS_THREAD(thread)){
1308 return;
1309 }
1310
1311 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1312
1313 g_rec_mutex_lock(thread_mutex);
1314
1315 old_max_precision = thread->max_precision;
1316
1317 if(max_precision == old_max_precision){
1318 g_rec_mutex_unlock(thread_mutex);
1319
1320 return;
1321 }
1322
1323 thread->max_precision = max_precision;
1324
1325 thread->frequency = thread->frequency / old_max_precision * max_precision;
1326
1327 thread->delay = (AGS_THREAD_HERTZ_JIFFIE / thread->frequency) / (AGS_THREAD_HERTZ_JIFFIE / thread->max_precision);
1328 thread->tic_delay = 0.0;
1329
1330 if(ags_thread_test_flags(thread, AGS_THREAD_INTERMEDIATE_POST_SYNC)){
1331 thread->tic_delay = floor(thread->delay); // thread->delay;
1332 }else if(ags_thread_test_flags(thread, AGS_THREAD_INTERMEDIATE_PRE_SYNC)){
1333 thread->tic_delay = 1.0;
1334 }else{
1335 thread->tic_delay = 0.0;
1336 }
1337
1338 g_rec_mutex_unlock(thread_mutex);
1339 }
1340
1341 /**
1342 * ags_thread_get_max_precision:
1343 * @thread: the #AgsThread
1344 *
1345 * Get max-precision.
1346 *
1347 * Returns: the max-precision
1348 *
1349 * Since: 3.0.0
1350 */
1351 gdouble
ags_thread_get_max_precision(AgsThread * thread)1352 ags_thread_get_max_precision(AgsThread *thread)
1353 {
1354 gdouble max_precision;
1355
1356 GRecMutex *thread_mutex;
1357
1358 if(!AGS_IS_THREAD(thread)){
1359 return(-1.0);
1360 }
1361
1362 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1363
1364 g_rec_mutex_lock(thread_mutex);
1365
1366 max_precision = thread->max_precision;
1367
1368 g_rec_mutex_unlock(thread_mutex);
1369
1370 return(max_precision);
1371 }
1372
1373 /**
1374 * ags_thread_parent:
1375 * @thread: the #AgsThread
1376 *
1377 * Get parent thread.
1378 *
1379 * Returns: (transfer full): the parent #AgsThread
1380 *
1381 * Since: 3.0.0
1382 */
1383 AgsThread*
ags_thread_parent(AgsThread * thread)1384 ags_thread_parent(AgsThread *thread)
1385 {
1386 AgsThread *parent;
1387
1388 GRecMutex *thread_mutex;
1389
1390 if(!AGS_IS_THREAD(thread)){
1391 return(NULL);
1392 }
1393
1394 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1395
1396 g_rec_mutex_lock(thread_mutex);
1397
1398 parent = thread->parent;
1399
1400 g_rec_mutex_unlock(thread_mutex);
1401
1402 if(parent != NULL){
1403 g_object_ref(parent);
1404 }
1405
1406 return(parent);
1407 }
1408
1409 /**
1410 * ags_thread_next:
1411 * @thread: the #AgsThread
1412 *
1413 * Get next thread.
1414 *
1415 * Returns: (transfer full): the next #AgsThread
1416 *
1417 * Since: 3.0.0
1418 */
1419 AgsThread*
ags_thread_next(AgsThread * thread)1420 ags_thread_next(AgsThread *thread)
1421 {
1422 AgsThread *next;
1423
1424 GRecMutex *thread_mutex;
1425
1426 if(!AGS_IS_THREAD(thread)){
1427 return(NULL);
1428 }
1429
1430 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1431
1432 g_rec_mutex_lock(thread_mutex);
1433
1434 next = thread->next;
1435
1436 if(next != NULL){
1437 g_object_ref(next);
1438 }
1439
1440 g_rec_mutex_unlock(thread_mutex);
1441
1442 return(next);
1443 }
1444
1445 /**
1446 * ags_thread_prev:
1447 * @thread: the #AgsThread
1448 *
1449 * Get prev thread.
1450 *
1451 * Returns: (transfer full): the prev #AgsThread
1452 *
1453 * Since: 3.0.0
1454 */
1455 AgsThread*
ags_thread_prev(AgsThread * thread)1456 ags_thread_prev(AgsThread *thread)
1457 {
1458 AgsThread *prev;
1459
1460 GRecMutex *thread_mutex;
1461
1462 if(!AGS_IS_THREAD(thread)){
1463 return(NULL);
1464 }
1465
1466 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1467
1468 g_rec_mutex_lock(thread_mutex);
1469
1470 prev = thread->prev;
1471
1472 if(prev != NULL){
1473 g_object_ref(prev);
1474 }
1475
1476 g_rec_mutex_unlock(thread_mutex);
1477
1478 return(prev);
1479 }
1480
1481 /**
1482 * ags_thread_children:
1483 * @thread: the #AgsThread
1484 *
1485 * Get children thread.
1486 *
1487 * Returns: (transfer full): the children #AgsThread
1488 *
1489 * Since: 3.0.0
1490 */
1491 AgsThread*
ags_thread_children(AgsThread * thread)1492 ags_thread_children(AgsThread *thread)
1493 {
1494 AgsThread *children;
1495
1496 GRecMutex *thread_mutex;
1497
1498 if(!AGS_IS_THREAD(thread)){
1499 return(NULL);
1500 }
1501
1502 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1503
1504 g_rec_mutex_lock(thread_mutex);
1505
1506 children = thread->children;
1507
1508 if(children != NULL){
1509 g_object_ref(children);
1510 }
1511
1512 g_rec_mutex_unlock(thread_mutex);
1513
1514 return(children);
1515 }
1516
1517 /**
1518 * ags_thread_get_toplevel:
1519 * @thread: the #AgsThread
1520 *
1521 * Retrieve toplevel thread.
1522 *
1523 * Returns: (transfer full): the toplevevel #AgsThread
1524 *
1525 * Since: 3.0.0
1526 */
1527 AgsThread*
ags_thread_get_toplevel(AgsThread * thread)1528 ags_thread_get_toplevel(AgsThread *thread)
1529 {
1530 AgsThread *current, *current_parent;
1531
1532 if(!AGS_IS_THREAD(thread)){
1533 return(NULL);
1534 }
1535
1536 current = thread;
1537 g_object_ref(current);
1538
1539 while((current_parent = ags_thread_parent(current)) != NULL){
1540 /* iterate */
1541 g_object_unref(current);
1542
1543 current = current_parent;
1544 }
1545
1546 return(current);
1547 }
1548
1549 /**
1550 * ags_thread_first:
1551 * @thread: the #AgsThread
1552 *
1553 * Retrieve first sibling.
1554 *
1555 * Returns: (transfer full): the very first #AgsThread within same tree level
1556 *
1557 * Since: 3.0.0
1558 */
1559 AgsThread*
ags_thread_first(AgsThread * thread)1560 ags_thread_first(AgsThread *thread)
1561 {
1562 AgsThread *current, *current_prev;
1563
1564 if(!AGS_IS_THREAD(thread)){
1565 return(NULL);
1566 }
1567
1568 current = thread;
1569 g_object_ref(current);
1570
1571 while((current_prev = ags_thread_prev(current)) != NULL){
1572 /* iterate */
1573 g_object_unref(current);
1574
1575 current = current_prev;
1576 }
1577
1578 return(current);
1579 }
1580
1581 /**
1582 * ags_thread_last:
1583 * @thread: the #AgsThread
1584 *
1585 * Retrieve last sibling.
1586 *
1587 * Returns: (transfer full): the very last @AgsThread within same tree level
1588 *
1589 * Since: 3.0.0
1590 */
1591 AgsThread*
ags_thread_last(AgsThread * thread)1592 ags_thread_last(AgsThread *thread)
1593 {
1594 AgsThread *current, *current_next;
1595
1596 if(!AGS_IS_THREAD(thread)){
1597 return(NULL);
1598 }
1599
1600 current = thread;
1601 g_object_ref(current);
1602
1603 while((current_next = ags_thread_next(current)) != NULL){
1604 /* iterate */
1605 g_object_unref(current);
1606
1607 current = current_next;
1608 }
1609
1610 return(current);
1611 }
1612
1613 /**
1614 * ags_thread_lock:
1615 * @thread: the #AgsThread
1616 *
1617 * Locks the threads own mutex and sets the appropriate flag.
1618 *
1619 * Since: 3.0.0
1620 */
1621 void
ags_thread_lock(AgsThread * thread)1622 ags_thread_lock(AgsThread *thread)
1623 {
1624 GRecMutex *mutex;
1625
1626 if(!AGS_IS_THREAD(thread)){
1627 return;
1628 }
1629
1630 /* mutex */
1631 mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1632
1633 /* lock */
1634 g_rec_mutex_lock(mutex);
1635 }
1636
1637 /**
1638 * ags_thread_trylock:
1639 * @thread: the #AgsThread
1640 *
1641 * Locks the threads own mutex if available and sets the
1642 * appropriate flag and returning %TRUE. Otherwise return %FALSE
1643 * without lock.
1644 *
1645 * Returns: %TRUE on success, otherwise %FALSE
1646 *
1647 * Since: 3.0.0
1648 */
1649 gboolean
ags_thread_trylock(AgsThread * thread)1650 ags_thread_trylock(AgsThread *thread)
1651 {
1652 GRecMutex *mutex;
1653
1654 if(!AGS_IS_THREAD(thread)){
1655 return(FALSE);
1656 }
1657
1658 /* lookup mutices */
1659 mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1660
1661 /* lock */
1662 if(!g_rec_mutex_trylock(mutex)){
1663 return(FALSE);
1664 }
1665
1666 return(TRUE);
1667 }
1668
1669 /**
1670 * ags_thread_unlock:
1671 * @thread: the #AgsThread
1672 *
1673 * Unlocks the threads own mutex and unsets the appropriate flag.
1674 *
1675 * Since: 3.0.0
1676 */
1677 void
ags_thread_unlock(AgsThread * thread)1678 ags_thread_unlock(AgsThread *thread)
1679 {
1680 GRecMutex *mutex;
1681
1682 if(!AGS_IS_THREAD(thread)){
1683 return;
1684 }
1685
1686 /* mutex */
1687 mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
1688
1689 /* unlock */
1690 g_rec_mutex_unlock(mutex);
1691 }
1692
1693 /**
1694 * ags_thread_remove_child:
1695 * @thread: the #AgsThread
1696 * @child: the child to remove
1697 *
1698 * Remove child of thread.
1699 *
1700 * Since: 3.0.0
1701 */
1702 void
ags_thread_remove_child(AgsThread * thread,AgsThread * child)1703 ags_thread_remove_child(AgsThread *thread, AgsThread *child)
1704 {
1705 AgsThread *children, *current_child, *next_child, *prev_child;
1706
1707 gboolean found_child;
1708
1709 if(!AGS_IS_THREAD(thread) ||
1710 !AGS_IS_THREAD(child)){
1711 return;
1712 }
1713
1714 children = ags_thread_children(thread);
1715
1716 if(children == NULL){
1717 return;
1718 }
1719
1720 current_child = children;
1721 g_object_ref(current_child);
1722
1723 found_child = FALSE;
1724
1725 while(current_child != NULL){
1726 if(current_child == child){
1727 found_child = TRUE;
1728
1729 break;
1730 }
1731
1732 /* iterate */
1733 next_child = ags_thread_next(current_child);
1734
1735 g_object_unref(current_child);
1736
1737 current_child = next_child;
1738 }
1739
1740 g_object_unref(children);
1741
1742 if(found_child){
1743 gboolean is_first, is_last;
1744
1745 g_rec_mutex_lock(AGS_THREAD_GET_OBJ_MUTEX(child));
1746
1747 is_first = (child->prev == NULL) ? TRUE: FALSE;
1748 is_last = (child->next == NULL) ? TRUE: FALSE;
1749
1750 child->parent = NULL;
1751
1752 g_rec_mutex_unlock(AGS_THREAD_GET_OBJ_MUTEX(child));
1753
1754 if(is_first){
1755 next_child = ags_thread_next(child);
1756
1757 g_rec_mutex_lock(AGS_THREAD_GET_OBJ_MUTEX(thread));
1758
1759 thread->children = next_child;
1760
1761 g_rec_mutex_unlock(AGS_THREAD_GET_OBJ_MUTEX(thread));
1762 }
1763
1764 next_child = ags_thread_next(child);
1765 prev_child = ags_thread_prev(child);
1766
1767 /* reset child */
1768 g_rec_mutex_lock(AGS_THREAD_GET_OBJ_MUTEX(child));
1769
1770 child->next = NULL;
1771 child->prev = NULL;
1772
1773 g_rec_mutex_unlock(AGS_THREAD_GET_OBJ_MUTEX(child));
1774
1775 if(next_child != NULL){
1776 g_object_unref(next_child);
1777 }
1778
1779 if(prev_child != NULL){
1780 g_object_unref(prev_child);
1781 }
1782
1783 /* relink */
1784 if(next_child != NULL){
1785 g_rec_mutex_lock(AGS_THREAD_GET_OBJ_MUTEX(next_child));
1786
1787 next_child->prev = prev_child;
1788
1789 g_rec_mutex_unlock(AGS_THREAD_GET_OBJ_MUTEX(next_child));
1790 }
1791
1792 if(prev_child != NULL){
1793 g_rec_mutex_lock(AGS_THREAD_GET_OBJ_MUTEX(prev_child));
1794
1795 prev_child->next = next_child;
1796
1797 g_rec_mutex_unlock(AGS_THREAD_GET_OBJ_MUTEX(prev_child));
1798 }
1799
1800 g_object_unref(thread);
1801 }
1802 }
1803
1804 /**
1805 * ags_thread_add_child:
1806 * @thread: the #AgsThread
1807 * @child: the child to remove
1808 *
1809 * Add child to thread.
1810 *
1811 * Since: 3.0.0
1812 */
1813 void
ags_thread_add_child(AgsThread * thread,AgsThread * child)1814 ags_thread_add_child(AgsThread *thread, AgsThread *child)
1815 {
1816 ags_thread_add_child_extended(thread, child,
1817 FALSE, TRUE);
1818 }
1819
1820 /**
1821 * ags_thread_add_child_extended:
1822 * @thread: the #AgsThread
1823 * @child: the child to remove
1824 * @no_start: don't start thread
1825 * @no_wait: don't wait until started
1826 *
1827 * Add child to thread.
1828 *
1829 * Since: 3.0.0
1830 */
1831 void
ags_thread_add_child_extended(AgsThread * thread,AgsThread * child,gboolean no_start,gboolean no_wait)1832 ags_thread_add_child_extended(AgsThread *thread, AgsThread *child,
1833 gboolean no_start, gboolean no_wait)
1834 {
1835 AgsThread *main_loop;
1836 AgsThread *current_parent;
1837 AgsThread *children;
1838 AgsThread *last_child;
1839
1840 GRecMutex *tree_lock;
1841
1842 if(!AGS_IS_THREAD(thread) ||
1843 !AGS_IS_THREAD(child)){
1844 return;
1845 }
1846
1847 /* check current parent */
1848 current_parent = ags_thread_parent(child);
1849
1850 if(current_parent == thread){
1851 #if 0
1852 if(current_parent != NULL){
1853 g_object_unref(current_parent);
1854 }
1855 #endif
1856
1857 return;
1858 }
1859
1860 main_loop = ags_concurrency_provider_get_main_loop(AGS_CONCURRENCY_PROVIDER(ags_application_context_get_instance()));
1861
1862 tree_lock = NULL;
1863
1864 if(main_loop != NULL){
1865 tree_lock = ags_main_loop_get_tree_lock(AGS_MAIN_LOOP(main_loop));
1866 }
1867
1868 if(tree_lock != NULL){
1869 g_rec_mutex_lock(tree_lock);
1870 }
1871
1872 if(current_parent != NULL){
1873 g_object_unref(current_parent);
1874 }
1875
1876 g_object_ref(thread);
1877 g_object_ref(child);
1878
1879 g_rec_mutex_lock(AGS_THREAD_GET_OBJ_MUTEX(child));
1880
1881 child->parent = thread;
1882
1883 g_rec_mutex_unlock(AGS_THREAD_GET_OBJ_MUTEX(child));
1884
1885 children = ags_thread_children(thread);
1886
1887 if(children == NULL){
1888 g_rec_mutex_lock(AGS_THREAD_GET_OBJ_MUTEX(thread));
1889
1890 thread->children = child;
1891
1892 g_rec_mutex_unlock(AGS_THREAD_GET_OBJ_MUTEX(thread));
1893 }else{
1894 last_child = ags_thread_last(children);
1895
1896 /* next */
1897 g_rec_mutex_lock(AGS_THREAD_GET_OBJ_MUTEX(last_child));
1898
1899 last_child->next = child;
1900 g_object_ref(child);
1901
1902 g_rec_mutex_unlock(AGS_THREAD_GET_OBJ_MUTEX(last_child));
1903
1904 /* prev */
1905 g_rec_mutex_lock(AGS_THREAD_GET_OBJ_MUTEX(child));
1906
1907 child->prev = last_child;
1908
1909 g_rec_mutex_unlock(AGS_THREAD_GET_OBJ_MUTEX(child));
1910
1911 /* unref */
1912 g_object_unref(children);
1913 }
1914
1915 if(tree_lock != NULL){
1916 g_rec_mutex_unlock(tree_lock);
1917 }
1918
1919 if(main_loop != NULL){
1920 g_object_unref(main_loop);
1921 }
1922
1923 if(!no_start){
1924 if(!ags_thread_test_status_flags(thread, AGS_THREAD_STATUS_RUNNING)){
1925 /* start child */
1926 ags_thread_start(child);
1927
1928 if(!no_wait){
1929 guint val;
1930
1931 /* wait child */
1932 g_mutex_lock(AGS_THREAD_GET_START_MUTEX(child));
1933
1934 ags_thread_set_status_flags(child, AGS_THREAD_STATUS_START_WAIT);
1935
1936 if(ags_thread_test_status_flags(child, AGS_THREAD_STATUS_START_WAIT) &&
1937 !ags_thread_test_status_flags(child, AGS_THREAD_STATUS_START_DONE)){
1938 while(ags_thread_test_status_flags(child, AGS_THREAD_STATUS_START_WAIT) &&
1939 !ags_thread_test_status_flags(child, AGS_THREAD_STATUS_START_DONE)){
1940 g_cond_wait(AGS_THREAD_GET_START_COND(child),
1941 AGS_THREAD_GET_START_MUTEX(child));
1942 }
1943 }
1944
1945 g_mutex_unlock(AGS_THREAD_GET_START_MUTEX(child));
1946 }
1947 }
1948 }
1949 }
1950
1951 gboolean
ags_thread_is_current_ready(AgsThread * current,guint current_sync_tic)1952 ags_thread_is_current_ready(AgsThread *current, guint current_sync_tic)
1953 {
1954 guint sync_tic;
1955 gboolean is_current_ready;
1956
1957 if(!AGS_IS_THREAD(current)){
1958 return(TRUE);
1959 }
1960
1961 if((!ags_thread_test_status_flags(current, AGS_THREAD_STATUS_RUNNING) &&
1962 !ags_thread_test_status_flags(current, AGS_THREAD_STATUS_READY)) ||
1963 ags_thread_test_status_flags(current, AGS_THREAD_STATUS_IS_CHAOS_TREE)){
1964 return(TRUE);
1965 }
1966
1967 is_current_ready = TRUE;
1968
1969 /* check current sync tic */
1970 sync_tic = ags_thread_get_current_sync_tic(current);
1971
1972 if(current_sync_tic == sync_tic){
1973 if(!ags_thread_test_status_flags(current, AGS_THREAD_STATUS_WAITING)){
1974 is_current_ready = FALSE;
1975 }
1976 }
1977
1978 return(is_current_ready);
1979 }
1980
1981 gboolean
ags_thread_is_tree_ready_recursive(AgsThread * thread,guint current_sync_tic)1982 ags_thread_is_tree_ready_recursive(AgsThread *thread, guint current_sync_tic)
1983 {
1984 AgsThread *child, *next_child;
1985
1986 gboolean is_tree_ready;
1987
1988 if(!AGS_IS_THREAD(thread)){
1989 return(TRUE);
1990 }
1991
1992 is_tree_ready = ags_thread_is_current_ready(thread, current_sync_tic);
1993
1994 if(!is_tree_ready){
1995 return(FALSE);
1996 }
1997
1998 /* set tree sync recursive */
1999 child = ags_thread_children(thread);
2000
2001 while(child != NULL){
2002 is_tree_ready = ags_thread_is_tree_ready_recursive(child, current_sync_tic);
2003
2004 if(!is_tree_ready){
2005 g_object_unref(child);
2006
2007 return(FALSE);
2008 }
2009
2010 /* iterate */
2011 next_child = ags_thread_next(child);
2012
2013 g_object_unref(child);
2014
2015 child = next_child;
2016 }
2017
2018 return(TRUE);
2019 }
2020
2021 void
ags_thread_prepare_current_sync(AgsThread * current,guint current_sync_tic)2022 ags_thread_prepare_current_sync(AgsThread *current, guint current_sync_tic)
2023 {
2024 if(!AGS_IS_THREAD(current)){
2025 return;
2026 }
2027
2028 /* get current mutex */
2029 if((!ags_thread_test_status_flags(current, AGS_THREAD_STATUS_RUNNING) &&
2030 !ags_thread_test_status_flags(current, AGS_THREAD_STATUS_READY)) ||
2031 ags_thread_test_status_flags(current, AGS_THREAD_STATUS_IS_CHAOS_TREE)){
2032 return;
2033 }
2034
2035 if(ags_thread_get_current_sync_tic(current) != current_sync_tic){
2036 g_critical("out-of-sync - main sync-tic != current sync-tic");
2037
2038 return;
2039 }
2040
2041 ags_thread_set_status_flags(current, AGS_THREAD_STATUS_SYNCED);
2042 }
2043
2044 void
ags_thread_prepare_tree_sync_recursive(AgsThread * thread,guint current_sync_tic)2045 ags_thread_prepare_tree_sync_recursive(AgsThread *thread, guint current_sync_tic)
2046 {
2047 AgsThread *child, *next_child;
2048
2049 if(!AGS_IS_THREAD(thread)){
2050 return;
2051 }
2052
2053 ags_thread_prepare_current_sync(thread, current_sync_tic);
2054
2055 /* set tree sync recursive */
2056 child = ags_thread_children(thread);
2057
2058 while(child != NULL){
2059 ags_thread_prepare_tree_sync_recursive(child, current_sync_tic);
2060
2061 /* iterate */
2062 next_child = ags_thread_next(child);
2063
2064 g_object_unref(child);
2065
2066 child = next_child;
2067 }
2068 }
2069
2070 void
ags_thread_set_current_sync(AgsThread * current,guint current_sync_tic)2071 ags_thread_set_current_sync(AgsThread *current, guint current_sync_tic)
2072 {
2073 guint next_current_sync_tic;
2074 guint sync_tic_wait, sync_tic_done;
2075
2076 GMutex *wait_mutex;
2077 GCond *wait_cond;
2078
2079 if(!AGS_IS_THREAD(current)){
2080 return;
2081 }
2082
2083 /* get current mutex */
2084 if((!ags_thread_test_status_flags(current, AGS_THREAD_STATUS_RUNNING) &&
2085 !ags_thread_test_status_flags(current, AGS_THREAD_STATUS_READY)) ||
2086 ags_thread_test_status_flags(current, AGS_THREAD_STATUS_IS_CHAOS_TREE)){
2087 return;
2088 }
2089
2090 if(ags_thread_get_current_sync_tic(current) != current_sync_tic){
2091 g_critical("out-of-sync - main sync-tic != current sync-tic");
2092
2093 return;
2094 }
2095
2096 wait_mutex = AGS_THREAD_GET_WAIT_MUTEX(current);
2097 wait_cond = AGS_THREAD_GET_WAIT_COND(current);
2098
2099 next_current_sync_tic = G_MAXUINT;
2100
2101 sync_tic_wait = 0;
2102 sync_tic_done = 0;
2103
2104 switch(current_sync_tic){
2105 case 0:
2106 {
2107 next_current_sync_tic = 1;
2108
2109 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_0;
2110 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_0;
2111 }
2112 break;
2113 case 1:
2114 {
2115 next_current_sync_tic = 2;
2116
2117 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_1;
2118 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_1;
2119 }
2120 break;
2121 case 2:
2122 {
2123 next_current_sync_tic = 3;
2124
2125 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_2;
2126 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_2;
2127 }
2128 break;
2129 case 3:
2130 {
2131 next_current_sync_tic = 4;
2132
2133 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_3;
2134 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_3;
2135 }
2136 break;
2137 case 4:
2138 {
2139 next_current_sync_tic = 5;
2140
2141 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_4;
2142 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_4;
2143 }
2144 break;
2145 case 5:
2146 {
2147 next_current_sync_tic = 6;
2148
2149 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_5;
2150 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_5;
2151 }
2152 break;
2153 case 6:
2154 {
2155 next_current_sync_tic = 7;
2156
2157 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_6;
2158 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_6;
2159 }
2160 break;
2161 case 7:
2162 {
2163 next_current_sync_tic = 8;
2164
2165 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_7;
2166 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_7;
2167 }
2168 break;
2169 case 8:
2170 {
2171 next_current_sync_tic = 0;
2172
2173 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_8;
2174 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_8;
2175 }
2176 break;
2177 default:
2178 g_critical("invalid current sync-tic");
2179 }
2180
2181 ags_thread_unset_status_flags(current, AGS_THREAD_STATUS_WAITING);
2182
2183 /* apply next current sync tic */
2184 ags_thread_set_current_sync_tic(current, next_current_sync_tic);
2185
2186 g_mutex_lock(wait_mutex);
2187
2188 ags_thread_set_sync_tic_flags(current, sync_tic_done);
2189
2190 if(ags_thread_test_sync_tic_flags(current, sync_tic_wait)){
2191 g_cond_signal(wait_cond);
2192 }
2193
2194 g_mutex_unlock(wait_mutex);
2195 }
2196
2197 void
ags_thread_set_tree_sync_recursive(AgsThread * thread,guint current_sync_tic)2198 ags_thread_set_tree_sync_recursive(AgsThread *thread, guint current_sync_tic)
2199 {
2200 AgsThread *child, *next_child;
2201
2202 if(!AGS_IS_THREAD(thread)){
2203 return;
2204 }
2205
2206 ags_thread_set_current_sync(thread, current_sync_tic);
2207
2208 /* set tree sync recursive */
2209 child = ags_thread_children(thread);
2210
2211 while(child != NULL){
2212 ags_thread_set_tree_sync_recursive(child, current_sync_tic);
2213
2214 /* iterate */
2215 next_child = ags_thread_next(child);
2216
2217 g_object_unref(child);
2218
2219 child = next_child;
2220 }
2221 }
2222
2223 guint
ags_thread_real_clock(AgsThread * thread)2224 ags_thread_real_clock(AgsThread *thread)
2225 {
2226 AgsThread *main_loop;
2227 AgsTaskLauncher *task_launcher;
2228
2229 AgsApplicationContext *application_context;
2230
2231 guint main_sync_tic, current_sync_tic, next_main_sync_tic;
2232 gdouble next_tic_delay, prev_tic_delay;
2233 guint sync_tic_wait, sync_tic_done;
2234 guint next_sync_tic_wait, next_sync_tic_done;
2235 guint clocked_steps;
2236 gboolean initial_sync;
2237
2238 GRecMutex *thread_mutex;
2239 GRecMutex *main_loop_mutex;
2240 GRecMutex *tree_mutex;
2241 GMutex *thread_start_mutex;
2242 GCond *thread_start_cond;
2243 GMutex *wait_mutex;
2244 GCond *wait_cond;
2245
2246 application_context = ags_application_context_get_instance();
2247
2248 /* get thread mutex */
2249 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
2250
2251 /* get main loop */
2252 main_loop = ags_concurrency_provider_get_main_loop(AGS_CONCURRENCY_PROVIDER(application_context));
2253
2254 main_loop_mutex = AGS_THREAD_GET_OBJ_MUTEX(main_loop);
2255
2256 tree_mutex = ags_main_loop_get_tree_lock(AGS_MAIN_LOOP(main_loop));
2257
2258 /* wait */
2259 wait_mutex = AGS_THREAD_GET_WAIT_MUTEX(thread);
2260 wait_cond = AGS_THREAD_GET_WAIT_COND(thread);
2261
2262 /* check initial sync */
2263 initial_sync = FALSE;
2264
2265 if(ags_thread_test_status_flags(thread, AGS_THREAD_STATUS_INITIAL_SYNC)){
2266 initial_sync = TRUE;
2267
2268 while(ags_main_loop_is_critical_region(AGS_MAIN_LOOP(main_loop))){
2269 #if !defined(AGS_WITH_RT)
2270 g_usleep(4);
2271 #endif
2272 }
2273
2274 /* increment queued critical region */
2275 ags_main_loop_inc_queued_critical_region(AGS_MAIN_LOOP(main_loop));
2276 }
2277
2278 thread_start_mutex = AGS_THREAD_GET_START_MUTEX(thread);
2279 thread_start_cond = AGS_THREAD_GET_START_COND(thread);
2280
2281 /* notify start */
2282 g_mutex_lock(thread_start_mutex);
2283
2284 ags_thread_set_status_flags(thread, AGS_THREAD_STATUS_START_DONE);
2285
2286 if(ags_thread_test_status_flags(thread, AGS_THREAD_STATUS_START_WAIT)){
2287 ags_thread_unset_status_flags(thread, AGS_THREAD_STATUS_START_WAIT);
2288
2289 g_cond_broadcast(thread_start_cond);
2290 }
2291
2292 g_mutex_unlock(thread_start_mutex);
2293
2294 g_rec_mutex_lock(tree_mutex);
2295
2296 if(thread == main_loop){
2297 while(ags_main_loop_test_queued_critical_region(AGS_MAIN_LOOP(main_loop)) != 0){
2298 g_rec_mutex_unlock(tree_mutex);
2299
2300 g_rec_mutex_lock(tree_mutex);
2301 }
2302
2303 ags_main_loop_set_critical_region(AGS_MAIN_LOOP(main_loop), TRUE);
2304 }
2305
2306 if(ags_thread_test_status_flags(thread, AGS_THREAD_STATUS_IS_CHAOS_TREE)){
2307 while(ags_main_loop_is_syncing(AGS_MAIN_LOOP(main_loop))){
2308 g_rec_mutex_unlock(tree_mutex);
2309
2310 #if !defined(AGS_WITH_RT)
2311 g_usleep(4);
2312 #endif
2313
2314 g_rec_mutex_lock(tree_mutex);
2315 }
2316
2317 ags_thread_unset_status_flags(thread, AGS_THREAD_STATUS_IS_CHAOS_TREE);
2318 }
2319
2320 /* sync tic */
2321 main_sync_tic = ags_thread_get_current_sync_tic(main_loop);
2322
2323 current_sync_tic = ags_thread_get_current_sync_tic(thread);
2324
2325 if(initial_sync){
2326 current_sync_tic = main_sync_tic;
2327 ags_thread_set_current_sync_tic(thread, main_sync_tic);
2328 }
2329
2330 sync_tic_wait = 0;
2331 sync_tic_done = 0;
2332
2333 switch(current_sync_tic){
2334 case 0:
2335 {
2336 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_0;
2337 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_0;
2338 }
2339 break;
2340 case 1:
2341 {
2342 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_1;
2343 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_1;
2344 }
2345 break;
2346 case 2:
2347 {
2348 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_2;
2349 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_2;
2350 }
2351 break;
2352 case 3:
2353 {
2354 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_3;
2355 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_3;
2356 }
2357 break;
2358 case 4:
2359 {
2360 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_4;
2361 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_4;
2362 }
2363 break;
2364 case 5:
2365 {
2366 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_5;
2367 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_5;
2368 }
2369 break;
2370 case 6:
2371 {
2372 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_6;
2373 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_6;
2374 }
2375 break;
2376 case 7:
2377 {
2378 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_7;
2379 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_7;
2380 }
2381 break;
2382 case 8:
2383 {
2384 sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_8;
2385 sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_8;
2386 }
2387 break;
2388 default:
2389 g_critical("invalid current sync-tic");
2390 }
2391
2392 next_main_sync_tic = G_MAXUINT;
2393
2394 next_sync_tic_wait = 0;
2395 next_sync_tic_done = 0;
2396
2397 switch(main_sync_tic){
2398 case 0:
2399 {
2400 next_main_sync_tic = 1;
2401
2402 next_sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_1;
2403 next_sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_1;
2404 }
2405 break;
2406 case 1:
2407 {
2408 next_main_sync_tic = 2;
2409
2410 next_sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_2;
2411 next_sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_2;
2412 }
2413 break;
2414 case 2:
2415 {
2416 next_main_sync_tic = 3;
2417
2418 next_sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_3;
2419 next_sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_3;
2420 }
2421 break;
2422 case 3:
2423 {
2424 next_main_sync_tic = 4;
2425
2426 next_sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_4;
2427 next_sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_4;
2428 }
2429 break;
2430 case 4:
2431 {
2432 next_main_sync_tic = 5;
2433
2434 next_sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_5;
2435 next_sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_5;
2436 }
2437 break;
2438 case 5:
2439 {
2440 next_main_sync_tic = 6;
2441
2442 next_sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_6;
2443 next_sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_6;
2444 }
2445 break;
2446 case 6:
2447 {
2448 next_main_sync_tic = 7;
2449
2450 next_sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_7;
2451 next_sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_7;
2452 }
2453 break;
2454 case 7:
2455 {
2456 next_main_sync_tic = 8;
2457
2458 next_sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_8;
2459 next_sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_8;
2460 }
2461 break;
2462 case 8:
2463 {
2464 next_main_sync_tic = 0;
2465
2466 next_sync_tic_wait = AGS_THREAD_SYNC_TIC_WAIT_0;
2467 next_sync_tic_done = AGS_THREAD_SYNC_TIC_DONE_0;
2468 }
2469 break;
2470 default:
2471 g_critical("invalid main sync-tic");
2472 }
2473
2474 /* do initial sync */
2475 if(initial_sync){
2476 gdouble main_delay;
2477 gdouble main_tic_delay, next_main_tic_delay, prev_main_tic_delay;
2478
2479 g_rec_mutex_lock(main_loop_mutex);
2480
2481 main_delay = main_loop->delay;
2482 main_tic_delay = main_loop->tic_delay;
2483
2484 g_rec_mutex_unlock(main_loop_mutex);
2485
2486 if(main_tic_delay + 1.0 < main_delay){
2487 next_main_tic_delay = main_tic_delay + 1.0;
2488 }else{
2489 next_main_tic_delay = 0.0; //(main_tic_delay + 1.0) - floor(main_delay); // (main_tic_delay + 1.0) - main_delay;
2490 }
2491
2492 if(main_tic_delay - 1.0 > 0.0){
2493 prev_main_tic_delay = main_tic_delay - 1.0;
2494 }else{
2495 prev_main_tic_delay = main_delay - 1.0; // (floor(main_delay) + 1.0) - (floor(main_delay) + main_tic_delay); // (main_delay + 1.0) - (main_delay + main_tic_delay);
2496 }
2497
2498 ags_thread_set_sync_tic_flags(thread, sync_tic_wait);
2499 ags_thread_unset_sync_tic_flags(thread, sync_tic_done);
2500
2501 /* mark synced */
2502 if(ags_thread_test_flags(thread, AGS_THREAD_IMMEDIATE_SYNC)){
2503 thread->tic_delay = main_tic_delay;
2504 }else if(ags_thread_test_flags(thread, AGS_THREAD_INTERMEDIATE_PRE_SYNC)){
2505 thread->tic_delay = next_main_tic_delay;
2506 }else if(ags_thread_test_flags(thread, AGS_THREAD_INTERMEDIATE_POST_SYNC)){
2507 thread->tic_delay = prev_main_tic_delay;
2508 }else{
2509 thread->tic_delay = 0.0;
2510 }
2511
2512 ags_thread_set_flags(thread, AGS_THREAD_MARK_SYNCED);
2513 ags_thread_set_status_flags(thread, (AGS_THREAD_STATUS_SYNCED_FREQ));
2514
2515 /* unset status flags */
2516 ags_thread_unset_status_flags(thread, AGS_THREAD_STATUS_INITIAL_SYNC);
2517
2518 /* decrement queued critical region */
2519 ags_main_loop_dec_queued_critical_region(AGS_MAIN_LOOP(main_loop));
2520 }
2521
2522 /* synchronize */
2523 ags_thread_set_status_flags(thread, AGS_THREAD_STATUS_WAITING);
2524
2525 if(current_sync_tic != main_sync_tic ||
2526 !ags_thread_is_tree_ready_recursive(main_loop, current_sync_tic)){
2527 gboolean unlock_tree;
2528
2529 unlock_tree = TRUE;
2530
2531 g_mutex_lock(wait_mutex);
2532
2533 if(ags_thread_test_sync_tic_flags(thread, sync_tic_wait) &&
2534 !ags_thread_test_sync_tic_flags(thread, sync_tic_done)){
2535 ags_thread_set_sync_tic_flags(thread, sync_tic_wait);
2536
2537 while(ags_thread_test_sync_tic_flags(thread, sync_tic_wait) &&
2538 !ags_thread_test_sync_tic_flags(thread, sync_tic_done)){
2539 if(unlock_tree){
2540 unlock_tree = FALSE;
2541
2542 g_rec_mutex_unlock(tree_mutex);
2543 }
2544
2545 g_cond_wait(wait_cond,
2546 wait_mutex);
2547 }
2548 }
2549
2550 ags_thread_unset_status_flags(thread, AGS_THREAD_STATUS_WAITING);
2551
2552 if(unlock_tree){
2553 unlock_tree = FALSE;
2554
2555 g_rec_mutex_unlock(tree_mutex);
2556 }
2557
2558 ags_thread_unset_sync_tic_flags(thread, sync_tic_wait);
2559 ags_thread_unset_sync_tic_flags(thread, sync_tic_done);
2560
2561 ags_thread_set_sync_tic_flags(thread, next_sync_tic_wait);
2562 ags_thread_unset_sync_tic_flags(thread, next_sync_tic_done);
2563
2564 g_mutex_unlock(wait_mutex);
2565 }else{
2566 ags_main_loop_set_syncing(AGS_MAIN_LOOP(main_loop), TRUE);
2567
2568 ags_thread_unset_status_flags(thread, AGS_THREAD_STATUS_WAITING);
2569
2570 /* get task launcher */
2571 task_launcher = ags_concurrency_provider_get_task_launcher(AGS_CONCURRENCY_PROVIDER(application_context));
2572
2573 /* run task launcher */
2574 ags_task_launcher_sync_run(task_launcher);
2575
2576 /* signal */
2577 #if 1
2578 if(main_sync_tic == current_sync_tic){
2579 }else{
2580 g_critical("out-of-sync - main sync-tic != current sync-tic");
2581 }
2582
2583 ags_thread_prepare_tree_sync_recursive(main_loop,
2584 main_sync_tic);
2585
2586 ags_thread_set_tree_sync_recursive(main_loop,
2587 main_sync_tic);
2588 #else
2589 ags_thread_prepare_tree_sync_recursive(main_loop,
2590 main_sync_tic);
2591
2592 ags_thread_set_tree_sync_recursive(main_loop,
2593 main_sync_tic);
2594 #endif
2595
2596 ags_main_loop_set_syncing(AGS_MAIN_LOOP(main_loop), FALSE);
2597
2598 ags_thread_unset_sync_tic_flags(thread, sync_tic_wait);
2599 ags_thread_unset_sync_tic_flags(thread, sync_tic_done);
2600
2601 ags_thread_set_sync_tic_flags(thread, next_sync_tic_wait);
2602 ags_thread_unset_sync_tic_flags(thread, next_sync_tic_done);
2603
2604 g_rec_mutex_unlock(tree_mutex);
2605 }
2606
2607 /* get task launcher */
2608 task_launcher = ags_concurrency_provider_get_task_launcher(AGS_CONCURRENCY_PROVIDER(application_context));
2609
2610 if(task_launcher != NULL){
2611 g_mutex_lock(&(task_launcher->wait_mutex));
2612
2613 if(g_atomic_int_get(&(task_launcher->is_running))){
2614 g_atomic_int_inc(&(task_launcher->wait_count));
2615
2616 while(g_atomic_int_get(&(task_launcher->is_running)) &&
2617 g_atomic_int_get(&(task_launcher->wait_count)) != 0){
2618 g_cond_wait(&(task_launcher->wait_cond),
2619 &(task_launcher->wait_mutex));
2620 }
2621 }
2622
2623 g_mutex_unlock(&(task_launcher->wait_mutex));
2624 }
2625
2626 /* compute clocked steps */
2627 clocked_steps = 0;
2628
2629 g_rec_mutex_lock(thread_mutex);
2630
2631 if(thread->delay >= 1.0){
2632 thread->tic_delay += 1.0;
2633
2634 if(thread->tic_delay >= thread->delay){
2635 clocked_steps = 1;
2636
2637 thread->tic_delay = 0.0; // thread->delay;
2638 }
2639
2640 if(initial_sync){
2641 /* prepare initial run */
2642 ags_thread_set_status_flags(thread, AGS_THREAD_STATUS_INITIAL_RUN);
2643 }
2644 }else{
2645 clocked_steps = (guint) floor((1.0 + thread->tic_delay) / thread->delay);
2646
2647 thread->tic_delay = 0.0; // (1.0 / thread->delay) - floor(1.0 / thread->delay);
2648 }
2649
2650 g_rec_mutex_unlock(thread_mutex);
2651
2652 if(thread == main_loop){
2653 ags_main_loop_set_critical_region(AGS_MAIN_LOOP(main_loop), FALSE);
2654 }
2655
2656 return(clocked_steps);
2657 }
2658
2659 /**
2660 * ags_thread_clock:
2661 * @thread: the #AgsThread instance
2662 *
2663 * Clock the thread.
2664 *
2665 * Returns: the cycles to be performed
2666 *
2667 * Since: 3.0.0
2668 */
2669 guint
ags_thread_clock(AgsThread * thread)2670 ags_thread_clock(AgsThread *thread)
2671 {
2672 guint cycles;
2673
2674 g_return_val_if_fail(AGS_IS_THREAD(thread), 0);
2675
2676 g_object_ref(thread);
2677 g_signal_emit(thread,
2678 thread_signals[CLOCK], 0,
2679 &cycles);
2680 g_object_unref(thread);
2681
2682 return(cycles);
2683 }
2684
2685 void*
ags_thread_loop(void * ptr)2686 ags_thread_loop(void *ptr)
2687 {
2688 AgsThread *main_loop;
2689 AgsThread *thread;
2690 AgsTaskLauncher *task_launcher;
2691
2692 AgsApplicationContext *application_context;
2693
2694 GList *start_start_queue, *start_queue;
2695
2696 guint main_sync_tic, current_sync_tic;
2697 guint i, i_stop;
2698
2699 GRecMutex *tree_mutex;
2700 GRecMutex *thread_mutex;
2701
2702 thread = (AgsThread *) ptr;
2703
2704 application_context = ags_application_context_get_instance();
2705
2706 /* set private for ags_thread_self() */
2707 g_object_ref(thread);
2708
2709 g_private_set(&ags_thread_key,
2710 thread);
2711
2712 if(!AGS_IS_MAIN_LOOP(thread)){
2713 ags_thread_set_status_flags(thread, AGS_THREAD_STATUS_IS_CHAOS_TREE);
2714 }
2715
2716 /* set/unset run flags */
2717 ags_thread_unset_status_flags(thread,
2718 (AGS_THREAD_STATUS_RT_SETUP |
2719 AGS_THREAD_STATUS_WAITING |
2720 AGS_THREAD_STATUS_SYNCED |
2721 AGS_THREAD_STATUS_SYNCED_FREQ));
2722
2723 ags_thread_unset_sync_tic_flags(thread, (AGS_THREAD_SYNC_TIC_WAIT_0 |
2724 AGS_THREAD_SYNC_TIC_DONE_0 |
2725 AGS_THREAD_SYNC_TIC_WAIT_1 |
2726 AGS_THREAD_SYNC_TIC_DONE_1 |
2727 AGS_THREAD_SYNC_TIC_WAIT_2 |
2728 AGS_THREAD_SYNC_TIC_DONE_2 |
2729 AGS_THREAD_SYNC_TIC_WAIT_3 |
2730 AGS_THREAD_SYNC_TIC_DONE_3 |
2731 AGS_THREAD_SYNC_TIC_WAIT_4 |
2732 AGS_THREAD_SYNC_TIC_DONE_4 |
2733 AGS_THREAD_SYNC_TIC_WAIT_5 |
2734 AGS_THREAD_SYNC_TIC_DONE_5 |
2735 AGS_THREAD_SYNC_TIC_WAIT_6 |
2736 AGS_THREAD_SYNC_TIC_DONE_6 |
2737 AGS_THREAD_SYNC_TIC_WAIT_7 |
2738 AGS_THREAD_SYNC_TIC_DONE_7 |
2739 AGS_THREAD_SYNC_TIC_WAIT_8 |
2740 AGS_THREAD_SYNC_TIC_DONE_8));
2741
2742 ags_thread_unset_flags(thread,
2743 (AGS_THREAD_MARK_SYNCED));
2744
2745 ags_thread_set_status_flags(thread,
2746 (AGS_THREAD_STATUS_RUNNING |
2747 AGS_THREAD_STATUS_READY |
2748 AGS_THREAD_STATUS_INITIAL_RUN |
2749 AGS_THREAD_STATUS_INITIAL_SYNC));
2750
2751 /* get thread mutex */
2752 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
2753
2754 while(ags_thread_test_status_flags(thread, AGS_THREAD_STATUS_RUNNING)){
2755 /* start queue */
2756 g_rec_mutex_lock(thread_mutex);
2757
2758 start_queue =
2759 start_start_queue = thread->start_queue;
2760
2761 thread->start_queue = NULL;
2762
2763 g_rec_mutex_unlock(thread_mutex);
2764
2765 while(start_queue != NULL){
2766 AgsThread *queued_thread;
2767
2768 GMutex *queued_thread_start_mutex;
2769 GCond *queued_thread_start_cond;
2770
2771 queued_thread = (AgsThread *) start_queue->data;
2772 g_object_ref(queued_thread);
2773
2774 /* */
2775 ags_thread_start(queued_thread);
2776
2777 queued_thread_start_mutex = AGS_THREAD_GET_START_MUTEX(queued_thread);
2778 queued_thread_start_cond = AGS_THREAD_GET_START_COND(queued_thread);
2779
2780 g_mutex_lock(queued_thread_start_mutex);
2781
2782 if(ags_thread_test_status_flags(queued_thread, AGS_THREAD_STATUS_START_WAIT) &&
2783 !ags_thread_test_status_flags(queued_thread, AGS_THREAD_STATUS_START_DONE)){
2784 ags_thread_set_status_flags(queued_thread, AGS_THREAD_STATUS_START_WAIT);
2785
2786 while(ags_thread_test_status_flags(queued_thread, AGS_THREAD_STATUS_START_WAIT) &&
2787 !ags_thread_test_status_flags(queued_thread, AGS_THREAD_STATUS_START_DONE)){
2788 g_cond_wait(queued_thread_start_cond,
2789 queued_thread_start_mutex);
2790 }
2791 }
2792
2793 g_mutex_unlock(queued_thread_start_mutex);
2794
2795 g_object_unref(queued_thread);
2796
2797 /* iterate */
2798 start_queue = start_queue->next;
2799 }
2800
2801 start_queue = start_start_queue;
2802
2803 while(start_queue != NULL){
2804 while(!ags_thread_test_status_flags(start_queue->data, AGS_THREAD_STATUS_SYNCED_FREQ));
2805
2806 /* iterate */
2807 start_queue = start_queue->next;
2808 }
2809
2810 g_list_free_full(start_start_queue,
2811 g_object_unref);
2812
2813 /* run with clock synchronization */
2814 i_stop = ags_thread_clock(thread);
2815
2816 /* set busy flag */
2817 if(i_stop > 0){
2818 ags_thread_set_status_flags(thread, AGS_THREAD_STATUS_BUSY);
2819 }
2820
2821 for(i = 0; i < i_stop && ags_thread_test_status_flags(thread, AGS_THREAD_STATUS_RUNNING); i++){
2822 #if 0
2823 g_message("run thread 0x%x", thread);
2824 #endif
2825
2826 /* run */
2827 ags_thread_run(thread);
2828 }
2829
2830 /* unset busy flag */
2831 if(i_stop > 0){
2832 if(ags_thread_test_status_flags(thread, AGS_THREAD_STATUS_INITIAL_RUN)){
2833 ags_thread_unset_status_flags(thread, AGS_THREAD_STATUS_INITIAL_RUN);
2834 }
2835
2836 ags_thread_unset_status_flags(thread, AGS_THREAD_STATUS_BUSY);
2837 }
2838 }
2839
2840 /* get main loop */
2841 main_loop = ags_concurrency_provider_get_main_loop(AGS_CONCURRENCY_PROVIDER(application_context));
2842
2843 tree_mutex = ags_main_loop_get_tree_lock(AGS_MAIN_LOOP(main_loop));
2844
2845 g_rec_mutex_lock(tree_mutex);
2846
2847 /* sync tic */
2848 main_sync_tic = ags_thread_get_current_sync_tic(main_loop);
2849
2850 current_sync_tic = ags_thread_get_current_sync_tic(thread);
2851
2852 #ifdef AGS_DEBUG
2853 g_message("thread finish %d %d", main_sync_tic, current_sync_tic);
2854 #endif
2855
2856 ags_thread_clear_status_flags(thread);
2857 ags_thread_clear_sync_tic_flags(thread);
2858
2859 if(!ags_thread_is_tree_ready_recursive(main_loop, current_sync_tic) ||
2860 current_sync_tic != main_sync_tic){
2861 if(main_sync_tic != current_sync_tic){
2862 g_critical("out-of-sync - main sync-tic != current sync-tic");
2863 }
2864
2865 g_rec_mutex_unlock(tree_mutex);
2866 }else{
2867 AgsTaskLauncher *task_launcher;
2868
2869 ags_main_loop_set_syncing(AGS_MAIN_LOOP(main_loop), TRUE);
2870
2871 /* get task launcher */
2872 task_launcher = ags_concurrency_provider_get_task_launcher(AGS_CONCURRENCY_PROVIDER(application_context));
2873
2874 /* run task launcher */
2875 ags_task_launcher_sync_run(task_launcher);
2876
2877 /* signal */
2878 #if 1
2879 if(main_sync_tic == current_sync_tic){
2880 }else{
2881 g_critical("out-of-sync - main sync-tic != current sync-tic");
2882 }
2883
2884 ags_thread_prepare_tree_sync_recursive(main_loop,
2885 main_sync_tic);
2886
2887 ags_thread_set_tree_sync_recursive(main_loop,
2888 main_sync_tic);
2889 #else
2890 ags_thread_prepare_tree_sync_recursive(main_loop,
2891 main_sync_tic);
2892
2893 ags_thread_set_tree_sync_recursive(main_loop,
2894 main_sync_tic);
2895 #endif
2896
2897 ags_main_loop_set_syncing(AGS_MAIN_LOOP(main_loop), FALSE);
2898
2899 g_rec_mutex_unlock(tree_mutex);
2900 }
2901
2902 /* exit thread */
2903 ags_thread_unset_flags(thread, AGS_THREAD_MARK_SYNCED);
2904
2905 thread->thread = NULL;
2906
2907 g_thread_exit(NULL);
2908
2909 return(NULL);
2910 }
2911
2912 void
ags_thread_real_start(AgsThread * thread)2913 ags_thread_real_start(AgsThread *thread)
2914 {
2915 if(thread->thread != NULL ||
2916 ags_thread_test_status_flags(thread, AGS_THREAD_STATUS_RUNNING)){
2917 return;
2918 }
2919
2920 #ifdef AGS_DEBUG
2921 g_message("thread start: %s", G_OBJECT_TYPE_NAME(thread));
2922 #endif
2923
2924 /* */
2925 thread->thread = g_thread_new("Advanced Gtk+ Sequencer - clock",
2926 ags_thread_loop,
2927 thread);
2928 }
2929
2930 /**
2931 * ags_thread_start:
2932 * @thread: the #AgsThread instance
2933 *
2934 * Start the thread.
2935 *
2936 * Since: 3.0.0
2937 */
2938 void
ags_thread_start(AgsThread * thread)2939 ags_thread_start(AgsThread *thread)
2940 {
2941 g_return_if_fail(AGS_IS_THREAD(thread));
2942
2943 g_object_ref(thread);
2944 g_signal_emit(thread,
2945 thread_signals[START], 0);
2946 g_object_unref(thread);
2947 }
2948
2949 /**
2950 * ags_thread_add_start_queue:
2951 * @thread: the #AgsThread
2952 * @child: the child #AgsThread to start
2953 *
2954 * Add @child to @thread's start queue.
2955 *
2956 * Since: 3.0.0
2957 */
2958 void
ags_thread_add_start_queue(AgsThread * thread,AgsThread * child)2959 ags_thread_add_start_queue(AgsThread *thread,
2960 AgsThread *child)
2961 {
2962 GRecMutex *thread_mutex;
2963
2964 if(!AGS_IS_THREAD(thread) ||
2965 !AGS_IS_THREAD(child)){
2966 return;
2967 }
2968
2969 /* thread mutex */
2970 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
2971
2972 /* add */
2973 g_rec_mutex_lock(thread_mutex);
2974
2975 thread->start_queue = g_list_prepend(thread->start_queue,
2976 child);
2977 g_object_ref(child);
2978
2979 g_rec_mutex_unlock(thread_mutex);
2980 }
2981
2982 /**
2983 * ags_thread_add_start_queue_all:
2984 * @thread: the #AgsThread
2985 * @child: (element-type Ags.Thread): the children as #GList-struct containing #AgsThread to start
2986 *
2987 * Add @child to @thread's start queue.
2988 *
2989 * Since: 3.0.0
2990 */
2991 void
ags_thread_add_start_queue_all(AgsThread * thread,GList * child)2992 ags_thread_add_start_queue_all(AgsThread *thread,
2993 GList *child)
2994 {
2995 GRecMutex *thread_mutex;
2996
2997 if(!AGS_IS_THREAD(thread) ||
2998 child == NULL){
2999 return;
3000 }
3001
3002 /* thread mutex */
3003 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(thread);
3004
3005 /* add all */
3006 g_rec_mutex_lock(thread_mutex);
3007
3008 if(thread->start_queue == NULL){
3009 thread->start_queue = g_list_copy_deep(child,
3010 (GCopyFunc) g_object_ref,
3011 NULL);
3012 }else{
3013 thread->start_queue = g_list_concat(thread->start_queue,
3014 g_list_copy_deep(child,
3015 (GCopyFunc) g_object_ref,
3016 NULL));
3017 }
3018
3019 g_rec_mutex_unlock(thread_mutex);
3020 }
3021
3022 /**
3023 * ags_thread_run:
3024 * @thread: the #AgsThread
3025 *
3026 * Only for internal use of ags_thread_loop but you may want to set the your very own
3027 * class function namely your thread's routine.
3028 *
3029 * Since: 3.0.0
3030 */
3031 void
ags_thread_run(AgsThread * thread)3032 ags_thread_run(AgsThread *thread)
3033 {
3034 g_return_if_fail(AGS_IS_THREAD(thread));
3035
3036 g_object_ref(thread);
3037 g_signal_emit(thread,
3038 thread_signals[RUN], 0);
3039 g_object_unref(thread);
3040 }
3041
3042
3043 void
ags_thread_real_stop(AgsThread * thread)3044 ags_thread_real_stop(AgsThread *thread)
3045 {
3046 if(thread->thread == NULL ||
3047 !ags_thread_test_status_flags(thread, AGS_THREAD_STATUS_RUNNING)){
3048 return;
3049 }
3050
3051 ags_thread_unset_status_flags(thread, AGS_THREAD_STATUS_RUNNING);
3052 }
3053
3054 /**
3055 * ags_thread_stop:
3056 * @thread: the #AgsThread
3057 *
3058 * Stop the threads loop by unsetting AGS_THREAD_STATUS_RUNNING flag.
3059 *
3060 * Since: 3.0.0
3061 */
3062 void
ags_thread_stop(AgsThread * thread)3063 ags_thread_stop(AgsThread *thread)
3064 {
3065 g_return_if_fail(AGS_IS_THREAD(thread));
3066
3067 g_object_ref(G_OBJECT(thread));
3068 g_signal_emit(G_OBJECT(thread),
3069 thread_signals[STOP], 0);
3070 g_object_unref(G_OBJECT(thread));
3071 }
3072
3073 /**
3074 * ags_thread_find_type:
3075 * @thread: the #AgsThread
3076 * @gtype: the #GType-struct
3077 *
3078 * Find @gtype as descendant of @thread. If its a descendant thread,
3079 * the ref-count is increased.
3080 *
3081 * Returns: (transfer full): the matching #AgsThread
3082 *
3083 * Since: 3.0.0
3084 */
3085 AgsThread*
ags_thread_find_type(AgsThread * thread,GType gtype)3086 ags_thread_find_type(AgsThread *thread, GType gtype)
3087 {
3088 AgsThread *child, *next_child;
3089 AgsThread *retval;
3090
3091 if(!AGS_IS_THREAD(thread) ||
3092 gtype == G_TYPE_NONE){
3093 return(NULL);
3094 }
3095
3096 if(g_type_is_a(G_OBJECT_TYPE(thread), gtype)){
3097 return(thread);
3098 }
3099
3100 child = ags_thread_children(thread);
3101
3102 while(child != NULL){
3103 if((retval = ags_thread_find_type(child, gtype)) != NULL){
3104 return(retval);
3105 }
3106
3107 /* iterate */
3108 next_child = ags_thread_next(child);
3109
3110 g_object_unref(child);
3111
3112 child = next_child;
3113 }
3114
3115 return(NULL);
3116 }
3117
3118 /**
3119 * ags_thread_self:
3120 *
3121 * Thread self.
3122 *
3123 * Returns: (transfer full): the running #AgsThread
3124 *
3125 * Since: 3.0.0
3126 */
3127 AgsThread*
ags_thread_self(void)3128 ags_thread_self(void)
3129 {
3130 AgsThread *self;
3131
3132 self = (AgsThread *) g_private_get(&ags_thread_key);
3133 g_object_ref(self);
3134
3135 return(self);
3136 }
3137
3138 /**
3139 * ags_thread_new:
3140 *
3141 * Create a new instance of #AgsThread.
3142 *
3143 * Returns: the new #AgsThread
3144 *
3145 * Since: 3.0.0
3146 */
3147 AgsThread*
ags_thread_new()3148 ags_thread_new()
3149 {
3150 AgsThread *thread;
3151
3152 thread = (AgsThread *) g_object_new(AGS_TYPE_THREAD,
3153 NULL);
3154
3155 return(thread);
3156 }
3157