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_destroy_worker.h>
21
22 #include <ags/object/ags_connectable.h>
23
24 #include <stdlib.h>
25
26 void ags_destroy_worker_class_init(AgsDestroyWorkerClass *destroy_worker);
27 void ags_destroy_worker_init(AgsDestroyWorker *destroy_worker);
28 void ags_destroy_worker_finalize(GObject *gobject);
29
30 void ags_destroy_worker_start(AgsThread *thread);
31 void ags_destroy_worker_stop(AgsThread *thread);
32
33 void ags_destroy_worker_do_poll(AgsWorkerThread *worker_thread);
34
35 /**
36 * SECTION:ags_destroy_worker
37 * @short_description: destroy worker
38 * @title: AgsDestroyWorker
39 * @section_id:
40 * @include: ags/worker/ags_destroy_worker.h
41 *
42 * The #AgsDestroyWorker does non-realtime work. You might want
43 * give it the responsibility to destroy your objects.
44 */
45
46 static gpointer ags_destroy_worker_parent_class = NULL;
47
48 AgsDestroyWorker *ags_destroy_worker = NULL;
49
50 GType
ags_destroy_worker_get_type()51 ags_destroy_worker_get_type()
52 {
53 static volatile gsize g_define_type_id__volatile = 0;
54
55 if(g_once_init_enter (&g_define_type_id__volatile)){
56 GType ags_type_destroy_worker = 0;
57
58 static const GTypeInfo ags_destroy_worker_info = {
59 sizeof (AgsDestroyWorkerClass),
60 NULL, /* base_init */
61 NULL, /* base_finalize */
62 (GClassInitFunc) ags_destroy_worker_class_init,
63 NULL, /* class_finalize */
64 NULL, /* class_data */
65 sizeof (AgsDestroyWorker),
66 0, /* n_preallocs */
67 (GInstanceInitFunc) ags_destroy_worker_init,
68 };
69
70 ags_type_destroy_worker = g_type_register_static(AGS_TYPE_WORKER_THREAD,
71 "AgsDestroyWorker",
72 &ags_destroy_worker_info,
73 0);
74
75 g_once_init_leave(&g_define_type_id__volatile, ags_type_destroy_worker);
76 }
77
78 return g_define_type_id__volatile;
79 }
80
81 void
ags_destroy_worker_class_init(AgsDestroyWorkerClass * destroy_worker)82 ags_destroy_worker_class_init(AgsDestroyWorkerClass *destroy_worker)
83 {
84 GObjectClass *gobject;
85 AgsThreadClass *thread;
86 AgsWorkerThreadClass *worker_thread;
87
88 ags_destroy_worker_parent_class = g_type_class_peek_parent(destroy_worker);
89
90 /* GObject */
91 gobject = (GObjectClass *) destroy_worker;
92
93 gobject->finalize = ags_destroy_worker_finalize;
94
95 /* AgsThread */
96 thread = (AgsThreadClass *) destroy_worker;
97
98 thread->start = ags_destroy_worker_start;
99 thread->run = NULL;
100 thread->stop = ags_destroy_worker_stop;
101
102 /* AgsDestroyWorker */
103 worker_thread = (AgsWorkerThreadClass *) destroy_worker;
104
105 worker_thread->do_poll = ags_destroy_worker_do_poll;
106 }
107
108 void
ags_destroy_worker_init(AgsDestroyWorker * destroy_worker)109 ags_destroy_worker_init(AgsDestroyWorker *destroy_worker)
110 {
111 destroy_worker->destroy_interval = (struct timespec *) malloc(sizeof(struct timespec));
112
113 destroy_worker->destroy_interval->tv_sec = 1;
114 destroy_worker->destroy_interval->tv_nsec = 0;
115
116 /* lock destroy list */
117 g_rec_mutex_init(&(destroy_worker->destroy_mutex));
118
119 /* destroy list */
120 destroy_worker->destroy_list = NULL;
121 }
122
123 void
ags_destroy_worker_finalize(GObject * gobject)124 ags_destroy_worker_finalize(GObject *gobject)
125 {
126 AgsDestroyWorker *destroy_worker;
127
128 destroy_worker = AGS_DESTROY_WORKER(gobject);
129
130 if(destroy_worker->destroy_interval != NULL){
131 free(destroy_worker->destroy_interval);
132 }
133
134 /* call parent */
135 G_OBJECT_CLASS(ags_destroy_worker_parent_class)->finalize(gobject);
136 }
137
138 void
ags_destroy_worker_start(AgsThread * thread)139 ags_destroy_worker_start(AgsThread *thread)
140 {
141 AgsWorkerThread *worker_thread;
142
143 worker_thread = AGS_WORKER_THREAD(thread);
144
145 ags_worker_thread_set_status_flags(worker_thread, AGS_WORKER_THREAD_STATUS_RUNNING);
146
147 worker_thread->worker_thread = g_thread_new("Advanced Gtk+ Sequencer - destroy worker",
148 ags_woker_thread_do_poll_loop,
149 worker_thread);
150 }
151
152 void
ags_destroy_worker_stop(AgsThread * thread)153 ags_destroy_worker_stop(AgsThread *thread)
154 {
155 AgsWorkerThread *worker_thread;
156
157 worker_thread = AGS_WORKER_THREAD(thread);
158
159 ags_worker_thread_set_status_flags(worker_thread, AGS_WORKER_THREAD_STATUS_RUNNING);
160 }
161
162 void
ags_destroy_worker_do_poll(AgsWorkerThread * worker_thread)163 ags_destroy_worker_do_poll(AgsWorkerThread *worker_thread)
164 {
165 AgsDestroyWorker *destroy_worker;
166
167 GList *list, *list_start;
168
169 destroy_worker = AGS_DESTROY_WORKER(worker_thread);
170
171 g_rec_mutex_lock(&(destroy_worker->destroy_mutex));
172
173 list_start =
174 list = destroy_worker->destroy_list;
175 destroy_worker->destroy_list = NULL;
176
177 g_rec_mutex_unlock(&(destroy_worker->destroy_mutex));
178
179 while(list != NULL){
180 AGS_DESTROY_ENTRY(list->data)->destroy_func(AGS_DESTROY_ENTRY(list->data)->ptr);
181
182 list = list->next;
183 }
184
185 g_list_free_full(list_start,
186 g_free);
187
188 nanosleep(destroy_worker->destroy_interval,
189 NULL);
190 }
191
192 /**
193 * ags_destroy_entry_alloc:
194 * @ptr: a pointer
195 * @destroy_func: (scope call): the @ptr's destroy function
196 *
197 * Allocated a destroy entry.
198 *
199 * Returns: (type gpointer) (transfer none): the allocated #AgsDestroyEntry
200 *
201 * Since: 3.0.0
202 */
203 AgsDestroyEntry*
ags_destroy_entry_alloc(gpointer ptr,AgsDestroyFunc destroy_func)204 ags_destroy_entry_alloc(gpointer ptr, AgsDestroyFunc destroy_func)
205 {
206 AgsDestroyEntry *destroy_entry;
207
208 destroy_entry = (AgsDestroyEntry *) malloc(sizeof(AgsDestroyEntry));
209
210 destroy_entry->ptr = ptr;
211 destroy_entry->destroy_func = destroy_func;
212
213 return(destroy_entry);
214 }
215
216 /**
217 * ags_destroy_worker_add:
218 * @destroy_worker: (type gpointer): the #AgsDestroyWorker
219 * @ptr: the gpointer to destroy
220 * @destroy_func: (scope call): the AgsDestroyFunc
221 *
222 * Add @ptr for destruction using @destroy_func.
223 *
224 * Since: 3.0.0
225 */
226 void
ags_destroy_worker_add(AgsDestroyWorker * destroy_worker,gpointer ptr,AgsDestroyFunc destroy_func)227 ags_destroy_worker_add(AgsDestroyWorker *destroy_worker,
228 gpointer ptr, AgsDestroyFunc destroy_func)
229 {
230 AgsDestroyEntry *destroy_entry;
231
232 if(!AGS_IS_DESTROY_WORKER(destroy_worker) ||
233 ptr == NULL ||
234 destroy_func == NULL){
235 return;
236 }
237
238 destroy_entry = ags_destroy_entry_alloc(ptr, destroy_func);
239
240 g_rec_mutex_lock(&(destroy_worker->destroy_mutex));
241
242 destroy_worker->destroy_list = g_list_prepend(destroy_worker->destroy_list,
243 destroy_entry);
244
245 g_rec_mutex_unlock(&(destroy_worker->destroy_mutex));
246 }
247
248 /**
249 * ags_destroy_worker_get_instance:
250 *
251 * Get your destroy worker instance.
252 *
253 * Returns: (transfer none): the #AgsDestroyWorker instance
254 *
255 * Since: 3.0.0
256 */
257 AgsDestroyWorker*
ags_destroy_worker_get_instance()258 ags_destroy_worker_get_instance()
259 {
260 static GMutex mutex;
261
262 g_mutex_lock(&mutex);
263
264 if(ags_destroy_worker == NULL){
265 ags_destroy_worker = ags_destroy_worker_new();
266 }
267
268 g_mutex_unlock(&mutex);
269
270 return(ags_destroy_worker);
271 }
272
273 /**
274 * ags_destroy_worker_new:
275 *
276 * Create a new #AgsDestroyWorker.
277 *
278 * Returns: the new #AgsDestroyWorker
279 *
280 * Since: 3.0.0
281 */
282 AgsDestroyWorker*
ags_destroy_worker_new()283 ags_destroy_worker_new()
284 {
285 AgsDestroyWorker *destroy_worker;
286
287 destroy_worker = (AgsDestroyWorker *) g_object_new(AGS_TYPE_DESTROY_WORKER,
288 NULL);
289
290 return(destroy_worker);
291 }
292