summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2006-08-25 13:17:24 +0000
committerJohan Hedberg <johan.hedberg@nokia.com>2006-08-25 13:17:24 +0000
commitdbe289f011a9ecedf0f4cabb9f25c9564c8aa830 (patch)
treecffb67e5a8afb9932f5cc064a1234a8dd7fc5ddc
parent39a699d168f52632ecd959a8e31b736ba86ad0ed (diff)
Fix and cleanup watch functionality
-rw-r--r--common/glib-ectomy.c252
-rw-r--r--common/glib-ectomy.h22
-rw-r--r--common/list.c15
-rw-r--r--common/list.h2
4 files changed, 169 insertions, 122 deletions
diff --git a/common/glib-ectomy.c b/common/glib-ectomy.c
index 6bbee3f1..9566d936 100644
--- a/common/glib-ectomy.c
+++ b/common/glib-ectomy.c
@@ -13,8 +13,34 @@
#include <sys/time.h>
#include <time.h>
-#include "glib-ectomy.h"
#include "list.h"
+#include "glib-ectomy.h"
+
+struct timeout {
+ guint id;
+ guint interval;
+ struct timeval expiration;
+ gpointer data;
+ GSourceFunc function;
+};
+
+struct _GMainContext {
+ guint next_id;
+ glong next_timeout;
+
+ struct slist *timeouts;
+ struct slist *proc_timeouts;
+ gboolean timeout_lock;
+
+ struct slist *watches;
+ struct slist *proc_watches;
+ gboolean watch_lock;
+};
+
+struct _GMainLoop {
+ int bail;
+ GMainContext *context;
+};
GIOError g_io_channel_read(GIOChannel *channel, gchar *buf, gsize count, gsize *bytes_read)
{
@@ -88,55 +114,82 @@ struct watch {
GIOFunc func;
gpointer user_data;
GDestroyNotify destroy;
-
- struct watch *prev;
- struct watch *next;
};
-static struct watch watch_head = { .id = 0, .prev = 0, .next = 0, .revents = 0 };
-
static GMainContext *default_context = NULL;
-static void watch_remove(struct watch *w)
+static void watch_free(struct watch *watch)
{
- struct watch *p, *n;
+ if (watch->destroy)
+ watch->destroy(watch->user_data);
+ free(watch);
+}
- if (!w)
+void g_io_remove_watch(guint id)
+{
+ struct slist *l;
+ struct watch *w;
+
+ if (!default_context)
return;
- p = w->prev;
- n = w->next;
+ for (l = default_context->watches; l != NULL; l = l->next) {
+ w = l->data;
- if (p)
- p->next = n;
+ if (w->id != id)
+ continue;
- if (n)
- n->prev = p;
+ default_context->watches = slist_remove(default_context->watches, w);
+ watch_free(w);
- free(w);
-}
+ return;
+ }
-void g_io_remove_watch(guint id)
-{
- struct watch *w, *n;
+ for (l = default_context->proc_watches; l != NULL; l = l->next) {
+ w = l->data;
- for (w = watch_head.next; w; w = n) {
- n = w->next;
if (w->id != id)
continue;
- watch_remove(w);
+ default_context->proc_watches = slist_remove(default_context->proc_watches, w);
+ watch_free(w);
+
return;
}
}
+static GMainContext *g_main_context_default()
+{
+ if (default_context)
+ return default_context;
+
+ default_context = malloc(sizeof(GMainContext));
+ if (!default_context)
+ return NULL;
+
+ memset(default_context, 0, sizeof(GMainContext));
+
+ default_context->next_timeout = -1;
+ default_context->next_id = 1;
+
+ return default_context;
+}
+
guint g_io_add_watch_full(GIOChannel *channel, gint priority,
GIOCondition condition, GIOFunc func,
gpointer user_data, GDestroyNotify notify)
{
- struct watch *watch = malloc(sizeof(struct watch));
+ struct watch *watch;
+ GMainContext *context = g_main_context_default();
- watch->id = ++watch_head.id;
+ if (!context)
+ return 0;
+
+ watch = malloc(sizeof(struct watch));
+ if (!watch)
+ return 0;
+
+ watch->id = context->next_id++;
watch->channel = channel;
watch->priority = priority;
watch->condition = condition;
@@ -144,12 +197,10 @@ guint g_io_add_watch_full(GIOChannel *channel, gint priority,
watch->user_data = user_data;
watch->destroy = notify;
- watch->prev = &watch_head;
- watch->next = watch_head.next;
- if (watch_head.next)
- watch_head.next->prev = watch;
-
- watch_head.next = watch;
+ if (context->watch_lock)
+ context->proc_watches = slist_prepend(context->proc_watches, watch);
+ else
+ context->watches = slist_prepend(context->watches, watch);
return watch->id;
}
@@ -161,22 +212,6 @@ guint g_io_add_watch(GIOChannel *channel, GIOCondition condition,
func, user_data, NULL);
}
-static GMainContext *g_main_context_default()
-{
- if (default_context)
- return default_context;
-
- default_context = malloc(sizeof(GMainContext));
- if (!default_context)
- return NULL;
-
- memset(default_context, 0, sizeof(GMainContext));
-
- default_context->timeout = -1;
-
- return default_context;
-}
-
GMainLoop *g_main_loop_new(GMainContext *context, gboolean is_running)
{
GMainLoop *ml;
@@ -199,16 +234,14 @@ GMainLoop *g_main_loop_new(GMainContext *context, gboolean is_running)
static void timeout_handlers_prepare(GMainContext *context)
{
- struct slist *l = context->ltimeout;
- struct timeout *t;
+ struct slist *l;
struct timeval tv;
glong msec, timeout = LONG_MAX;
gettimeofday(&tv, NULL);
- while (l) {
- t = l->data;
- l = l->next;
+ for (l = context->timeouts; l != NULL; l = l->next) {
+ struct timeout *t = l->data;
/* calculate the remainning time */
msec = (t->expiration.tv_sec - tv.tv_sec) * 1000 +
@@ -220,32 +253,30 @@ static void timeout_handlers_prepare(GMainContext *context)
}
/* set to min value found or NO timeout */
- context->timeout = (timeout != LONG_MAX ? timeout: -1);
+ context->next_timeout = (timeout != LONG_MAX ? timeout : -1);
}
-static int timeout_cmp(const void *t1, const void *t2)
+static int ptr_cmp(const void *t1, const void *t2)
{
return t1 - t2;
}
static void timeout_handlers_check(GMainContext *context)
{
- struct timeout *t;
struct timeval tv;
gettimeofday(&tv, NULL);
- context->processed = NULL;
+ context->timeout_lock = TRUE;
- while (context->ltimeout) {
+ while (context->timeouts) {
+ struct timeout *t = context->timeouts->data;
glong secs, msecs;
gboolean ret;
- t = context->ltimeout->data;
-
if (timercmp(&tv, &t->expiration, <)) {
- context->ltimeout = slist_remove(context->ltimeout, t);
- context->processed = slist_append(context->processed, t);
+ context->timeouts = slist_remove(context->timeouts, t);
+ context->proc_timeouts = slist_append(context->proc_timeouts, t);
continue;
}
@@ -253,10 +284,10 @@ static void timeout_handlers_check(GMainContext *context)
/* Check if the handler was removed/freed by the callback
* function */
- if (!slist_find(context->ltimeout, t, timeout_cmp))
+ if (!slist_find(context->timeouts, t, ptr_cmp))
continue;
- context->ltimeout = slist_remove(context->ltimeout, t);
+ context->timeouts = slist_remove(context->timeouts, t);
if (!ret) {
free(t);
@@ -274,58 +305,77 @@ static void timeout_handlers_check(GMainContext *context)
t->expiration.tv_sec++;
}
- context->processed = slist_append(context->processed, t);
+ context->proc_timeouts = slist_append(context->proc_timeouts, t);
}
- context->ltimeout = context->processed;
- context->processed = NULL;
+ context->timeouts = context->proc_timeouts;
+ context->proc_timeouts = NULL;
+ context->timeout_lock = FALSE;
}
void g_main_loop_run(GMainLoop *loop)
{
int open_max = sysconf(_SC_OPEN_MAX);
struct pollfd *ufds;
+ GMainContext *context = loop->context;
ufds = malloc(open_max * sizeof(struct pollfd));
if (!ufds)
return;
while (!loop->bail) {
- int nfds, rc;
- struct watch *n, *w;
+ int nfds;
+ struct slist *l;
+ struct watch *w;
- nfds = 0;
- for (w = watch_head.next; w != NULL; w = w->next) {
+ for (nfds = 0, l = context->watches; l != NULL; l = l->next, nfds++) {
+ w = l->data;
ufds[nfds].fd = w->channel->fd;
ufds[nfds].events = w->condition;
ufds[nfds].revents = 0;
w->revents = &ufds[nfds].revents;
- nfds++;
}
/* calculate the next timeout */
- timeout_handlers_prepare(loop->context);
+ timeout_handlers_prepare(context);
- rc = poll(ufds, nfds, loop->context->timeout);
- if (rc < 0)
+ if (poll(ufds, nfds, context->next_timeout) < 0)
continue;
- w = watch_head.next;
- while (w) {
- if (!*w->revents || w->func(w->channel, *w->revents, w->user_data)) {
- w = w->next;
+ context->watch_lock = TRUE;
+
+ while (context->watches) {
+ gboolean ret;
+
+ w = context->watches->data;
+
+ if (!*w->revents) {
+ context->watches = slist_remove(context->watches, w);
+ context->proc_watches = slist_append(context->proc_watches, w);
continue;
}
- n = w->next;
+ ret = w->func(w->channel, *w->revents, w->user_data);
+
+ /* Check if the watch was removed/freed by the callback
+ * function */
+ if (!slist_find(context->watches, w, ptr_cmp))
+ continue;
- if (w->destroy)
- w->destroy(w->user_data);
- watch_remove(w);
+ context->watches = slist_remove(context->watches, w);
- w = n;
+ if (!ret) {
+ watch_free(w);
+ continue;
+ }
+
+ context->proc_watches = slist_append(context->proc_watches, w);
}
+ context->watches = context->proc_watches;
+ context->proc_watches = NULL;
+ context->watch_lock = FALSE;
+
/* check expired timers */
timeout_handlers_check(loop->context);
}
@@ -335,19 +385,7 @@ void g_main_loop_run(GMainLoop *loop)
void g_main_loop_quit(GMainLoop *loop)
{
- struct watch *w, *next;
-
loop->bail = 1;
-
- for (w = watch_head.next; w; w = next) {
- next = w->next;
- if (w->destroy)
- w->destroy(w->user_data);
- watch_head.next = w->next;
- free(w);
- }
-
- watch_head.next = NULL;
}
void g_main_loop_unref(GMainLoop *loop)
@@ -355,8 +393,12 @@ void g_main_loop_unref(GMainLoop *loop)
if (!loop->context)
return;
- slist_foreach(loop->context->ltimeout, (slist_func_t)free, NULL);
- slist_free(loop->context->ltimeout);
+ slist_foreach(loop->context->watches, (slist_func_t)watch_free, NULL);
+ slist_free(loop->context->watches);
+
+ slist_foreach(loop->context->timeouts, (slist_func_t)free, NULL);
+ slist_free(loop->context->timeouts);
+
free(loop->context);
loop->context = NULL;
}
@@ -395,8 +437,12 @@ guint g_timeout_add(guint interval, GSourceFunc function, gpointer data)
}
/* attach the timeout the default context */
- t->id = ++default_context->next_id;
- default_context->ltimeout = slist_append(default_context->ltimeout, t);
+ t->id = default_context->next_id++;
+
+ if (default_context->timeout_lock)
+ default_context->proc_timeouts = slist_prepend(default_context->proc_timeouts, t);
+ else
+ default_context->timeouts = slist_prepend(default_context->timeouts, t);
return t->id;
}
@@ -409,7 +455,7 @@ gint g_timeout_remove(const guint id)
if (!default_context)
return -1;
- l = default_context->ltimeout;
+ l = default_context->timeouts;
while (l) {
t = l->data;
@@ -418,13 +464,13 @@ gint g_timeout_remove(const guint id)
if (t->id != id)
continue;
- default_context->ltimeout = slist_remove(default_context->ltimeout, t);
+ default_context->timeouts = slist_remove(default_context->timeouts, t);
free(t);
return 0;
}
- l = default_context->processed;
+ l = default_context->proc_timeouts;
while (l) {
t = l->data;
@@ -433,7 +479,7 @@ gint g_timeout_remove(const guint id)
if (t->id != id)
continue;
- default_context->processed = slist_remove(default_context->processed, t);
+ default_context->proc_timeouts = slist_remove(default_context->proc_timeouts, t);
free(t);
return 0;
diff --git a/common/glib-ectomy.h b/common/glib-ectomy.h
index af6f4fbb..16f4810d 100644
--- a/common/glib-ectomy.h
+++ b/common/glib-ectomy.h
@@ -36,25 +36,9 @@ typedef struct _GIOChannel {
typedef gboolean (*GSourceFunc) (gpointer data);
-struct timeout {
- guint id;
- guint interval;
- struct timeval expiration;
- gpointer data;
- GSourceFunc function;
-};
-
-typedef struct _GMainContext {
- guint next_id;
- glong timeout;
- struct slist *ltimeout;
- struct slist *processed;
-} GMainContext;
-
-typedef struct _GMainLoop {
- int bail;
- GMainContext *context;
-} GMainLoop;
+typedef struct _GMainContext GMainContext;
+
+typedef struct _GMainLoop GMainLoop;
typedef enum {
G_IO_ERROR_NONE,
diff --git a/common/list.c b/common/list.c
index 42d377b7..a887bcdd 100644
--- a/common/list.c
+++ b/common/list.c
@@ -55,6 +55,21 @@ struct slist *slist_append(struct slist *list, void *data)
return list;
}
+struct slist *slist_prepend(struct slist *list, void *data)
+{
+ struct slist *entry;
+
+ entry = malloc(sizeof(struct slist));
+ /* FIXME: this currently just silently fails */
+ if (!entry)
+ return list;
+
+ entry->data = data;
+ entry->next = list;
+
+ return entry;
+}
+
struct slist *slist_remove(struct slist *list, void *data)
{
struct slist *l, *next, *prev = NULL, *match = NULL;
diff --git a/common/list.h b/common/list.h
index c43756a9..1b502110 100644
--- a/common/list.h
+++ b/common/list.h
@@ -35,6 +35,8 @@ typedef void (*slist_func_t)(void *data, void *user_data);
struct slist *slist_append(struct slist *list, void *data);
+struct slist *slist_prepend(struct slist *list, void *data);
+
struct slist *slist_remove(struct slist *list, void *data);
struct slist *slist_find(struct slist *list, const void *data,