diff --git a/gdk/gdkparalleltask.c b/gdk/gdkparalleltask.c new file mode 100644 index 0000000000..4b9c49e609 --- /dev/null +++ b/gdk/gdkparalleltask.c @@ -0,0 +1,86 @@ +/* + * Copyright © 2024 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + +#include "config.h" + +#include "gdkparalleltaskprivate.h" + +typedef struct _TaskData TaskData; + +struct _TaskData +{ + GdkTaskFunc task_func; + gpointer task_data; + int n_running_tasks; +}; + +static void +gdk_parallel_task_thread_func (gpointer data, + gpointer unused) +{ + TaskData *task = data; + + task->task_func (task->task_data); + + g_atomic_int_add (&task->n_running_tasks, -1); +} + +/** + * gdk_parallel_task_run: + * @task_func: the function to spawn + * @task_data: data to pass to the function + * + * Spawns the given function in many threads. + * Once all functions have exited, this function returns. + **/ +void +gdk_parallel_task_run (GdkTaskFunc task_func, + gpointer task_data) +{ + static GThreadPool *pool; + TaskData task = { + .task_func = task_func, + .task_data = task_data, + }; + int i, n_tasks; + + if (g_once_init_enter (&pool)) + { + GThreadPool *the_pool = g_thread_pool_new (gdk_parallel_task_thread_func, + NULL, + MAX (2, g_get_num_processors ()) - 1, + FALSE, + NULL); + g_once_init_leave (&pool, the_pool); + } + + n_tasks = g_get_num_processors (); + task.n_running_tasks = n_tasks; + /* Start with 1 because we run 1 task ourselves */ + for (i = 1; i < n_tasks; i++) + { + g_thread_pool_push (pool, &task, NULL); + } + + gdk_parallel_task_thread_func (&task, NULL); + + while (g_atomic_int_get (&task.n_running_tasks) > 0) + g_thread_yield (); +} + diff --git a/gdk/gdkparalleltaskprivate.h b/gdk/gdkparalleltaskprivate.h new file mode 100644 index 0000000000..a20fb72f95 --- /dev/null +++ b/gdk/gdkparalleltaskprivate.h @@ -0,0 +1,32 @@ +/* + * Copyright © 2024 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +typedef void (* GdkTaskFunc) (gpointer user_data); + +void gdk_parallel_task_run (GdkTaskFunc task_func, + gpointer task_data); + +G_END_DECLS + diff --git a/gdk/meson.build b/gdk/meson.build index 131d0f3018..b75349f291 100644 --- a/gdk/meson.build +++ b/gdk/meson.build @@ -52,6 +52,7 @@ gdk_public_sources = files([ 'gdkmonitor.c', 'gdkpaintable.c', 'gdkpango.c', + 'gdkparalleltask.c', 'gdkpipeiostream.c', 'gdkpopup.c', 'gdkpopuplayout.c',