util.c (4615B)
1 /* 2 This file is part of GNUnet. 3 Copyright (C) 2024 GNUnet e.V. 4 5 GNUnet is free software: you can redistribute it and/or modify it 6 under the terms of the GNU Affero General Public License as published 7 by the Free Software Foundation, either version 3 of the License, 8 or (at your option) any later version. 9 10 GNUnet is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Affero General Public License for more details. 14 15 You should have received a copy of the GNU Affero General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 SPDX-License-Identifier: AGPL3.0-or-later 19 */ 20 /* 21 * @author Tobias Frisch 22 * @file util.c 23 */ 24 25 #include "util.h" 26 27 #include <pthread.h> 28 #include <stdio.h> 29 30 static GList *tasks = NULL; 31 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 32 33 struct UTIL_CompleteTask 34 { 35 GSourceFunc function; 36 gpointer data; 37 guint id; 38 }; 39 40 static void 41 util_kill_task(gpointer task_data) 42 { 43 g_assert(task_data); 44 45 struct UTIL_CompleteTask *task = (struct UTIL_CompleteTask*) task_data; 46 47 if (task->id) 48 g_source_remove(task->id); 49 50 g_free(task); 51 } 52 53 void 54 util_scheduler_cleanup() 55 { 56 if (tasks) 57 g_list_free_full(tasks, (GDestroyNotify) util_kill_task); 58 59 tasks = NULL; 60 } 61 62 static gboolean 63 util_complete_task(gpointer task_data) 64 { 65 g_assert(task_data); 66 67 struct UTIL_CompleteTask *task = (struct UTIL_CompleteTask*) task_data; 68 gboolean result = FALSE; 69 70 pthread_mutex_lock(&mutex); 71 if (!tasks) 72 goto unlock_mutex; 73 74 const GSourceFunc function = task->function; 75 gpointer data = task->data; 76 77 if (tasks) 78 tasks = g_list_remove(tasks, task); 79 80 g_free(task); 81 82 result = function(data); 83 84 unlock_mutex: 85 pthread_mutex_unlock(&mutex); 86 return result; 87 } 88 89 guint 90 util_idle_add(GSourceFunc function, 91 gpointer data) 92 { 93 struct UTIL_CompleteTask *task = g_malloc(sizeof(struct UTIL_CompleteTask)); 94 95 task->function = function; 96 task->data = data; 97 task->id = g_idle_add( 98 G_SOURCE_FUNC(util_complete_task), 99 task 100 ); 101 102 tasks = g_list_append( 103 tasks, 104 task 105 ); 106 107 return task->id; 108 } 109 110 guint 111 util_immediate_add(GSourceFunc function, 112 gpointer data) 113 { 114 struct UTIL_CompleteTask *task = g_malloc(sizeof(struct UTIL_CompleteTask)); 115 116 task->function = function; 117 task->data = data; 118 task->id = g_timeout_add( 119 0, 120 G_SOURCE_FUNC(util_complete_task), 121 task 122 ); 123 124 tasks = g_list_append( 125 tasks, 126 task 127 ); 128 129 return task->id; 130 } 131 132 guint 133 util_timeout_add(guint interval, 134 GSourceFunc function, 135 gpointer data) 136 { 137 struct UTIL_CompleteTask *task = g_malloc(sizeof(struct UTIL_CompleteTask)); 138 139 task->function = function; 140 task->data = data; 141 task->id = g_timeout_add( 142 interval, 143 G_SOURCE_FUNC(util_complete_task), 144 task 145 ); 146 147 tasks = g_list_append( 148 tasks, 149 task 150 ); 151 152 return task->id; 153 } 154 155 guint 156 util_timeout_add_seconds(guint interval, 157 GSourceFunc function, 158 gpointer data) 159 { 160 struct UTIL_CompleteTask *task = g_malloc(sizeof(struct UTIL_CompleteTask)); 161 162 task->function = function; 163 task->data = data; 164 task->id = g_timeout_add_seconds( 165 interval, 166 G_SOURCE_FUNC(util_complete_task), 167 task 168 ); 169 170 tasks = g_list_append( 171 tasks, 172 task 173 ); 174 175 return task->id; 176 } 177 178 gboolean 179 util_source_remove(guint tag) 180 { 181 struct UTIL_CompleteTask *task = NULL; 182 GList *current = tasks; 183 184 while (current) 185 { 186 task = (struct UTIL_CompleteTask*) current->data; 187 188 if (task->id == tag) 189 break; 190 191 current = g_list_next(current); 192 task = NULL; 193 } 194 195 if (!task) 196 return FALSE; 197 198 const gboolean result = g_source_remove(task->id); 199 200 tasks = g_list_remove(tasks, task); 201 g_free(task); 202 203 return result; 204 } 205 206 gboolean 207 util_source_remove_by_data(gpointer data) 208 { 209 struct UTIL_CompleteTask *task = NULL; 210 GList *current = tasks; 211 GList *matches = NULL; 212 213 while (current) 214 { 215 task = (struct UTIL_CompleteTask*) current->data; 216 217 if (task->data == data) 218 matches = g_list_append(matches, task); 219 220 current = g_list_next(current); 221 task = NULL; 222 } 223 224 if (!matches) 225 return FALSE; 226 227 gboolean result = TRUE; 228 229 current = matches; 230 while (current) 231 { 232 task = (struct UTIL_CompleteTask*) current->data; 233 234 result &= g_source_remove(task->id); 235 tasks = g_list_remove(tasks, task); 236 g_free(task); 237 238 current = g_list_next(current); 239 } 240 241 g_list_free(matches); 242 return result; 243 }