1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2021 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 #ifndef __AGS_THREAD_H__
21 #define __AGS_THREAD_H__
22 
23 #include <glib.h>
24 #include <glib-object.h>
25 
26 #include <ags/lib/ags_uuid.h>
27 #include <ags/lib/ags_time.h>
28 
29 #include <time.h>
30 
31 G_BEGIN_DECLS
32 
33 #define AGS_TYPE_THREAD                (ags_thread_get_type())
34 #define AGS_TYPE_THREAD_FLAGS          (ags_thread_flags_get_type())
35 #define AGS_TYPE_THREAD_STATUS_FLAGS   (ags_thread_status_flags_get_type())
36 #define AGS_TYPE_THREAD_SYNC_TIC_FLAGS (ags_thread_sync_tic_flags_get_type())
37 #define AGS_THREAD(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), AGS_TYPE_THREAD, AgsThread))
38 #define AGS_THREAD_CLASS(class)        (G_TYPE_CHECK_CLASS_CAST(class, AGS_TYPE_THREAD, AgsThreadClass))
39 #define AGS_IS_THREAD(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), AGS_TYPE_THREAD))
40 #define AGS_IS_THREAD_CLASS(class)     (G_TYPE_CHECK_CLASS_TYPE ((class), AGS_TYPE_THREAD))
41 #define AGS_THREAD_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS(obj, AGS_TYPE_THREAD, AgsThreadClass))
42 
43 #define AGS_THREAD_GET_OBJ_MUTEX(obj) (&(((AgsThread *) obj)->obj_mutex))
44 
45 #define AGS_THREAD_GET_WAIT_MUTEX(obj) (&(((AgsThread *) obj)->wait_mutex))
46 #define AGS_THREAD_GET_WAIT_COND(obj) (&(((AgsThread *) obj)->wait_cond))
47 #define AGS_THREAD_GET_TIC_MUTEX(obj) (&(((AgsThread *) obj)->tic_mutex))
48 #define AGS_THREAD_GET_TIC_COND(obj) (&(((AgsThread *) obj)->tic_cond))
49 #define AGS_THREAD_GET_START_MUTEX(obj) (&(((AgsThread *) obj)->start_mutex))
50 #define AGS_THREAD_GET_START_COND(obj) (&(((AgsThread *) obj)->start_cond))
51 
52 #define AGS_THREAD_HERTZ_JIFFIE (1000.0)
53 #define AGS_THREAD_YIELD_JIFFIE (2.0)
54 
55 #define AGS_THREAD_DEFAULT_JIFFIE (250.0)
56 #define AGS_THREAD_DEFAULT_MAX_PRECISION (1000.0)
57 
58 #define AGS_THREAD_MAX_PRECISION (1000.0)
59 
60 #define AGS_THREAD_DEFAULT_ATTACK (1.0)
61 
62 #define AGS_THREAD_TOLERANCE (0.0)
63 
64 typedef struct _AgsThread AgsThread;
65 typedef struct _AgsThreadClass AgsThreadClass;
66 
67 /**
68  * AgsThreadFlags:
69  * @AGS_THREAD_ADDED_TO_REGISTRY: the thread was added to registry, see #AgsConnectable::add_to_registry()
70  * @AGS_THREAD_CONNECTED: the thread was connected by #AgsConnectable::connect()
71  * @AGS_THREAD_UNREF_ON_EXIT: call g_object_unref() before g_thread_exit()
72  * @AGS_THREAD_IMMEDIATE_SYNC: do sync immediately
73  * @AGS_THREAD_INTERMEDIATE_PRE_SYNC: intermediate pre sync to parent thread
74  * @AGS_THREAD_INTERMEDIATE_POST_SYNC: intermediate post sync to parent thread
75  * @AGS_THREAD_START_SYNCED_FREQ: sync frequency as starting thread
76  * @AGS_THREAD_MARK_SYNCED: mark thread synced
77  * @AGS_THREAD_TIME_ACCOUNTING: time accounting causes to track time
78  *
79  * Enum values to control the behavior or indicate internal state of #AgsThread by
80  * enable/disable as flags.
81  */
82 typedef enum{
83   AGS_THREAD_ADDED_TO_REGISTRY       = 1,
84   AGS_THREAD_CONNECTED               = 1 <<  1,
85   AGS_THREAD_UNREF_ON_EXIT           = 1 <<  2,
86   AGS_THREAD_IMMEDIATE_SYNC          = 1 <<  3,
87   AGS_THREAD_INTERMEDIATE_PRE_SYNC   = 1 <<  4,
88   AGS_THREAD_INTERMEDIATE_POST_SYNC  = 1 <<  5,
89   AGS_THREAD_START_SYNCED_FREQ       = 1 <<  6,
90   AGS_THREAD_MARK_SYNCED             = 1 <<  7,
91   AGS_THREAD_TIME_ACCOUNTING         = 1 <<  8,
92 }AgsThreadFlags;
93 
94 /**
95  * AgsThreadStatusFlags:
96  * @AGS_THREAD_STATUS_RT_SETUP: realtime setup was performed
97  * @AGS_THREAD_STATUS_INITIAL_SYNC: initial sync indicates the thread wasn't synced before
98  * @AGS_THREAD_STATUS_INITIAL_RUN: the first call to #AgsThread:run()
99  * @AGS_THREAD_STATUS_IS_CHAOS_TREE: the thread is not synced
100  * @AGS_THREAD_STATUS_START_WAIT: the thread start is waiting
101  * @AGS_THREAD_STATUS_START_DONE: the thread start is done
102  * @AGS_THREAD_STATUS_READY: the thread is ready
103  * @AGS_THREAD_STATUS_WAITING: the thread is waiting
104  * @AGS_THREAD_STATUS_RUNNING: the thread is running
105  * @AGS_THREAD_STATUS_LOCKED: the thread is locked
106  * @AGS_THREAD_STATUS_BUSY: the thread is busy
107  * @AGS_THREAD_STATUS_SYNCED: the thread joined the tic based system, it is synced
108  * @AGS_THREAD_STATUS_SYNCED_FREQ: the frequency was synced
109  *
110  * Enum values to control the behavior or indicate internal state of #AgsThread by
111  * enable/disable as status flags.
112  */
113 typedef enum{
114   AGS_THREAD_STATUS_RT_SETUP                = 1,
115   AGS_THREAD_STATUS_INITIAL_SYNC            = 1 <<  1,
116   AGS_THREAD_STATUS_INITIAL_RUN             = 1 <<  2,
117   AGS_THREAD_STATUS_IS_CHAOS_TREE           = 1 <<  3,
118   AGS_THREAD_STATUS_START_WAIT              = 1 <<  4,
119   AGS_THREAD_STATUS_START_DONE              = 1 <<  5,
120   AGS_THREAD_STATUS_READY                   = 1 <<  6,
121   AGS_THREAD_STATUS_WAITING                 = 1 <<  7,
122   AGS_THREAD_STATUS_RUNNING                 = 1 <<  8,
123   AGS_THREAD_STATUS_LOCKED                  = 1 <<  9,
124   AGS_THREAD_STATUS_BUSY                    = 1 << 10,
125   AGS_THREAD_STATUS_SYNCED                  = 1 << 11,
126   AGS_THREAD_STATUS_SYNCED_FREQ             = 1 << 12,
127 }AgsThreadStatusFlags;
128 
129 /**
130  * AgsThreadSyncTicFlags:
131  * @AGS_THREAD_SYNC_TIC_WAIT_0: wait tree to be synced
132  * @AGS_THREAD_SYNC_TIC_DONE_0: done tree to be synced
133  * @AGS_THREAD_SYNC_TIC_WAIT_1: wait tree to be synced
134  * @AGS_THREAD_SYNC_TIC_DONE_1: done tree to be synced
135  * @AGS_THREAD_SYNC_TIC_WAIT_2: wait tree to be synced
136  * @AGS_THREAD_SYNC_TIC_DONE_2: done tree to be synced
137  * @AGS_THREAD_SYNC_TIC_WAIT_3: wait tree to be synced
138  * @AGS_THREAD_SYNC_TIC_DONE_3: done tree to be synced
139  * @AGS_THREAD_SYNC_TIC_WAIT_4: wait tree to be synced
140  * @AGS_THREAD_SYNC_TIC_DONE_4: done tree to be synced
141  * @AGS_THREAD_SYNC_TIC_WAIT_5: wait tree to be synced
142  * @AGS_THREAD_SYNC_TIC_DONE_5: done tree to be synced
143  * @AGS_THREAD_SYNC_TIC_WAIT_6: wait tree to be synced
144  * @AGS_THREAD_SYNC_TIC_DONE_6: done tree to be synced
145  * @AGS_THREAD_SYNC_TIC_WAIT_7: wait tree to be synced
146  * @AGS_THREAD_SYNC_TIC_DONE_7: done tree to be synced
147  * @AGS_THREAD_SYNC_TIC_WAIT_8: wait tree to be synced
148  * @AGS_THREAD_SYNC_TIC_DONE_8: done tree to be synced
149  *
150  * Enum values to control the behavior or indicate internal state of #AgsThread by
151  * enable/disable as sync tic flags.
152  */
153 typedef enum{
154   AGS_THREAD_SYNC_TIC_WAIT_0                  = 1,
155   AGS_THREAD_SYNC_TIC_DONE_0                  = 1 <<  1,
156   AGS_THREAD_SYNC_TIC_WAIT_1                  = 1 <<  2,
157   AGS_THREAD_SYNC_TIC_DONE_1                  = 1 <<  3,
158   AGS_THREAD_SYNC_TIC_WAIT_2                  = 1 <<  4,
159   AGS_THREAD_SYNC_TIC_DONE_2                  = 1 <<  5,
160   AGS_THREAD_SYNC_TIC_WAIT_3                  = 1 <<  6,
161   AGS_THREAD_SYNC_TIC_DONE_3                  = 1 <<  7,
162   AGS_THREAD_SYNC_TIC_WAIT_4                  = 1 <<  8,
163   AGS_THREAD_SYNC_TIC_DONE_4                  = 1 <<  9,
164   AGS_THREAD_SYNC_TIC_WAIT_5                  = 1 << 10,
165   AGS_THREAD_SYNC_TIC_DONE_5                  = 1 << 11,
166   AGS_THREAD_SYNC_TIC_WAIT_6                  = 1 << 12,
167   AGS_THREAD_SYNC_TIC_DONE_6                  = 1 << 13,
168   AGS_THREAD_SYNC_TIC_WAIT_7                  = 1 << 14,
169   AGS_THREAD_SYNC_TIC_DONE_7                  = 1 << 15,
170   AGS_THREAD_SYNC_TIC_WAIT_8                  = 1 << 16,
171   AGS_THREAD_SYNC_TIC_DONE_8                  = 1 << 17,
172 }AgsThreadSyncTicFlags;
173 
174 struct _AgsThread
175 {
176   GObject gobject;
177 
178   guint my_flags;
179   volatile guint status_flags;
180   volatile guint sync_tic_flags;
181 
182   GRecMutex obj_mutex;
183 
184   AgsUUID *uuid;
185 
186   volatile guint current_sync_tic;
187 
188   gdouble delay;
189   gdouble tic_delay;
190 
191   gdouble frequency;
192   gdouble max_precision;
193 
194   gint64 last_run_start;
195   gint64 last_run_end;
196 
197   GThread *thread;
198 
199   GMutex wait_mutex;
200   GCond wait_cond;
201 
202   GMutex tic_mutex;
203   GCond tic_cond;
204 
205   GList *start_queue;
206 
207   GMutex start_mutex;
208   GCond start_cond;
209 
210   AgsThread *parent;
211 
212   AgsThread *next;
213   AgsThread *prev;
214 
215   AgsThread *children;
216 };
217 
218 struct _AgsThreadClass
219 {
220   GObjectClass gobject;
221 
222   guint (*clock)(AgsThread *thread);
223 
224   void (*start)(AgsThread *thread);
225   void (*run)(AgsThread *thread);
226   void (*stop)(AgsThread *thread);
227 };
228 
229 GType ags_thread_get_type();
230 GType ags_thread_flags_get_type();
231 GType ags_thread_status_flags_get_type();
232 GType ags_thread_sync_tic_flags_get_type();
233 
234 gboolean ags_thread_global_get_use_sync_counter();
235 
236 gboolean ags_thread_test_flags(AgsThread *thread, guint flags);
237 void ags_thread_set_flags(AgsThread *thread, guint flags);
238 void ags_thread_unset_flags(AgsThread *thread, guint flags);
239 
240 gboolean ags_thread_test_status_flags(AgsThread *thread, guint status_flags);
241 void ags_thread_set_status_flags(AgsThread *thread, guint status_flags);
242 void ags_thread_unset_status_flags(AgsThread *thread, guint status_flags);
243 void ags_thread_clear_status_flags(AgsThread *thread);
244 
245 gboolean ags_thread_test_sync_tic_flags(AgsThread *thread, guint sync_tic_flags);
246 void ags_thread_set_sync_tic_flags(AgsThread *thread, guint sync_tic_flags);
247 void ags_thread_unset_sync_tic_flags(AgsThread *thread, guint sync_tic_flags);
248 void ags_thread_clear_sync_tic_flags(AgsThread *thread);
249 
250 void ags_thread_set_current_sync_tic(AgsThread *thread, guint current_sync_tic);
251 guint ags_thread_get_current_sync_tic(AgsThread *thread);
252 
253 void ags_thread_set_delay(AgsThread *thread, gdouble delay);
254 gdouble ags_thread_get_delay(AgsThread *thread);
255 
256 void ags_thread_set_frequency(AgsThread *thread, gdouble frequency);
257 gdouble ags_thread_get_frequency(AgsThread *thread);
258 
259 void ags_thread_set_max_precision(AgsThread *thread, gdouble max_precision);
260 gdouble ags_thread_get_max_precision(AgsThread *thread);
261 
262 AgsThread* ags_thread_find_type(AgsThread *thread, GType gtype);
263 AgsThread* ags_thread_self(void);
264 
265 AgsThread* ags_thread_parent(AgsThread *thread);
266 AgsThread* ags_thread_next(AgsThread *thread);
267 AgsThread* ags_thread_prev(AgsThread *thread);
268 AgsThread* ags_thread_children(AgsThread *thread);
269 
270 AgsThread* ags_thread_get_toplevel(AgsThread *thread);
271 AgsThread* ags_thread_first(AgsThread *thread);
272 AgsThread* ags_thread_last(AgsThread *thread);
273 
274 void ags_thread_lock(AgsThread *thread);
275 gboolean ags_thread_trylock(AgsThread *thread);
276 void ags_thread_unlock(AgsThread *thread);
277 
278 void ags_thread_remove_child(AgsThread *thread, AgsThread *child);
279 void ags_thread_add_child(AgsThread *thread, AgsThread *child);
280 void ags_thread_add_child_extended(AgsThread *thread, AgsThread *child,
281 				   gboolean no_start, gboolean no_wait);
282 
283 gboolean ags_thread_is_current_ready(AgsThread *current, guint current_sync_tic);
284 gboolean ags_thread_is_tree_ready_recursive(AgsThread *thread, guint current_sync_tic);
285 
286 void ags_thread_prepare_current_sync(AgsThread *current, guint current_sync_tic);
287 void ags_thread_prepare_tree_sync_recursive(AgsThread *thread, guint current_sync_tic);
288 
289 void ags_thread_set_current_sync(AgsThread *current, guint current_sync_tic);
290 void ags_thread_set_tree_sync_recursive(AgsThread *thread, guint current_sync_tic);
291 
292 guint ags_thread_clock(AgsThread *thread);
293 
294 void ags_thread_add_start_queue(AgsThread *thread,
295 				AgsThread *child);
296 void ags_thread_add_start_queue_all(AgsThread *thread,
297 				    GList *child);
298 
299 void ags_thread_start(AgsThread *thread);
300 void ags_thread_run(AgsThread *thread);
301 void ags_thread_stop(AgsThread *thread);
302 
303 AgsThread* ags_thread_new();
304 
305 G_END_DECLS
306 
307 #endif /*__AGS_THREAD_H__*/
308