NetSurf
schedule.c
Go to the documentation of this file.
1/*
2 * Copyright 2006-2007 Daniel Silverstone <dsilvers@digital-scurf.org>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <glib.h>
20#include <stdlib.h>
21#include <stdbool.h>
22
23#include "utils/errors.h"
24#include "utils/log.h"
25
26#include "gtk/schedule.h"
27
28
29/** Killable callback closure embodiment. */
30typedef struct {
31 void (*callback)(void *); /**< The callback function. */
32 void *context; /**< The context for the callback. */
33 bool callback_killed; /**< Whether or not this was killed. */
35
36/** List of callbacks which have occurred and are pending running. */
37static GList *pending_callbacks = NULL;
38/** List of callbacks which are queued to occur in the future. */
39static GList *queued_callbacks = NULL;
40/** List of callbacks which are about to be run in this ::schedule_run. */
41static GList *this_run = NULL;
42
43static gboolean
45{
47 if (cb->callback_killed) {
48 /* This callback instance has been killed. */
49 NSLOG(schedule, DEBUG, "CB at %p already dead.", cb);
50 }
51 queued_callbacks = g_list_remove(queued_callbacks, cb);
52 pending_callbacks = g_list_append(pending_callbacks, cb);
53 return FALSE;
54}
55
56static void
57nsgtk_schedule_kill_callback(void *_target, void *_match)
58{
59 _nsgtk_callback_t *target = (_nsgtk_callback_t *)_target;
60 _nsgtk_callback_t *match = (_nsgtk_callback_t *)_match;
61 if ((target->callback == match->callback) &&
62 (target->context == match->context)) {
63 NSLOG(schedule, DEBUG,
64 "Found match for %p(%p), killing.",
65 target->callback, target->context);
66 target->callback = NULL;
67 target->context = NULL;
68 target->callback_killed = true;
69 match->callback_killed = true;
70 }
71}
72
73/**
74 * remove a matching callback and context tuple from all lists
75 *
76 * \param callback The callback to match
77 * \param cbctx The callback context to match
78 * \return NSERROR_OK if the tuple was removed from at least one list else NSERROR_NOT_FOUND
79 */
80static nserror
81schedule_remove(void (*callback)(void *p), void *cbctx)
82{
83 _nsgtk_callback_t cb_match = {
84 .callback = callback,
85 .context = cbctx,
86 .callback_killed = false,
87 };
88
89 g_list_foreach(queued_callbacks,
91 g_list_foreach(pending_callbacks,
93 g_list_foreach(this_run,
95
96 if (cb_match.callback_killed == false) {
97 return NSERROR_NOT_FOUND;
98 }
99 return NSERROR_OK;
100}
101
102/* exported interface documented in gtk/schedule.h */
103nserror nsgtk_schedule(int t, void (*callback)(void *p), void *cbctx)
104{
106 nserror res;
107
108 /* Kill any pending schedule of this kind. */
109 res = schedule_remove(callback, cbctx);
110
111 /* only removal */
112 if (t < 0) {
113 return res;
114 }
115
116 cb = malloc(sizeof(_nsgtk_callback_t));
117 cb->callback = callback;
118 cb->context = cbctx;
119 cb->callback_killed = false;
120 /* Prepend is faster right now. */
121 queued_callbacks = g_list_prepend(queued_callbacks, cb);
122 g_timeout_add(t, nsgtk_schedule_generic_callback, cb);
123
124 return NSERROR_OK;
125}
126
127bool
129{
130 /* Capture this run of pending callbacks into the list. */
132
133 if (this_run == NULL)
134 return false; /* Nothing to do */
135
136 /* Clear the pending list. */
137 pending_callbacks = NULL;
138
139 NSLOG(schedule, DEBUG,
140 "Captured a run of %d callbacks to fire.",
141 g_list_length(this_run));
142
143 /* Run all the callbacks which made it this far. */
144 while (this_run != NULL) {
146 this_run = g_list_remove(this_run, this_run->data);
147 if (!cb->callback_killed)
148 cb->callback(cb->context);
149 free(cb);
150 }
151 return true;
152}
int schedule_run(void)
Process events up to current time.
Definition: schedule.c:137
Error codes.
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NOT_FOUND
Requested item not found.
Definition: errors.h:34
@ NSERROR_OK
No error.
Definition: errors.h:30
static GList * pending_callbacks
List of callbacks which have occurred and are pending running.
Definition: schedule.c:37
static GList * queued_callbacks
List of callbacks which are queued to occur in the future.
Definition: schedule.c:39
static GList * this_run
List of callbacks which are about to be run in this schedule_run.
Definition: schedule.c:41
nserror nsgtk_schedule(int t, void(*callback)(void *p), void *cbctx)
Definition: schedule.c:103
static nserror schedule_remove(void(*callback)(void *p), void *cbctx)
remove a matching callback and context tuple from all lists
Definition: schedule.c:81
static void nsgtk_schedule_kill_callback(void *_target, void *_match)
Definition: schedule.c:57
static gboolean nsgtk_schedule_generic_callback(gpointer data)
Definition: schedule.c:44
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
Killable callback closure embodiment.
Definition: schedule.c:30
void(* callback)(void *)
The callback function.
Definition: schedule.c:31
void * context
The context for the callback.
Definition: schedule.c:32
bool callback_killed
Whether or not this was killed.
Definition: schedule.c:33