messenger-gtk

Gtk+3 graphical user interfaces for GNUnet Messenger
Log | Files | Refs | Submodules | README | LICENSE

commit ceeb88257a9c2c8461654509c006757eaed248c4
parent 4567323fcf69165a27eff9b4bb6ff6d81a6c4696
Author: Jacki <jacki@thejackimonster.de>
Date:   Sat, 20 Jul 2024 22:36:52 +0200

Replace mutex synchronization with pipes

Diffstat:
Msrc/application.c | 76++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/application.h | 8+++++---
Msrc/chat/messenger.c | 44++------------------------------------------
Msrc/meson.build | 1+
Asrc/schedule.c | 165+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/schedule.h | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 278 insertions(+), 75 deletions(-)

diff --git a/src/application.c b/src/application.c @@ -97,6 +97,8 @@ _application_init(MESSENGER_Application *app) { g_assert(app); + schedule_load_glib(&(app->ui.schedule)); + ui_messenger_init(app, &(app->ui.messenger)); #ifndef MESSENGER_APPLICATION_NO_PORTAL @@ -312,11 +314,11 @@ application_init(MESSENGER_Application *app, _load_ui_stylesheets(app); + schedule_init(&(app->chat.schedule)); + schedule_init(&(app->ui.schedule)); + app->chat.status = EXIT_FAILURE; app->chat.tid = 0; - pipe(app->chat.pipe); - - pthread_mutex_init(&(app->chat.mutex), NULL); app->quarks.widget = g_quark_from_string("messenger_widget"); app->quarks.data = g_quark_from_string("messenger_data"); @@ -441,11 +443,6 @@ application_run(MESSENGER_Application *app) // Wait for other thread to stop properly pthread_join(app->chat.tid, NULL); - close(app->chat.pipe[0]); - close(app->chat.pipe[1]); - - pthread_mutex_destroy(&(app->chat.mutex)); - GList *list; // Get rid of open requests @@ -627,13 +624,10 @@ _application_event_call(gpointer user_data) call = (MESSENGER_ApplicationEventCall*) user_data; - // Locking the mutex for synchronization - pthread_mutex_lock(&(call->app->chat.mutex)); call->event(call->app); - pthread_mutex_unlock(&(call->app->chat.mutex)); GNUNET_free(call); - return FALSE; + return TRUE; } void @@ -651,7 +645,11 @@ application_call_event(MESSENGER_Application *app, call->app = app; call->event = event; - util_immediate_add(G_SOURCE_FUNC(_application_event_call), call); + schedule_sync_run( + &(app->ui.schedule), + G_SOURCE_FUNC(_application_event_call), + call + ); } static gboolean @@ -664,12 +662,9 @@ _application_sync_event_call(gpointer user_data) call = (MESSENGER_ApplicationEventCall*) user_data; call->event(call->app); - util_scheduler_cleanup(); - - pthread_mutex_unlock(&(call->app->chat.mutex)); GNUNET_free(call); - return FALSE; + return TRUE; } void @@ -687,11 +682,11 @@ application_call_sync_event(MESSENGER_Application *app, call->app = app; call->event = event; - util_scheduler_cleanup(); - util_immediate_add(G_SOURCE_FUNC(_application_sync_event_call), call); - - // Locking the mutex for synchronization - pthread_mutex_lock(&(app->chat.mutex)); + schedule_sync_run( + &(app->ui.schedule), + G_SOURCE_FUNC(_application_sync_event_call), + call + ); } typedef struct MESSENGER_ApplicationMessageEventCall @@ -712,13 +707,10 @@ _application_message_event_call(gpointer user_data) call = (MESSENGER_ApplicationMessageEventCall*) user_data; - // Locking the mutex for synchronization - pthread_mutex_lock(&(call->app->chat.mutex)); call->event(call->app, call->context, call->message); - pthread_mutex_unlock(&(call->app->chat.mutex)); GNUNET_free(call); - return FALSE; + return TRUE; } void @@ -741,7 +733,27 @@ application_call_message_event(MESSENGER_Application *app, call->context = context; call->message = message; - util_immediate_add(G_SOURCE_FUNC(_application_message_event_call), call); + schedule_sync_run( + &(app->ui.schedule), + G_SOURCE_FUNC(_application_message_event_call), + call + ); +} + +static gboolean +_application_stop_chat(gpointer user_data) +{ + MESSENGER_Application *app = user_data; + + if (app->chat.messenger.idle) + GNUNET_SCHEDULER_cancel(app->chat.messenger.idle); + + GNUNET_CHAT_disconnect(app->chat.messenger.handle); + GNUNET_CHAT_stop(app->chat.messenger.handle); + app->chat.messenger.handle = NULL; + + GNUNET_SCHEDULER_shutdown(); + return FALSE; } void @@ -750,10 +762,14 @@ application_exit(MESSENGER_Application *app, { g_assert(app); - // Forward a signal to the other thread causing it to shutdown the - // GNUnet handles of the application. - write(app->chat.pipe[1], &signal, sizeof(signal)); + schedule_sync_run( + &(app->chat.schedule), + G_SOURCE_FUNC(_application_stop_chat), + app + ); + schedule_cleanup(&(app->chat.schedule)); + schedule_cleanup(&(app->ui.schedule)); application_pw_core_cleanup(app); if (app->pw.context) diff --git a/src/application.h b/src/application.h @@ -55,6 +55,7 @@ #include "ui/send_file.h" #include "ui/settings.h" +#include "schedule.h" #include "util.h" #define MESSENGER_APPLICATION_APPNAME "GNUnet Messenger" @@ -109,10 +110,9 @@ typedef struct MESSENGER_Application pthread_t tid; char *identity; - int pipe [2]; - pthread_mutex_t mutex; - CHAT_MESSENGER_Handle messenger; + + MESSENGER_Schedule schedule; } chat; struct { @@ -139,6 +139,8 @@ typedef struct MESSENGER_Application UI_FILES_Handle files; UI_CONTACTS_Handle contacts; UI_SETTINGS_Handle settings; + + MESSENGER_Schedule schedule; } ui; struct { diff --git a/src/chat/messenger.c b/src/chat/messenger.c @@ -28,29 +28,6 @@ #include <gnunet/gnunet_chat_lib.h> static void -_chat_messenger_quit(void *cls) -{ - g_assert(cls); - - MESSENGER_Application *app = (MESSENGER_Application*) cls; - - if (app->chat.messenger.idle) - GNUNET_SCHEDULER_cancel(app->chat.messenger.idle); - - MESSENGER_ApplicationSignal signal; - int received = read(app->chat.pipe[0], &signal, sizeof(signal)); - - if (received < 0) - signal = MESSENGER_FAIL; - - GNUNET_CHAT_disconnect(app->chat.messenger.handle); - GNUNET_CHAT_stop(app->chat.messenger.handle); - app->chat.messenger.handle = NULL; - - GNUNET_SCHEDULER_shutdown(); -} - -static void _chat_messenger_idle(void *cls) { g_assert(cls); @@ -76,9 +53,6 @@ _chat_messenger_message(void *cls, MESSENGER_Application *app = (MESSENGER_Application*) cls; - // Locking the mutex for synchronization - pthread_mutex_lock(&(app->chat.mutex)); - if (GNUNET_YES == GNUNET_CHAT_message_is_deleted(message)) { application_call_message_event( @@ -238,7 +212,6 @@ _chat_messenger_message(void *cls, } skip_message_handling: - pthread_mutex_unlock(&(app->chat.mutex)); return GNUNET_YES; } @@ -252,6 +225,8 @@ chat_messenger_run(void *cls, MESSENGER_Application *app = (MESSENGER_Application*) cls; + schedule_load_gnunet(&(app->chat.schedule)); + // Start libgnunetchat handle app->chat.messenger.handle = GNUNET_CHAT_start( cfg, @@ -259,25 +234,10 @@ chat_messenger_run(void *cls, app ); - // Setup pipe to handle closing the application from the other thread - struct GNUNET_NETWORK_FDSet *fd = GNUNET_NETWORK_fdset_create (); - GNUNET_NETWORK_fdset_set_native(fd, app->chat.pipe[0]); - - app->chat.messenger.quit = GNUNET_SCHEDULER_add_select( - GNUNET_SCHEDULER_PRIORITY_URGENT, - GNUNET_TIME_relative_get_forever_(), - fd, - NULL, - &_chat_messenger_quit, - app - ); - // The idle callback seems to be necessary to not wait too long for // other events app->chat.messenger.idle = GNUNET_SCHEDULER_add_now( &_chat_messenger_idle, app ); - - GNUNET_NETWORK_fdset_destroy(fd); } diff --git a/src/meson.build b/src/meson.build @@ -30,6 +30,7 @@ messenger_gtk_sources = files([ 'file.c', 'file.h', 'request.c', 'request.h', 'resources.c', 'resources.h', + 'schedule.c', 'schedule.h', 'ui.c', 'ui.h', 'util.c', 'util.h', 'messenger_gtk.c', diff --git a/src/schedule.c b/src/schedule.c @@ -0,0 +1,165 @@ +/* + This file is part of GNUnet. + Copyright (C) 2024 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file schedule.c + */ + +#include "schedule.h" + +#include <glib-2.0/glib-unix.h> + +void +schedule_init(MESSENGER_Schedule *schedule) +{ + g_assert(schedule); + memset(schedule, 0, sizeof(MESSENGER_Schedule)); + + g_assert(0 == pipe(schedule->push_pipe)); + g_assert(0 == pipe(schedule->sync_pipe)); +} + +static void +__schedule_setup_push_task(MESSENGER_Schedule *schedule); + +static void +__schedule_pushed_task(void *cls) +{ + MESSENGER_Schedule *schedule = cls; + gboolean keep; + char val; + + g_assert(schedule); + schedule->task = NULL; + + g_assert(sizeof(val) == read(schedule->push_pipe[0], &val, sizeof(val))); + + keep = schedule->function(schedule->data); + + schedule->function = NULL; + schedule->data = NULL; + + if (keep) + __schedule_setup_push_task(schedule); + + g_assert(sizeof(val) == write(schedule->sync_pipe[1], &val, sizeof(val))); +} + +static void +__schedule_setup_push_task(MESSENGER_Schedule *schedule) +{ + struct GNUNET_NETWORK_FDSet *fd = GNUNET_NETWORK_fdset_create (); + GNUNET_NETWORK_fdset_set_native(fd, schedule->push_pipe[0]); + + schedule->task = GNUNET_SCHEDULER_add_select( + GNUNET_SCHEDULER_PRIORITY_DEFAULT, + GNUNET_TIME_relative_get_forever_(), + fd, + NULL, + __schedule_pushed_task, + schedule + ); + + GNUNET_NETWORK_fdset_destroy(fd); +} + +void +schedule_load_gnunet(MESSENGER_Schedule *schedule) +{ + g_assert(schedule); + __schedule_setup_push_task(schedule); +} + +static gboolean +__schedule_pushed(gint fd, + GIOCondition condition, + gpointer user_data) +{ + MESSENGER_Schedule *schedule = user_data; + gboolean keep; + guint task; + char val; + + g_assert(schedule); + task = schedule->poll; + schedule->poll = 0; + + g_assert(sizeof(val) == read(schedule->push_pipe[0], &val, sizeof(val))); + + keep = schedule->function(schedule->data); + + schedule->function = NULL; + schedule->data = NULL; + + if (keep) + schedule->poll = task; + + g_assert(sizeof(val) == write(schedule->sync_pipe[1], &val, sizeof(val))); + return keep; +} + +void +schedule_load_glib(MESSENGER_Schedule *schedule) +{ + g_assert(schedule); + schedule->poll = g_unix_fd_add( + schedule->push_pipe[0], + G_IO_IN, + __schedule_pushed, + schedule + ); +} + +void +schedule_cleanup(MESSENGER_Schedule *schedule) +{ + g_assert(schedule); + + if (schedule->task) + GNUNET_SCHEDULER_cancel(schedule->task); + if (schedule->poll) + g_source_remove(schedule->poll); + + close(schedule->push_pipe[0]); + close(schedule->push_pipe[1]); + + close(schedule->sync_pipe[0]); + close(schedule->sync_pipe[1]); + + memset(schedule, 0, sizeof(MESSENGER_Schedule)); +} + +void +schedule_sync_run(MESSENGER_Schedule *schedule, + GSourceFunc function, + gpointer data) +{ + g_assert((schedule) && (function)); + + schedule->function = function; + schedule->data = data; + + const char push = 1; + char sync; + + g_assert(sizeof(push) == write(schedule->push_pipe[1], &push, sizeof(push))); + g_assert(sizeof(sync) == read(schedule->sync_pipe[0], &sync, sizeof(sync))); + g_assert(push == sync); +} diff --git a/src/schedule.h b/src/schedule.h @@ -0,0 +1,59 @@ +/* + This file is part of GNUnet. + Copyright (C) 2024 GNUnet e.V. + + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + or (at your option) any later version. + + GNUnet is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + + SPDX-License-Identifier: AGPL3.0-or-later + */ +/* + * @author Tobias Frisch + * @file schedule.h + */ + +#ifndef SCHEDULE_H_ +#define SCHEDULE_H_ + +#include <glib-2.0/glib.h> +#include <gnunet/gnunet_util_lib.h> + +typedef struct MESSENGER_Schedule { + int push_pipe [2]; + int sync_pipe [2]; + + GSourceFunc function; + gpointer data; + + struct GNUNET_SCHEDULER_Task *task; + guint poll; +} MESSENGER_Schedule; + +void +schedule_init(MESSENGER_Schedule *schedule); + +void +schedule_load_gnunet(MESSENGER_Schedule *schedule); + +void +schedule_load_glib(MESSENGER_Schedule *schedule); + +void +schedule_cleanup(MESSENGER_Schedule *schedule); + +void +schedule_sync_run(MESSENGER_Schedule *schedule, + GSourceFunc function, + gpointer data); + +#endif /* SCHEDULE_H_ */