/* * Copyright (C) 2020 Philip Withnall * Copyright (C) 2020 Richard Hughes * * SPDX-License-Identifier: LGPL-2.1+ */ #include typedef struct { GApplication *app; FwupdClient *client; GPtrArray *worker_threads; } FuThreadTestSelf; static gboolean fwupd_thread_test_exit_idle_cb(gpointer user_data) { FuThreadTestSelf *self = user_data; g_application_release(self->app); return G_SOURCE_REMOVE; } static gpointer fwupd_thread_test_thread_cb(gpointer user_data) { FuThreadTestSelf *self = user_data; g_autoptr(GError) error_local = NULL; g_autoptr(GPtrArray) devices = NULL; g_autoptr(GMainContext) context = g_main_context_new(); g_autoptr(GMainContextPusher) pusher = g_main_context_pusher_new(context); g_assert(pusher != NULL); g_message("Calling fwupd_client_get_devices() in thread %p with main context %p", g_thread_self(), g_main_context_get_thread_default()); devices = fwupd_client_get_devices(self->client, NULL, &error_local); if (devices == NULL) g_warning("%s", error_local->message); g_idle_add(fwupd_thread_test_exit_idle_cb, self); return NULL; } static gboolean fwupd_thread_test_idle_cb(gpointer user_data) { FuThreadTestSelf *self = user_data; g_message("fwupd_thread_test_idle_cb() in thread %p with main context %p", g_thread_self(), g_main_context_get_thread_default()); /* create 'n' threads with a small delay, and 'n-1' references on the app */ for (guint i = 0; i < 30; i++) { g_autofree gchar *thread_str = g_strdup_printf("worker%02u", i); GThread *thread = g_thread_new(thread_str, fwupd_thread_test_thread_cb, self); g_usleep(g_random_int_range(0, 1000)); g_ptr_array_add(self->worker_threads, thread); if (i > 0) g_application_hold(self->app); } return G_SOURCE_REMOVE; } static void fwupd_thread_test_activate_cb(GApplication *app, gpointer user_data) { FuThreadTestSelf *self = user_data; g_application_hold(self->app); g_idle_add(fwupd_thread_test_idle_cb, self); } static gboolean fwupd_thread_test_has_system_bus(void) { g_autoptr(GDBusConnection) conn = NULL; conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL); return conn != NULL; } int main(void) { gint retval; g_autoptr(FwupdClient) client = fwupd_client_new(); g_autoptr(GApplication) app = g_application_new("org.test.Test", G_APPLICATION_FLAGS_NONE); g_autoptr(GPtrArray) worker_threads = g_ptr_array_new(); FuThreadTestSelf self = {app, client, worker_threads}; /* only some of the CI targets have a DBus daemon */ if (!fwupd_thread_test_has_system_bus()) { g_message("D-Bus system bus unavailable, skipping tests."); return 0; } g_message("Created FwupdClient in thread %p with main context %p", g_thread_self(), g_main_context_get_thread_default()); g_signal_connect(app, "activate", G_CALLBACK(fwupd_thread_test_activate_cb), &self); retval = g_application_run(app, 0, NULL); for (guint i = 0; i < self.worker_threads->len; i++) { GThread *thread = g_ptr_array_index(self.worker_threads, i); g_thread_join(thread); } return retval; }