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