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