/src/tinysparql/subprojects/glib-2.80.3/glib/ghook.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* GLIB - Library of useful routines for C programming |
2 | | * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald |
3 | | * |
4 | | * GHook: Callback maintenance functions |
5 | | * Copyright (C) 1998 Tim Janik |
6 | | * |
7 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
8 | | * |
9 | | * This library is free software; you can redistribute it and/or |
10 | | * modify it under the terms of the GNU Lesser General Public |
11 | | * License as published by the Free Software Foundation; either |
12 | | * version 2.1 of the License, or (at your option) any later version. |
13 | | * |
14 | | * This library is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | | * Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public |
20 | | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | /* |
24 | | * Modified by the GLib Team and others 1997-2000. See the AUTHORS |
25 | | * file for a list of people on the GLib Team. See the ChangeLog |
26 | | * files for a list of changes. These files are distributed with |
27 | | * GLib at ftp://ftp.gtk.org/pub/gtk/. |
28 | | */ |
29 | | |
30 | | /* |
31 | | * MT safe |
32 | | */ |
33 | | |
34 | | #include "config.h" |
35 | | |
36 | | #include "ghook.h" |
37 | | |
38 | | #include "gtestutils.h" |
39 | | #include "gslice.h" |
40 | | |
41 | | /** |
42 | | * GHookList: |
43 | | * @seq_id: the next free #GHook id |
44 | | * @hook_size: the size of the #GHookList elements, in bytes |
45 | | * @is_setup: 1 if the #GHookList has been initialized |
46 | | * @hooks: the first #GHook element in the list |
47 | | * @dummy3: unused |
48 | | * @finalize_hook: the function to call to finalize a #GHook element. |
49 | | * The default behaviour is to call the hooks @destroy function |
50 | | * @dummy: unused |
51 | | * |
52 | | * The #GHookList struct represents a list of hook functions. |
53 | | */ |
54 | | |
55 | | /** |
56 | | * GHookFinalizeFunc: |
57 | | * @hook_list: a #GHookList |
58 | | * @hook: the hook in @hook_list that gets finalized |
59 | | * |
60 | | * Defines the type of function to be called when a hook in a |
61 | | * list of hooks gets finalized. |
62 | | */ |
63 | | |
64 | | /** |
65 | | * GHookFlagMask: |
66 | | * @G_HOOK_FLAG_ACTIVE: set if the hook has not been destroyed |
67 | | * @G_HOOK_FLAG_IN_CALL: set if the hook is currently being run |
68 | | * @G_HOOK_FLAG_MASK: A mask covering all bits reserved for |
69 | | * hook flags; see %G_HOOK_FLAG_USER_SHIFT |
70 | | * |
71 | | * Flags used internally in the #GHook implementation. |
72 | | */ |
73 | | |
74 | | /** |
75 | | * G_HOOK_FLAGS: |
76 | | * @hook: a #GHook |
77 | | * |
78 | | * Gets the flags of a hook. |
79 | | */ |
80 | | |
81 | | /** |
82 | | * G_HOOK_FLAG_USER_SHIFT: |
83 | | * |
84 | | * The position of the first bit which is not reserved for internal |
85 | | * use be the #GHook implementation, i.e. |
86 | | * `1 << G_HOOK_FLAG_USER_SHIFT` is the first |
87 | | * bit which can be used for application-defined flags. |
88 | | */ |
89 | | |
90 | | /** |
91 | | * G_HOOK: |
92 | | * @hook: a pointer |
93 | | * |
94 | | * Casts a pointer to a `GHook*`. |
95 | | */ |
96 | | |
97 | | /** |
98 | | * G_HOOK_IS_VALID: |
99 | | * @hook: a #GHook |
100 | | * |
101 | | * Returns %TRUE if the #GHook is valid, i.e. it is in a #GHookList, |
102 | | * it is active and it has not been destroyed. |
103 | | * |
104 | | * Returns: %TRUE if the #GHook is valid |
105 | | */ |
106 | | |
107 | | /** |
108 | | * G_HOOK_ACTIVE: |
109 | | * @hook: a #GHook |
110 | | * |
111 | | * Returns %TRUE if the #GHook is active, which is normally the case |
112 | | * until the #GHook is destroyed. |
113 | | * |
114 | | * Returns: %TRUE if the #GHook is active |
115 | | */ |
116 | | |
117 | | /** |
118 | | * G_HOOK_IN_CALL: |
119 | | * @hook: a #GHook |
120 | | * |
121 | | * Returns %TRUE if the #GHook function is currently executing. |
122 | | * |
123 | | * Returns: %TRUE if the #GHook function is currently executing |
124 | | */ |
125 | | |
126 | | /** |
127 | | * G_HOOK_IS_UNLINKED: |
128 | | * @hook: a #GHook |
129 | | * |
130 | | * Returns %TRUE if the #GHook is not in a #GHookList. |
131 | | * |
132 | | * Returns: %TRUE if the #GHook is not in a #GHookList |
133 | | */ |
134 | | |
135 | | /** |
136 | | * GHook: |
137 | | * @data: data which is passed to func when this hook is invoked |
138 | | * @next: pointer to the next hook in the list |
139 | | * @prev: pointer to the previous hook in the list |
140 | | * @ref_count: the reference count of this hook |
141 | | * @hook_id: the id of this hook, which is unique within its list |
142 | | * @flags: flags which are set for this hook. See #GHookFlagMask for |
143 | | * predefined flags |
144 | | * @func: the function to call when this hook is invoked. The possible |
145 | | * signatures for this function are #GHookFunc and #GHookCheckFunc |
146 | | * @destroy: the default @finalize_hook function of a #GHookList calls |
147 | | * this member of the hook that is being finalized |
148 | | * |
149 | | * The #GHook struct represents a single hook function in a #GHookList. |
150 | | */ |
151 | | |
152 | | /** |
153 | | * GHookFunc: |
154 | | * @data: the data field of the #GHook is passed to the hook function here |
155 | | * |
156 | | * Defines the type of a hook function that can be invoked |
157 | | * by g_hook_list_invoke(). |
158 | | */ |
159 | | |
160 | | /** |
161 | | * GHookCheckFunc: |
162 | | * @data: the data field of the #GHook is passed to the hook function here |
163 | | * |
164 | | * Defines the type of a hook function that can be invoked |
165 | | * by g_hook_list_invoke_check(). |
166 | | * |
167 | | * Returns: %FALSE if the #GHook should be destroyed |
168 | | */ |
169 | | |
170 | | /* --- functions --- */ |
171 | | static void |
172 | | default_finalize_hook (GHookList *hook_list, |
173 | | GHook *hook) |
174 | 0 | { |
175 | 0 | GDestroyNotify destroy = hook->destroy; |
176 | |
|
177 | 0 | if (destroy) |
178 | 0 | { |
179 | 0 | hook->destroy = NULL; |
180 | 0 | destroy (hook->data); |
181 | 0 | } |
182 | 0 | } |
183 | | |
184 | | /** |
185 | | * g_hook_list_init: |
186 | | * @hook_list: a #GHookList |
187 | | * @hook_size: the size of each element in the #GHookList, |
188 | | * typically `sizeof (GHook)`. |
189 | | * |
190 | | * Initializes a #GHookList. |
191 | | * This must be called before the #GHookList is used. |
192 | | */ |
193 | | void |
194 | | g_hook_list_init (GHookList *hook_list, |
195 | | guint hook_size) |
196 | 0 | { |
197 | 0 | g_return_if_fail (hook_list != NULL); |
198 | 0 | g_return_if_fail (hook_size >= sizeof (GHook)); |
199 | | |
200 | 0 | hook_list->seq_id = 1; |
201 | 0 | hook_list->hook_size = hook_size; |
202 | 0 | hook_list->is_setup = TRUE; |
203 | 0 | hook_list->hooks = NULL; |
204 | 0 | hook_list->dummy3 = NULL; |
205 | 0 | hook_list->finalize_hook = default_finalize_hook; |
206 | 0 | hook_list->dummy[0] = NULL; |
207 | 0 | hook_list->dummy[1] = NULL; |
208 | 0 | } |
209 | | |
210 | | /** |
211 | | * g_hook_list_clear: |
212 | | * @hook_list: a #GHookList |
213 | | * |
214 | | * Removes all the #GHook elements from a #GHookList. |
215 | | */ |
216 | | void |
217 | | g_hook_list_clear (GHookList *hook_list) |
218 | 0 | { |
219 | 0 | g_return_if_fail (hook_list != NULL); |
220 | | |
221 | 0 | if (hook_list->is_setup) |
222 | 0 | { |
223 | 0 | GHook *hook; |
224 | | |
225 | 0 | hook_list->is_setup = FALSE; |
226 | | |
227 | 0 | hook = hook_list->hooks; |
228 | 0 | if (!hook) |
229 | 0 | { |
230 | | /* destroy hook_list->hook_memchunk */ |
231 | 0 | } |
232 | 0 | else |
233 | 0 | do |
234 | 0 | { |
235 | 0 | GHook *tmp; |
236 | | |
237 | 0 | g_hook_ref (hook_list, hook); |
238 | 0 | g_hook_destroy_link (hook_list, hook); |
239 | 0 | tmp = hook->next; |
240 | 0 | g_hook_unref (hook_list, hook); |
241 | 0 | hook = tmp; |
242 | 0 | } |
243 | 0 | while (hook); |
244 | 0 | } |
245 | 0 | } |
246 | | |
247 | | /** |
248 | | * g_hook_alloc: |
249 | | * @hook_list: a #GHookList |
250 | | * |
251 | | * Allocates space for a #GHook and initializes it. |
252 | | * |
253 | | * Returns: a new #GHook |
254 | | */ |
255 | | GHook* |
256 | | g_hook_alloc (GHookList *hook_list) |
257 | 0 | { |
258 | 0 | GHook *hook; |
259 | | |
260 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
261 | 0 | g_return_val_if_fail (hook_list->is_setup, NULL); |
262 | | |
263 | 0 | hook = g_slice_alloc0 (hook_list->hook_size); |
264 | 0 | hook->data = NULL; |
265 | 0 | hook->next = NULL; |
266 | 0 | hook->prev = NULL; |
267 | 0 | hook->flags = G_HOOK_FLAG_ACTIVE; |
268 | 0 | hook->ref_count = 0; |
269 | 0 | hook->hook_id = 0; |
270 | 0 | hook->func = NULL; |
271 | 0 | hook->destroy = NULL; |
272 | | |
273 | 0 | return hook; |
274 | 0 | } |
275 | | /** |
276 | | * g_hook_free: |
277 | | * @hook_list: a #GHookList |
278 | | * @hook: the #GHook to free |
279 | | * |
280 | | * Calls the #GHookList @finalize_hook function if it exists, |
281 | | * and frees the memory allocated for the #GHook. |
282 | | */ |
283 | | void |
284 | | g_hook_free (GHookList *hook_list, |
285 | | GHook *hook) |
286 | 0 | { |
287 | 0 | g_return_if_fail (hook_list != NULL); |
288 | 0 | g_return_if_fail (hook_list->is_setup); |
289 | 0 | g_return_if_fail (hook != NULL); |
290 | 0 | g_return_if_fail (G_HOOK_IS_UNLINKED (hook)); |
291 | 0 | g_return_if_fail (!G_HOOK_IN_CALL (hook)); |
292 | | |
293 | 0 | if(hook_list->finalize_hook != NULL) |
294 | 0 | hook_list->finalize_hook (hook_list, hook); |
295 | 0 | g_slice_free1 (hook_list->hook_size, hook); |
296 | 0 | } |
297 | | |
298 | | /** |
299 | | * g_hook_destroy_link: |
300 | | * @hook_list: a #GHookList |
301 | | * @hook: the #GHook to remove |
302 | | * |
303 | | * Removes one #GHook from a #GHookList, marking it |
304 | | * inactive and calling g_hook_unref() on it. |
305 | | */ |
306 | | void |
307 | | g_hook_destroy_link (GHookList *hook_list, |
308 | | GHook *hook) |
309 | 0 | { |
310 | 0 | g_return_if_fail (hook_list != NULL); |
311 | 0 | g_return_if_fail (hook != NULL); |
312 | | |
313 | 0 | hook->flags &= ~G_HOOK_FLAG_ACTIVE; |
314 | 0 | if (hook->hook_id) |
315 | 0 | { |
316 | 0 | hook->hook_id = 0; |
317 | 0 | g_hook_unref (hook_list, hook); /* counterpart to g_hook_insert_before */ |
318 | 0 | } |
319 | 0 | } |
320 | | |
321 | | /** |
322 | | * g_hook_destroy: |
323 | | * @hook_list: a #GHookList |
324 | | * @hook_id: a hook ID |
325 | | * |
326 | | * Destroys a #GHook, given its ID. |
327 | | * |
328 | | * Returns: %TRUE if the #GHook was found in the #GHookList and destroyed |
329 | | */ |
330 | | gboolean |
331 | | g_hook_destroy (GHookList *hook_list, |
332 | | gulong hook_id) |
333 | 0 | { |
334 | 0 | GHook *hook; |
335 | | |
336 | 0 | g_return_val_if_fail (hook_list != NULL, FALSE); |
337 | 0 | g_return_val_if_fail (hook_id > 0, FALSE); |
338 | | |
339 | 0 | hook = g_hook_get (hook_list, hook_id); |
340 | 0 | if (hook) |
341 | 0 | { |
342 | 0 | g_hook_destroy_link (hook_list, hook); |
343 | 0 | return TRUE; |
344 | 0 | } |
345 | | |
346 | 0 | return FALSE; |
347 | 0 | } |
348 | | |
349 | | /** |
350 | | * g_hook_unref: |
351 | | * @hook_list: a #GHookList |
352 | | * @hook: the #GHook to unref |
353 | | * |
354 | | * Decrements the reference count of a #GHook. |
355 | | * If the reference count falls to 0, the #GHook is removed |
356 | | * from the #GHookList and g_hook_free() is called to free it. |
357 | | */ |
358 | | void |
359 | | g_hook_unref (GHookList *hook_list, |
360 | | GHook *hook) |
361 | 0 | { |
362 | 0 | g_return_if_fail (hook_list != NULL); |
363 | 0 | g_return_if_fail (hook != NULL); |
364 | 0 | g_return_if_fail (hook->ref_count > 0); |
365 | | |
366 | 0 | hook->ref_count--; |
367 | 0 | if (!hook->ref_count) |
368 | 0 | { |
369 | 0 | g_return_if_fail (hook->hook_id == 0); |
370 | 0 | g_return_if_fail (!G_HOOK_IN_CALL (hook)); |
371 | | |
372 | 0 | if (hook->prev) |
373 | 0 | hook->prev->next = hook->next; |
374 | 0 | else |
375 | 0 | hook_list->hooks = hook->next; |
376 | 0 | if (hook->next) |
377 | 0 | { |
378 | 0 | hook->next->prev = hook->prev; |
379 | 0 | hook->next = NULL; |
380 | 0 | } |
381 | 0 | hook->prev = NULL; |
382 | |
|
383 | 0 | if (!hook_list->is_setup) |
384 | 0 | { |
385 | 0 | hook_list->is_setup = TRUE; |
386 | 0 | g_hook_free (hook_list, hook); |
387 | 0 | hook_list->is_setup = FALSE; |
388 | | |
389 | 0 | if (!hook_list->hooks) |
390 | 0 | { |
391 | | /* destroy hook_list->hook_memchunk */ |
392 | 0 | } |
393 | 0 | } |
394 | 0 | else |
395 | 0 | g_hook_free (hook_list, hook); |
396 | 0 | } |
397 | 0 | } |
398 | | |
399 | | /** |
400 | | * g_hook_ref: |
401 | | * @hook_list: a #GHookList |
402 | | * @hook: the #GHook to increment the reference count of |
403 | | * |
404 | | * Increments the reference count for a #GHook. |
405 | | * |
406 | | * Returns: the @hook that was passed in (since 2.6) |
407 | | */ |
408 | | GHook * |
409 | | g_hook_ref (GHookList *hook_list, |
410 | | GHook *hook) |
411 | 0 | { |
412 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
413 | 0 | g_return_val_if_fail (hook != NULL, NULL); |
414 | 0 | g_return_val_if_fail (hook->ref_count > 0, NULL); |
415 | | |
416 | 0 | hook->ref_count++; |
417 | |
|
418 | 0 | return hook; |
419 | 0 | } |
420 | | |
421 | | /** |
422 | | * g_hook_append: |
423 | | * @hook_list: a #GHookList |
424 | | * @hook: the #GHook to add to the end of @hook_list |
425 | | * |
426 | | * Appends a #GHook onto the end of a #GHookList. |
427 | | */ |
428 | | |
429 | | /** |
430 | | * g_hook_prepend: |
431 | | * @hook_list: a #GHookList |
432 | | * @hook: the #GHook to add to the start of @hook_list |
433 | | * |
434 | | * Prepends a #GHook on the start of a #GHookList. |
435 | | */ |
436 | | void |
437 | | g_hook_prepend (GHookList *hook_list, |
438 | | GHook *hook) |
439 | 0 | { |
440 | 0 | g_return_if_fail (hook_list != NULL); |
441 | | |
442 | 0 | g_hook_insert_before (hook_list, hook_list->hooks, hook); |
443 | 0 | } |
444 | | |
445 | | /** |
446 | | * g_hook_insert_before: |
447 | | * @hook_list: a #GHookList |
448 | | * @sibling: (nullable): the #GHook to insert the new #GHook before |
449 | | * @hook: the #GHook to insert |
450 | | * |
451 | | * Inserts a #GHook into a #GHookList, before a given #GHook. |
452 | | */ |
453 | | void |
454 | | g_hook_insert_before (GHookList *hook_list, |
455 | | GHook *sibling, |
456 | | GHook *hook) |
457 | 0 | { |
458 | 0 | g_return_if_fail (hook_list != NULL); |
459 | 0 | g_return_if_fail (hook_list->is_setup); |
460 | 0 | g_return_if_fail (hook != NULL); |
461 | 0 | g_return_if_fail (G_HOOK_IS_UNLINKED (hook)); |
462 | 0 | g_return_if_fail (hook->ref_count == 0); |
463 | | |
464 | 0 | hook->hook_id = hook_list->seq_id++; |
465 | 0 | hook->ref_count = 1; /* counterpart to g_hook_destroy_link */ |
466 | | |
467 | 0 | if (sibling) |
468 | 0 | { |
469 | 0 | if (sibling->prev) |
470 | 0 | { |
471 | 0 | hook->prev = sibling->prev; |
472 | 0 | hook->prev->next = hook; |
473 | 0 | hook->next = sibling; |
474 | 0 | sibling->prev = hook; |
475 | 0 | } |
476 | 0 | else |
477 | 0 | { |
478 | 0 | hook_list->hooks = hook; |
479 | 0 | hook->next = sibling; |
480 | 0 | sibling->prev = hook; |
481 | 0 | } |
482 | 0 | } |
483 | 0 | else |
484 | 0 | { |
485 | 0 | if (hook_list->hooks) |
486 | 0 | { |
487 | 0 | sibling = hook_list->hooks; |
488 | 0 | while (sibling->next) |
489 | 0 | sibling = sibling->next; |
490 | 0 | hook->prev = sibling; |
491 | 0 | sibling->next = hook; |
492 | 0 | } |
493 | 0 | else |
494 | 0 | hook_list->hooks = hook; |
495 | 0 | } |
496 | 0 | } |
497 | | |
498 | | /** |
499 | | * g_hook_list_invoke: |
500 | | * @hook_list: a #GHookList |
501 | | * @may_recurse: %TRUE if functions which are already running |
502 | | * (e.g. in another thread) can be called. If set to %FALSE, |
503 | | * these are skipped |
504 | | * |
505 | | * Calls all of the #GHook functions in a #GHookList. |
506 | | */ |
507 | | void |
508 | | g_hook_list_invoke (GHookList *hook_list, |
509 | | gboolean may_recurse) |
510 | 0 | { |
511 | 0 | GHook *hook; |
512 | | |
513 | 0 | g_return_if_fail (hook_list != NULL); |
514 | 0 | g_return_if_fail (hook_list->is_setup); |
515 | | |
516 | 0 | hook = g_hook_first_valid (hook_list, may_recurse); |
517 | 0 | while (hook) |
518 | 0 | { |
519 | 0 | GHookFunc func; |
520 | 0 | gboolean was_in_call; |
521 | | |
522 | 0 | func = (GHookFunc) hook->func; |
523 | | |
524 | 0 | was_in_call = G_HOOK_IN_CALL (hook); |
525 | 0 | hook->flags |= G_HOOK_FLAG_IN_CALL; |
526 | 0 | func (hook->data); |
527 | 0 | if (!was_in_call) |
528 | 0 | hook->flags &= ~G_HOOK_FLAG_IN_CALL; |
529 | | |
530 | 0 | hook = g_hook_next_valid (hook_list, hook, may_recurse); |
531 | 0 | } |
532 | 0 | } |
533 | | |
534 | | /** |
535 | | * g_hook_list_invoke_check: |
536 | | * @hook_list: a #GHookList |
537 | | * @may_recurse: %TRUE if functions which are already running |
538 | | * (e.g. in another thread) can be called. If set to %FALSE, |
539 | | * these are skipped |
540 | | * |
541 | | * Calls all of the #GHook functions in a #GHookList. |
542 | | * Any function which returns %FALSE is removed from the #GHookList. |
543 | | */ |
544 | | void |
545 | | g_hook_list_invoke_check (GHookList *hook_list, |
546 | | gboolean may_recurse) |
547 | 0 | { |
548 | 0 | GHook *hook; |
549 | | |
550 | 0 | g_return_if_fail (hook_list != NULL); |
551 | 0 | g_return_if_fail (hook_list->is_setup); |
552 | | |
553 | 0 | hook = g_hook_first_valid (hook_list, may_recurse); |
554 | 0 | while (hook) |
555 | 0 | { |
556 | 0 | GHookCheckFunc func; |
557 | 0 | gboolean was_in_call; |
558 | 0 | gboolean need_destroy; |
559 | | |
560 | 0 | func = (GHookCheckFunc) hook->func; |
561 | | |
562 | 0 | was_in_call = G_HOOK_IN_CALL (hook); |
563 | 0 | hook->flags |= G_HOOK_FLAG_IN_CALL; |
564 | 0 | need_destroy = !func (hook->data); |
565 | 0 | if (!was_in_call) |
566 | 0 | hook->flags &= ~G_HOOK_FLAG_IN_CALL; |
567 | 0 | if (need_destroy) |
568 | 0 | g_hook_destroy_link (hook_list, hook); |
569 | | |
570 | 0 | hook = g_hook_next_valid (hook_list, hook, may_recurse); |
571 | 0 | } |
572 | 0 | } |
573 | | |
574 | | /** |
575 | | * GHookCheckMarshaller: |
576 | | * @hook: a #GHook |
577 | | * @marshal_data: user data |
578 | | * |
579 | | * Defines the type of function used by g_hook_list_marshal_check(). |
580 | | * |
581 | | * Returns: %FALSE if @hook should be destroyed |
582 | | */ |
583 | | |
584 | | /** |
585 | | * g_hook_list_marshal_check: |
586 | | * @hook_list: a #GHookList |
587 | | * @may_recurse: %TRUE if hooks which are currently running |
588 | | * (e.g. in another thread) are considered valid. If set to %FALSE, |
589 | | * these are skipped |
590 | | * @marshaller: (scope call): the function to call for each #GHook |
591 | | * @marshal_data: data to pass to @marshaller |
592 | | * |
593 | | * Calls a function on each valid #GHook and destroys it if the |
594 | | * function returns %FALSE. |
595 | | */ |
596 | | void |
597 | | g_hook_list_marshal_check (GHookList *hook_list, |
598 | | gboolean may_recurse, |
599 | | GHookCheckMarshaller marshaller, |
600 | | gpointer data) |
601 | 0 | { |
602 | 0 | GHook *hook; |
603 | | |
604 | 0 | g_return_if_fail (hook_list != NULL); |
605 | 0 | g_return_if_fail (hook_list->is_setup); |
606 | 0 | g_return_if_fail (marshaller != NULL); |
607 | | |
608 | 0 | hook = g_hook_first_valid (hook_list, may_recurse); |
609 | 0 | while (hook) |
610 | 0 | { |
611 | 0 | gboolean was_in_call; |
612 | 0 | gboolean need_destroy; |
613 | | |
614 | 0 | was_in_call = G_HOOK_IN_CALL (hook); |
615 | 0 | hook->flags |= G_HOOK_FLAG_IN_CALL; |
616 | 0 | need_destroy = !marshaller (hook, data); |
617 | 0 | if (!was_in_call) |
618 | 0 | hook->flags &= ~G_HOOK_FLAG_IN_CALL; |
619 | 0 | if (need_destroy) |
620 | 0 | g_hook_destroy_link (hook_list, hook); |
621 | | |
622 | 0 | hook = g_hook_next_valid (hook_list, hook, may_recurse); |
623 | 0 | } |
624 | 0 | } |
625 | | |
626 | | /** |
627 | | * GHookMarshaller: |
628 | | * @hook: a #GHook |
629 | | * @marshal_data: user data |
630 | | * |
631 | | * Defines the type of function used by g_hook_list_marshal(). |
632 | | */ |
633 | | |
634 | | /** |
635 | | * g_hook_list_marshal: |
636 | | * @hook_list: a #GHookList |
637 | | * @may_recurse: %TRUE if hooks which are currently running |
638 | | * (e.g. in another thread) are considered valid. If set to %FALSE, |
639 | | * these are skipped |
640 | | * @marshaller: (scope call): the function to call for each #GHook |
641 | | * @marshal_data: data to pass to @marshaller |
642 | | * |
643 | | * Calls a function on each valid #GHook. |
644 | | */ |
645 | | void |
646 | | g_hook_list_marshal (GHookList *hook_list, |
647 | | gboolean may_recurse, |
648 | | GHookMarshaller marshaller, |
649 | | gpointer data) |
650 | 0 | { |
651 | 0 | GHook *hook; |
652 | | |
653 | 0 | g_return_if_fail (hook_list != NULL); |
654 | 0 | g_return_if_fail (hook_list->is_setup); |
655 | 0 | g_return_if_fail (marshaller != NULL); |
656 | | |
657 | 0 | hook = g_hook_first_valid (hook_list, may_recurse); |
658 | 0 | while (hook) |
659 | 0 | { |
660 | 0 | gboolean was_in_call; |
661 | | |
662 | 0 | was_in_call = G_HOOK_IN_CALL (hook); |
663 | 0 | hook->flags |= G_HOOK_FLAG_IN_CALL; |
664 | 0 | marshaller (hook, data); |
665 | 0 | if (!was_in_call) |
666 | 0 | hook->flags &= ~G_HOOK_FLAG_IN_CALL; |
667 | | |
668 | 0 | hook = g_hook_next_valid (hook_list, hook, may_recurse); |
669 | 0 | } |
670 | 0 | } |
671 | | |
672 | | /** |
673 | | * g_hook_first_valid: |
674 | | * @hook_list: a #GHookList |
675 | | * @may_be_in_call: %TRUE if hooks which are currently running |
676 | | * (e.g. in another thread) are considered valid. If set to %FALSE, |
677 | | * these are skipped |
678 | | * |
679 | | * Returns the first #GHook in a #GHookList which has not been destroyed. |
680 | | * The reference count for the #GHook is incremented, so you must call |
681 | | * g_hook_unref() to restore it when no longer needed. (Or call |
682 | | * g_hook_next_valid() if you are stepping through the #GHookList.) |
683 | | * |
684 | | * Returns: the first valid #GHook, or %NULL if none are valid |
685 | | */ |
686 | | GHook* |
687 | | g_hook_first_valid (GHookList *hook_list, |
688 | | gboolean may_be_in_call) |
689 | 0 | { |
690 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
691 | | |
692 | 0 | if (hook_list->is_setup) |
693 | 0 | { |
694 | 0 | GHook *hook; |
695 | | |
696 | 0 | hook = hook_list->hooks; |
697 | 0 | if (hook) |
698 | 0 | { |
699 | 0 | g_hook_ref (hook_list, hook); |
700 | 0 | if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook))) |
701 | 0 | return hook; |
702 | 0 | else |
703 | 0 | return g_hook_next_valid (hook_list, hook, may_be_in_call); |
704 | 0 | } |
705 | 0 | } |
706 | | |
707 | 0 | return NULL; |
708 | 0 | } |
709 | | |
710 | | /** |
711 | | * g_hook_next_valid: |
712 | | * @hook_list: a #GHookList |
713 | | * @hook: the current #GHook |
714 | | * @may_be_in_call: %TRUE if hooks which are currently running |
715 | | * (e.g. in another thread) are considered valid. If set to %FALSE, |
716 | | * these are skipped |
717 | | * |
718 | | * Returns the next #GHook in a #GHookList which has not been destroyed. |
719 | | * The reference count for the #GHook is incremented, so you must call |
720 | | * g_hook_unref() to restore it when no longer needed. (Or continue to call |
721 | | * g_hook_next_valid() until %NULL is returned.) |
722 | | * |
723 | | * Returns: the next valid #GHook, or %NULL if none are valid |
724 | | */ |
725 | | GHook* |
726 | | g_hook_next_valid (GHookList *hook_list, |
727 | | GHook *hook, |
728 | | gboolean may_be_in_call) |
729 | 0 | { |
730 | 0 | GHook *ohook = hook; |
731 | |
|
732 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
733 | | |
734 | 0 | if (!hook) |
735 | 0 | return NULL; |
736 | | |
737 | 0 | hook = hook->next; |
738 | 0 | while (hook) |
739 | 0 | { |
740 | 0 | if (G_HOOK_IS_VALID (hook) && (may_be_in_call || !G_HOOK_IN_CALL (hook))) |
741 | 0 | { |
742 | 0 | g_hook_ref (hook_list, hook); |
743 | 0 | g_hook_unref (hook_list, ohook); |
744 | | |
745 | 0 | return hook; |
746 | 0 | } |
747 | 0 | hook = hook->next; |
748 | 0 | } |
749 | 0 | g_hook_unref (hook_list, ohook); |
750 | |
|
751 | 0 | return NULL; |
752 | 0 | } |
753 | | |
754 | | /** |
755 | | * g_hook_get: |
756 | | * @hook_list: a #GHookList |
757 | | * @hook_id: a hook id |
758 | | * |
759 | | * Returns the #GHook with the given id, or %NULL if it is not found. |
760 | | * |
761 | | * Returns: the #GHook with the given id, or %NULL if it is not found |
762 | | */ |
763 | | GHook* |
764 | | g_hook_get (GHookList *hook_list, |
765 | | gulong hook_id) |
766 | 0 | { |
767 | 0 | GHook *hook; |
768 | | |
769 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
770 | 0 | g_return_val_if_fail (hook_id > 0, NULL); |
771 | | |
772 | 0 | hook = hook_list->hooks; |
773 | 0 | while (hook) |
774 | 0 | { |
775 | 0 | if (hook->hook_id == hook_id) |
776 | 0 | return hook; |
777 | 0 | hook = hook->next; |
778 | 0 | } |
779 | | |
780 | 0 | return NULL; |
781 | 0 | } |
782 | | |
783 | | /** |
784 | | * GHookFindFunc: |
785 | | * @hook: a #GHook |
786 | | * @data: user data passed to g_hook_find_func() |
787 | | * |
788 | | * Defines the type of the function passed to g_hook_find(). |
789 | | * |
790 | | * Returns: %TRUE if the required #GHook has been found |
791 | | */ |
792 | | |
793 | | /** |
794 | | * g_hook_find: |
795 | | * @hook_list: a #GHookList |
796 | | * @need_valids: %TRUE if #GHook elements which have been destroyed |
797 | | * should be skipped |
798 | | * @func: (scope call): the function to call for each #GHook, which should return |
799 | | * %TRUE when the #GHook has been found |
800 | | * @data: the data to pass to @func |
801 | | * |
802 | | * Finds a #GHook in a #GHookList using the given function to |
803 | | * test for a match. |
804 | | * |
805 | | * Returns: the found #GHook or %NULL if no matching #GHook is found |
806 | | */ |
807 | | GHook* |
808 | | g_hook_find (GHookList *hook_list, |
809 | | gboolean need_valids, |
810 | | GHookFindFunc func, |
811 | | gpointer data) |
812 | 0 | { |
813 | 0 | GHook *hook; |
814 | | |
815 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
816 | 0 | g_return_val_if_fail (func != NULL, NULL); |
817 | | |
818 | 0 | hook = hook_list->hooks; |
819 | 0 | while (hook) |
820 | 0 | { |
821 | 0 | GHook *tmp; |
822 | | |
823 | | /* test only non-destroyed hooks */ |
824 | 0 | if (!hook->hook_id) |
825 | 0 | { |
826 | 0 | hook = hook->next; |
827 | 0 | continue; |
828 | 0 | } |
829 | | |
830 | 0 | g_hook_ref (hook_list, hook); |
831 | | |
832 | 0 | if (func (hook, data) && hook->hook_id && (!need_valids || G_HOOK_ACTIVE (hook))) |
833 | 0 | { |
834 | 0 | g_hook_unref (hook_list, hook); |
835 | | |
836 | 0 | return hook; |
837 | 0 | } |
838 | | |
839 | 0 | tmp = hook->next; |
840 | 0 | g_hook_unref (hook_list, hook); |
841 | 0 | hook = tmp; |
842 | 0 | } |
843 | | |
844 | 0 | return NULL; |
845 | 0 | } |
846 | | |
847 | | /** |
848 | | * g_hook_find_data: |
849 | | * @hook_list: a #GHookList |
850 | | * @need_valids: %TRUE if #GHook elements which have been destroyed |
851 | | * should be skipped |
852 | | * @data: the data to find |
853 | | * |
854 | | * Finds a #GHook in a #GHookList with the given data. |
855 | | * |
856 | | * Returns: the #GHook with the given @data or %NULL if no matching |
857 | | * #GHook is found |
858 | | */ |
859 | | GHook* |
860 | | g_hook_find_data (GHookList *hook_list, |
861 | | gboolean need_valids, |
862 | | gpointer data) |
863 | 0 | { |
864 | 0 | GHook *hook; |
865 | | |
866 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
867 | | |
868 | 0 | hook = hook_list->hooks; |
869 | 0 | while (hook) |
870 | 0 | { |
871 | | /* test only non-destroyed hooks */ |
872 | 0 | if (hook->data == data && |
873 | 0 | hook->hook_id && |
874 | 0 | (!need_valids || G_HOOK_ACTIVE (hook))) |
875 | 0 | return hook; |
876 | | |
877 | 0 | hook = hook->next; |
878 | 0 | } |
879 | | |
880 | 0 | return NULL; |
881 | 0 | } |
882 | | |
883 | | /** |
884 | | * g_hook_find_func: |
885 | | * @hook_list: a #GHookList |
886 | | * @need_valids: %TRUE if #GHook elements which have been destroyed |
887 | | * should be skipped |
888 | | * @func: the function to find |
889 | | * |
890 | | * Finds a #GHook in a #GHookList with the given function. |
891 | | * |
892 | | * Returns: the #GHook with the given @func or %NULL if no matching |
893 | | * #GHook is found |
894 | | */ |
895 | | GHook* |
896 | | g_hook_find_func (GHookList *hook_list, |
897 | | gboolean need_valids, |
898 | | gpointer func) |
899 | 0 | { |
900 | 0 | GHook *hook; |
901 | | |
902 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
903 | 0 | g_return_val_if_fail (func != NULL, NULL); |
904 | | |
905 | 0 | hook = hook_list->hooks; |
906 | 0 | while (hook) |
907 | 0 | { |
908 | | /* test only non-destroyed hooks */ |
909 | 0 | if (hook->func == func && |
910 | 0 | hook->hook_id && |
911 | 0 | (!need_valids || G_HOOK_ACTIVE (hook))) |
912 | 0 | return hook; |
913 | | |
914 | 0 | hook = hook->next; |
915 | 0 | } |
916 | | |
917 | 0 | return NULL; |
918 | 0 | } |
919 | | |
920 | | /** |
921 | | * g_hook_find_func_data: |
922 | | * @hook_list: a #GHookList |
923 | | * @need_valids: %TRUE if #GHook elements which have been destroyed |
924 | | * should be skipped |
925 | | * @func: (not nullable): the function to find |
926 | | * @data: the data to find |
927 | | * |
928 | | * Finds a #GHook in a #GHookList with the given function and data. |
929 | | * |
930 | | * Returns: the #GHook with the given @func and @data or %NULL if |
931 | | * no matching #GHook is found |
932 | | */ |
933 | | GHook* |
934 | | g_hook_find_func_data (GHookList *hook_list, |
935 | | gboolean need_valids, |
936 | | gpointer func, |
937 | | gpointer data) |
938 | 0 | { |
939 | 0 | GHook *hook; |
940 | | |
941 | 0 | g_return_val_if_fail (hook_list != NULL, NULL); |
942 | 0 | g_return_val_if_fail (func != NULL, NULL); |
943 | | |
944 | 0 | hook = hook_list->hooks; |
945 | 0 | while (hook) |
946 | 0 | { |
947 | | /* test only non-destroyed hooks */ |
948 | 0 | if (hook->data == data && |
949 | 0 | hook->func == func && |
950 | 0 | hook->hook_id && |
951 | 0 | (!need_valids || G_HOOK_ACTIVE (hook))) |
952 | 0 | return hook; |
953 | | |
954 | 0 | hook = hook->next; |
955 | 0 | } |
956 | | |
957 | 0 | return NULL; |
958 | 0 | } |
959 | | |
960 | | /** |
961 | | * GHookCompareFunc: |
962 | | * @new_hook: the #GHook being inserted |
963 | | * @sibling: the #GHook to compare with @new_hook |
964 | | * |
965 | | * Defines the type of function used to compare #GHook elements in |
966 | | * g_hook_insert_sorted(). |
967 | | * |
968 | | * Returns: a value <= 0 if @new_hook should be before @sibling |
969 | | */ |
970 | | |
971 | | /** |
972 | | * g_hook_insert_sorted: |
973 | | * @hook_list: a #GHookList |
974 | | * @hook: the #GHook to insert |
975 | | * @func: (scope call): the comparison function used to sort the #GHook elements |
976 | | * |
977 | | * Inserts a #GHook into a #GHookList, sorted by the given function. |
978 | | */ |
979 | | void |
980 | | g_hook_insert_sorted (GHookList *hook_list, |
981 | | GHook *hook, |
982 | | GHookCompareFunc func) |
983 | 0 | { |
984 | 0 | GHook *sibling; |
985 | | |
986 | 0 | g_return_if_fail (hook_list != NULL); |
987 | 0 | g_return_if_fail (hook_list->is_setup); |
988 | 0 | g_return_if_fail (hook != NULL); |
989 | 0 | g_return_if_fail (G_HOOK_IS_UNLINKED (hook)); |
990 | 0 | g_return_if_fail (hook->func != NULL); |
991 | 0 | g_return_if_fail (func != NULL); |
992 | | |
993 | | /* first non-destroyed hook */ |
994 | 0 | sibling = hook_list->hooks; |
995 | 0 | while (sibling && !sibling->hook_id) |
996 | 0 | sibling = sibling->next; |
997 | | |
998 | 0 | while (sibling) |
999 | 0 | { |
1000 | 0 | GHook *tmp; |
1001 | | |
1002 | 0 | g_hook_ref (hook_list, sibling); |
1003 | 0 | if (func (hook, sibling) <= 0 && sibling->hook_id) |
1004 | 0 | { |
1005 | 0 | g_hook_unref (hook_list, sibling); |
1006 | 0 | break; |
1007 | 0 | } |
1008 | | |
1009 | | /* next non-destroyed hook */ |
1010 | 0 | tmp = sibling->next; |
1011 | 0 | while (tmp && !tmp->hook_id) |
1012 | 0 | tmp = tmp->next; |
1013 | |
|
1014 | 0 | g_hook_unref (hook_list, sibling); |
1015 | 0 | sibling = tmp; |
1016 | | |
1017 | 0 | } |
1018 | | |
1019 | 0 | g_hook_insert_before (hook_list, sibling, hook); |
1020 | 0 | } |
1021 | | |
1022 | | /** |
1023 | | * g_hook_compare_ids: |
1024 | | * @new_hook: a #GHook |
1025 | | * @sibling: a #GHook to compare with @new_hook |
1026 | | * |
1027 | | * Compares the ids of two #GHook elements, returning a negative value |
1028 | | * if the second id is greater than the first. |
1029 | | * |
1030 | | * Returns: a value <= 0 if the id of @sibling is >= the id of @new_hook |
1031 | | */ |
1032 | | gint |
1033 | | g_hook_compare_ids (GHook *new_hook, |
1034 | | GHook *sibling) |
1035 | 0 | { |
1036 | 0 | if (new_hook->hook_id < sibling->hook_id) |
1037 | 0 | return -1; |
1038 | 0 | else if (new_hook->hook_id > sibling->hook_id) |
1039 | 0 | return 1; |
1040 | | |
1041 | 0 | return 0; |
1042 | 0 | } |