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