1 /* GSequencer - Advanced GTK Sequencer
2 * Copyright (C) 2005-2019 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_generic_main_loop.h>
21
22 #include <ags/object/ags_main_loop.h>
23
24 #include <ags/i18n.h>
25
26 void ags_generic_main_loop_class_init(AgsGenericMainLoopClass *generic_main_loop);
27 void ags_generic_main_loop_main_loop_interface_init(AgsMainLoopInterface *main_loop);
28 void ags_generic_main_loop_init(AgsGenericMainLoop *generic_main_loop);
29 void ags_generic_main_loop_set_property(GObject *gobject,
30 guint prop_id,
31 const GValue *value,
32 GParamSpec *param_spec);
33 void ags_generic_main_loop_get_property(GObject *gobject,
34 guint prop_id,
35 GValue *value,
36 GParamSpec *param_spec);
37 void ags_generic_main_loop_finalize(GObject *gobject);
38
39 GRecMutex* ags_generic_main_loop_get_tree_lock(AgsMainLoop *main_loop);
40 void ags_generic_main_loop_set_syncing(AgsMainLoop *main_loop, gboolean is_syncing);
41 gboolean ags_generic_main_loop_is_syncing(AgsMainLoop *main_loop);
42 void ags_generic_main_loop_set_critical_region(AgsMainLoop *main_loop, gboolean is_critical_region);
43 gboolean ags_generic_main_loop_is_critical_region(AgsMainLoop *main_loop);
44 void ags_generic_main_loop_inc_queued_critical_region(AgsMainLoop *main_loop);
45 void ags_generic_main_loop_dec_queued_critical_region(AgsMainLoop *main_loop);
46 guint ags_generic_main_loop_test_queued_critical_region(AgsMainLoop *main_loop);
47 void ags_generic_main_loop_change_frequency(AgsMainLoop *main_loop,
48 gdouble frequency);
49
50 void ags_generic_main_loop_start(AgsThread *thread);
51
52 /**
53 * SECTION:ags_generic_main_loop
54 * @short_description: generic loop
55 * @title: AgsGenericMainLoop
56 * @section_id:
57 * @include: ags/thread/ags_generic_main_loop.h
58 *
59 * The #AgsGenericMainLoop is suitable as #AgsMainLoop and does
60 * generic processing.
61 */
62
63 static gpointer ags_generic_main_loop_parent_class = NULL;
64
65 enum{
66 PROP_0,
67 };
68
69 GType
ags_generic_main_loop_get_type()70 ags_generic_main_loop_get_type()
71 {
72 static volatile gsize g_define_type_id__volatile = 0;
73
74 if(g_once_init_enter (&g_define_type_id__volatile)){
75 GType ags_type_generic_main_loop = 0;
76
77 static const GTypeInfo ags_generic_main_loop_info = {
78 sizeof (AgsGenericMainLoopClass),
79 NULL, /* base_init */
80 NULL, /* base_finalize */
81 (GClassInitFunc) ags_generic_main_loop_class_init,
82 NULL, /* class_finalize */
83 NULL, /* class_data */
84 sizeof (AgsGenericMainLoop),
85 0, /* n_preallocs */
86 (GInstanceInitFunc) ags_generic_main_loop_init,
87 };
88
89 static const GInterfaceInfo ags_main_loop_interface_info = {
90 (GInterfaceInitFunc) ags_generic_main_loop_main_loop_interface_init,
91 NULL, /* interface_finalize */
92 NULL, /* interface_data */
93 };
94
95 ags_type_generic_main_loop = g_type_register_static(AGS_TYPE_THREAD,
96 "AgsGenericMainLoop",
97 &ags_generic_main_loop_info,
98 0);
99
100 g_type_add_interface_static(ags_type_generic_main_loop,
101 AGS_TYPE_MAIN_LOOP,
102 &ags_main_loop_interface_info);
103
104 g_once_init_leave(&g_define_type_id__volatile, ags_type_generic_main_loop);
105 }
106
107 return g_define_type_id__volatile;
108 }
109
110 void
ags_generic_main_loop_class_init(AgsGenericMainLoopClass * generic_main_loop)111 ags_generic_main_loop_class_init(AgsGenericMainLoopClass *generic_main_loop)
112 {
113 GObjectClass *gobject;
114
115 AgsThreadClass *thread;
116
117 GParamSpec *param_spec;
118
119 ags_generic_main_loop_parent_class = g_type_class_peek_parent(generic_main_loop);
120
121 /* GObject */
122 gobject = (GObjectClass *) generic_main_loop;
123
124 gobject->set_property = ags_generic_main_loop_set_property;
125 gobject->get_property = ags_generic_main_loop_get_property;
126
127 gobject->finalize = ags_generic_main_loop_finalize;
128
129 /* properties */
130
131 /* AgsThread */
132 thread = (AgsThreadClass *) generic_main_loop;
133
134 thread->start = ags_generic_main_loop_start;
135
136 /* AgsGenericMainLoop */
137 }
138
139 void
ags_generic_main_loop_main_loop_interface_init(AgsMainLoopInterface * main_loop)140 ags_generic_main_loop_main_loop_interface_init(AgsMainLoopInterface *main_loop)
141 {
142 main_loop->get_tree_lock = ags_generic_main_loop_get_tree_lock;
143
144 main_loop->set_syncing = ags_generic_main_loop_set_syncing;
145 main_loop->is_syncing = ags_generic_main_loop_is_syncing;
146
147 main_loop->set_critical_region = ags_generic_main_loop_set_critical_region;
148 main_loop->is_critical_region = ags_generic_main_loop_is_critical_region;
149
150 main_loop->inc_queued_critical_region = ags_generic_main_loop_inc_queued_critical_region;
151 main_loop->dec_queued_critical_region = ags_generic_main_loop_dec_queued_critical_region;
152 main_loop->test_queued_critical_region = ags_generic_main_loop_test_queued_critical_region;
153
154 main_loop->change_frequency = ags_generic_main_loop_change_frequency;
155 }
156
157 void
ags_generic_main_loop_init(AgsGenericMainLoop * generic_main_loop)158 ags_generic_main_loop_init(AgsGenericMainLoop *generic_main_loop)
159 {
160 AgsThread *thread;
161
162 guint i;
163
164 /* calculate frequency */
165 thread = (AgsThread *) generic_main_loop;
166
167 ags_thread_set_flags(thread, AGS_THREAD_TIME_ACCOUNTING);
168
169 g_object_set(thread,
170 "frequency", AGS_GENERIC_MAIN_LOOP_DEFAULT_JIFFIE,
171 NULL);
172
173 /* tree lock mutex */
174 g_rec_mutex_init(&(generic_main_loop->tree_lock));
175
176 ags_main_loop_set_syncing(AGS_MAIN_LOOP(generic_main_loop), FALSE);
177
178 ags_main_loop_set_critical_region(AGS_MAIN_LOOP(generic_main_loop), FALSE);
179 g_atomic_int_set(&(generic_main_loop->critical_region_ref), 0);
180 }
181
182 void
ags_generic_main_loop_set_property(GObject * gobject,guint prop_id,const GValue * value,GParamSpec * param_spec)183 ags_generic_main_loop_set_property(GObject *gobject,
184 guint prop_id,
185 const GValue *value,
186 GParamSpec *param_spec)
187 {
188 AgsGenericMainLoop *generic_main_loop;
189
190 GRecMutex *thread_mutex;
191
192 generic_main_loop = AGS_GENERIC_MAIN_LOOP(gobject);
193
194 /* get thread mutex */
195 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(generic_main_loop);
196
197 switch(prop_id){
198 default:
199 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
200 break;
201 }
202 }
203
204 void
ags_generic_main_loop_get_property(GObject * gobject,guint prop_id,GValue * value,GParamSpec * param_spec)205 ags_generic_main_loop_get_property(GObject *gobject,
206 guint prop_id,
207 GValue *value,
208 GParamSpec *param_spec)
209 {
210 AgsGenericMainLoop *generic_main_loop;
211
212 GRecMutex *thread_mutex;
213
214 generic_main_loop = AGS_GENERIC_MAIN_LOOP(gobject);
215
216 /* get thread mutex */
217 thread_mutex = AGS_THREAD_GET_OBJ_MUTEX(generic_main_loop);
218
219 switch(prop_id){
220 default:
221 G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, param_spec);
222 break;
223 }
224 }
225
226 void
ags_generic_main_loop_finalize(GObject * gobject)227 ags_generic_main_loop_finalize(GObject *gobject)
228 {
229 /* call parent */
230 G_OBJECT_CLASS(ags_generic_main_loop_parent_class)->finalize(gobject);
231 }
232
233 GRecMutex*
ags_generic_main_loop_get_tree_lock(AgsMainLoop * main_loop)234 ags_generic_main_loop_get_tree_lock(AgsMainLoop *main_loop)
235 {
236 GRecMutex *tree_lock;
237
238 /* get tree lock mutex */
239 tree_lock = &(AGS_GENERIC_MAIN_LOOP(main_loop)->tree_lock);
240
241 return(tree_lock);
242 }
243
244 void
ags_generic_main_loop_set_syncing(AgsMainLoop * main_loop,gboolean is_syncing)245 ags_generic_main_loop_set_syncing(AgsMainLoop *main_loop, gboolean is_syncing)
246 {
247 AgsGenericMainLoop *generic_main_loop;
248
249 generic_main_loop = AGS_GENERIC_MAIN_LOOP(main_loop);
250
251 /* set syncing */
252 g_atomic_int_set(&(generic_main_loop->is_syncing), is_syncing);
253 }
254
255 gboolean
ags_generic_main_loop_is_syncing(AgsMainLoop * main_loop)256 ags_generic_main_loop_is_syncing(AgsMainLoop *main_loop)
257 {
258 AgsGenericMainLoop *generic_main_loop;
259
260 gboolean is_syncing;
261
262 generic_main_loop = AGS_GENERIC_MAIN_LOOP(main_loop);
263
264 /* is syncing */
265 is_syncing = g_atomic_int_get(&(generic_main_loop->is_syncing));
266
267 return(is_syncing);
268 }
269
270 void
ags_generic_main_loop_set_critical_region(AgsMainLoop * main_loop,gboolean is_critical_region)271 ags_generic_main_loop_set_critical_region(AgsMainLoop *main_loop, gboolean is_critical_region)
272 {
273 AgsGenericMainLoop *generic_main_loop;
274
275 generic_main_loop = AGS_GENERIC_MAIN_LOOP(main_loop);
276
277 /* set critical region */
278 g_atomic_int_set(&(generic_main_loop->is_critical_region), is_critical_region);
279 }
280
281 gboolean
ags_generic_main_loop_is_critical_region(AgsMainLoop * main_loop)282 ags_generic_main_loop_is_critical_region(AgsMainLoop *main_loop)
283 {
284 AgsGenericMainLoop *generic_main_loop;
285
286 gboolean is_critical_region;
287
288 generic_main_loop = AGS_GENERIC_MAIN_LOOP(main_loop);
289
290 /* is critical region */
291 is_critical_region = g_atomic_int_get(&(generic_main_loop->is_critical_region));
292
293 return(is_critical_region);
294 }
295
296 void
ags_generic_main_loop_inc_queued_critical_region(AgsMainLoop * main_loop)297 ags_generic_main_loop_inc_queued_critical_region(AgsMainLoop *main_loop)
298 {
299 AgsGenericMainLoop *generic_main_loop;
300
301 generic_main_loop = AGS_GENERIC_MAIN_LOOP(main_loop);
302
303 /* increment critical region */
304 g_atomic_int_inc(&(generic_main_loop->critical_region_ref));
305 }
306
307 void
ags_generic_main_loop_dec_queued_critical_region(AgsMainLoop * main_loop)308 ags_generic_main_loop_dec_queued_critical_region(AgsMainLoop *main_loop)
309 {
310 AgsGenericMainLoop *generic_main_loop;
311
312 generic_main_loop = AGS_GENERIC_MAIN_LOOP(main_loop);
313
314 /* decrement critical region */
315 g_atomic_int_dec_and_test(&(generic_main_loop->critical_region_ref));
316 }
317
318 guint
ags_generic_main_loop_test_queued_critical_region(AgsMainLoop * main_loop)319 ags_generic_main_loop_test_queued_critical_region(AgsMainLoop *main_loop)
320 {
321 AgsGenericMainLoop *generic_main_loop;
322
323 guint critical_region_ref;
324
325 generic_main_loop = AGS_GENERIC_MAIN_LOOP(main_loop);
326
327 /* set critical region */
328 critical_region_ref = g_atomic_int_get(&(generic_main_loop->is_critical_region));
329
330 return(critical_region_ref);
331 }
332
333 void
ags_generic_main_loop_change_frequency(AgsMainLoop * main_loop,gdouble frequency)334 ags_generic_main_loop_change_frequency(AgsMainLoop *main_loop,
335 gdouble frequency)
336 {
337 //empty
338 }
339
340 void
ags_generic_main_loop_start(AgsThread * thread)341 ags_generic_main_loop_start(AgsThread *thread)
342 {
343 AGS_THREAD_CLASS(ags_generic_main_loop_parent_class)->start(thread);
344 }
345
346 /**
347 * ags_generic_main_loop_new:
348 *
349 * Create a new #AgsGenericMainLoop.
350 *
351 * Returns: the new #AgsGenericMainLoop
352 *
353 * Since: 3.0.0
354 */
355 AgsGenericMainLoop*
ags_generic_main_loop_new()356 ags_generic_main_loop_new()
357 {
358 AgsGenericMainLoop *generic_main_loop;
359
360 generic_main_loop = (AgsGenericMainLoop *) g_object_new(AGS_TYPE_GENERIC_MAIN_LOOP,
361 NULL);
362
363 return(generic_main_loop);
364 }
365