1 #include "tpl_utils_gthread.h"
10 tpl_gthread_func init_func;
21 tpl_bool_t is_eventfd;
22 tpl_gsource_functions *gsource_funcs;
24 tpl_gsource_type_t type;
25 tpl_gsource *finalizer;
26 tpl_bool_t intended_destroy;
32 __gsource_remove_and_destroy(tpl_gsource *source);
35 _tpl_gthread_init(gpointer data)
37 tpl_gthread *thread = (tpl_gthread *)data;
39 g_mutex_lock(&thread->thread_mutex);
41 if (thread->init_func)
42 thread->init_func(thread->func_data);
44 g_cond_signal(&thread->thread_cond);
45 g_mutex_unlock(&thread->thread_mutex);
47 g_main_loop_run(thread->loop);
53 tpl_gthread_create(const char *thread_name,
54 tpl_gthread_func init_func, void *func_data)
56 GMainContext *context = NULL;
57 GMainLoop *loop = NULL;
58 tpl_gthread *new_thread = NULL;
60 context = g_main_context_new();
62 TPL_ERR("Failed to create GMainContext");
66 loop = g_main_loop_new(context, FALSE);
68 TPL_ERR("Failed to create GMainLoop");
69 g_main_context_unref(context);
73 g_main_context_unref(context);
75 new_thread = calloc(1, sizeof(tpl_gthread));
77 TPL_ERR("Failed to allocate tpl_gthread");
78 g_main_context_unref(context);
79 g_main_loop_unref(loop);
84 g_mutex_init(&new_thread->thread_mutex);
85 g_cond_init(&new_thread->thread_cond);
88 g_mutex_lock(&new_thread->thread_mutex);
90 new_thread->loop = loop;
91 new_thread->init_func = init_func;
92 new_thread->func_data = func_data;
93 new_thread->thread = g_thread_new(thread_name,
94 _tpl_gthread_init, new_thread);
95 g_cond_wait(&new_thread->thread_cond,
96 &new_thread->thread_mutex);
98 g_mutex_unlock(&new_thread->thread_mutex);
104 tpl_gthread_destroy(tpl_gthread *thread)
106 g_mutex_lock(&thread->thread_mutex);
108 g_main_loop_quit(thread->loop);
109 g_thread_join(thread->thread);
110 g_main_loop_unref(thread->loop);
114 g_mutex_unlock(&thread->thread_mutex);
116 g_mutex_clear(&thread->thread_mutex);
117 g_cond_clear(&thread->thread_cond);
119 thread->func_data = NULL;
120 thread->thread = NULL;
127 _thread_source_prepare(GSource *source, gint *time)
129 tpl_gsource *gsource = (tpl_gsource *)source;
130 tpl_bool_t ret = TPL_FALSE;
132 if (gsource->type != SOURCE_TYPE_NORMAL)
135 if (gsource->gsource_funcs && gsource->gsource_funcs->prepare)
136 ret = gsource->gsource_funcs->prepare(gsource);
144 _thread_source_check(GSource *source)
146 tpl_gsource *gsource = (tpl_gsource *)source;
147 tpl_bool_t ret = TPL_FALSE;
149 if (gsource->type != SOURCE_TYPE_NORMAL)
152 if (gsource->gsource_funcs && gsource->gsource_funcs->check)
153 ret = gsource->gsource_funcs->check(gsource);
159 _thread_source_dispatch(GSource *source, GSourceFunc cb, gpointer data)
161 tpl_gsource *gsource = (tpl_gsource *)source;
162 gboolean ret = G_SOURCE_CONTINUE;
163 GIOCondition cond = g_source_query_unix_fd(source, gsource->tag);
164 tpl_gthread *thread = gsource->thread;
168 if (cond & G_IO_IN) {
170 uint64_t message = 0;
172 if (gsource->is_eventfd) {
173 s = read(gsource->fd, &message, sizeof(uint64_t));
174 if (s != sizeof(uint64_t)) {
175 TPL_ERR("Failed to read from event_fd(%d)",
180 if (gsource->gsource_funcs && gsource->gsource_funcs->dispatch)
181 ret = gsource->gsource_funcs->dispatch(gsource, message);
183 if (gsource->type == SOURCE_TYPE_FINALIZER &&
184 gsource->intended_destroy == TPL_TRUE) {
185 tpl_gsource *del_source = (tpl_gsource *)gsource->data;
186 if (!g_source_is_destroyed(&del_source->gsource)) {
187 g_mutex_lock(&thread->thread_mutex);
189 __gsource_remove_and_destroy(del_source);
190 __gsource_remove_and_destroy(gsource);
192 g_cond_signal(&thread->thread_cond);
193 g_mutex_unlock(&thread->thread_mutex);
195 return G_SOURCE_REMOVE;
200 if (cond && !(cond & G_IO_IN)) {
201 /* When some io errors occur, it is not considered as a critical error.
202 * There may be problems with the screen, but it does not affect the operation. */
203 TPL_WARN("Invalid GIOCondition occured. tpl_gsource(%p) fd(%d) cond(%d)",
204 gsource, gsource->fd, cond);
206 if (gsource->type == SOURCE_TYPE_DISPOSABLE) {
207 if (gsource->gsource_funcs && gsource->gsource_funcs->dispatch)
208 ret = gsource->gsource_funcs->dispatch(gsource, 0);
212 if (gsource->type == SOURCE_TYPE_DISPOSABLE) {
213 g_mutex_lock(&thread->thread_mutex);
214 __gsource_remove_and_destroy(gsource);
215 ret = G_SOURCE_REMOVE;
216 g_mutex_unlock(&thread->thread_mutex);
223 _thread_source_finalize(GSource *source)
225 tpl_gsource *gsource = (tpl_gsource *)source;
227 if (gsource->gsource_funcs && gsource->gsource_funcs->finalize)
228 gsource->gsource_funcs->finalize(gsource);
230 if (gsource->is_eventfd)
234 gsource->thread = NULL;
235 gsource->gsource_funcs = NULL;
236 gsource->data = NULL;
237 gsource->finalizer = NULL;
240 static GSourceFuncs _thread_source_funcs = {
241 .prepare = _thread_source_prepare,
242 .check = _thread_source_check,
243 .dispatch = _thread_source_dispatch,
244 .finalize = _thread_source_finalize,
248 tpl_gsource_create(tpl_gthread *thread, void *data, int fd,
249 tpl_gsource_functions *funcs, tpl_gsource_type_t type)
251 tpl_gsource *new_gsource = NULL;
253 new_gsource = (tpl_gsource *)g_source_new(&_thread_source_funcs,
254 sizeof(tpl_gsource));
256 TPL_ERR("Failed to create new tpl_gsource");
261 new_gsource->fd = eventfd(0, EFD_CLOEXEC);
262 if (new_gsource->fd < 0) {
263 TPL_ERR("Failed to create eventfd. errno(%d)", errno);
264 g_source_unref(&new_gsource->gsource);
268 new_gsource->is_eventfd = TPL_TRUE;
270 new_gsource->fd = fd;
271 new_gsource->is_eventfd = TPL_FALSE;
274 new_gsource->thread = thread;
275 new_gsource->gsource_funcs = funcs;
276 new_gsource->data = data;
277 new_gsource->type = type;
278 new_gsource->intended_destroy = TPL_FALSE;
280 if (new_gsource->type == SOURCE_TYPE_NORMAL) {
281 tpl_gsource *finalizer = tpl_gsource_create(thread, new_gsource, -1,
282 NULL, SOURCE_TYPE_FINALIZER);
283 new_gsource->finalizer = finalizer;
285 new_gsource->finalizer = NULL;
287 new_gsource->tag = g_source_add_unix_fd(&new_gsource->gsource,
290 g_source_attach(&new_gsource->gsource,
291 g_main_loop_get_context(thread->loop));
293 TPL_DEBUG("[GSOURCE_CREATE] tpl_gsource(%p) thread(%p) data(%p) fd(%d) type(%d)",
294 new_gsource, thread, data, new_gsource->fd, type);
300 __gsource_remove_and_destroy(tpl_gsource *source)
302 if (g_source_is_destroyed(&source->gsource))
305 TPL_DEBUG("[GSOURCE_DESTROY] tpl_gsource(%p) type(%d)",
306 source, source->type);
308 g_source_remove_unix_fd(&source->gsource, source->tag);
309 g_source_destroy(&source->gsource);
310 g_source_unref(&source->gsource);
314 tpl_gsource_destroy(tpl_gsource *source, tpl_bool_t destroy_in_thread)
316 tpl_gthread *thread = source->thread;
318 if (g_source_is_destroyed(&source->gsource)) {
319 TPL_WARN("gsource(%p) already has been destroyed.",
324 g_mutex_lock(&thread->thread_mutex);
325 if (source->type == SOURCE_TYPE_NORMAL &&
327 tpl_gsource *finalizer = source->finalizer;
329 if (destroy_in_thread) {
330 finalizer->intended_destroy = TPL_TRUE;
331 tpl_gsource_send_message(finalizer, 1);
333 g_cond_wait(&thread->thread_cond, &thread->thread_mutex);
335 __gsource_remove_and_destroy(finalizer);
336 source->finalizer = NULL;
340 if (!destroy_in_thread) {
341 __gsource_remove_and_destroy(source);
343 g_mutex_unlock(&thread->thread_mutex);
347 tpl_gsource_send_message(tpl_gsource *source, uint64_t message)
349 uint64_t value = message;
352 if (!source->is_eventfd) {
353 TPL_ERR("source is not using eventfd. source(%p) fd(%d)",
358 ret = write(source->fd, &value, sizeof(uint64_t));
360 TPL_ERR("failed to send devent. tpl_gsource(%p)",
366 tpl_gsource_get_data(tpl_gsource *source)
377 tpl_gsource_check_io_condition(tpl_gsource *source)
382 TPL_ERR("Invalid parameter tpl_gsource is null");
386 cond = g_source_query_unix_fd(&source->gsource, source->tag);
394 tpl_gmutex_init(tpl_gmutex *gmutex)
396 g_mutex_init(gmutex);
400 tpl_gmutex_clear(tpl_gmutex *gmutex)
402 g_mutex_clear(gmutex);
406 tpl_gmutex_lock(tpl_gmutex *gmutex)
408 g_mutex_lock(gmutex);
412 tpl_gmutex_unlock(tpl_gmutex *gmutex)
414 g_mutex_unlock(gmutex);
418 tpl_gcond_init(tpl_gcond *gcond)
424 tpl_gcond_clear(tpl_gcond *gcond)
430 tpl_gcond_wait(tpl_gcond *gcond, tpl_gmutex *gmutex)
432 g_cond_wait(gcond, gmutex);
436 tpl_cond_timed_wait(tpl_gcond *gcond, tpl_gmutex *gmutex,
439 gint64 end_time = g_get_monotonic_time() +
440 (timeout_ms * G_TIME_SPAN_MILLISECOND);
441 if (!g_cond_wait_until(gcond, gmutex, end_time))
442 return TPL_ERROR_TIME_OUT;
444 return TPL_ERROR_NONE;
448 tpl_gcond_signal(tpl_gcond *gcond)
450 g_cond_signal(gcond);