diff options
| author | Johan Hedberg <johan.hedberg@nokia.com> | 2006-08-25 13:17:24 +0000 | 
|---|---|---|
| committer | Johan Hedberg <johan.hedberg@nokia.com> | 2006-08-25 13:17:24 +0000 | 
| commit | dbe289f011a9ecedf0f4cabb9f25c9564c8aa830 (patch) | |
| tree | cffb67e5a8afb9932f5cc064a1234a8dd7fc5ddc | |
| parent | 39a699d168f52632ecd959a8e31b736ba86ad0ed (diff) | |
Fix and cleanup watch functionality
| -rw-r--r-- | common/glib-ectomy.c | 252 | ||||
| -rw-r--r-- | common/glib-ectomy.h | 22 | ||||
| -rw-r--r-- | common/list.c | 15 | ||||
| -rw-r--r-- | common/list.h | 2 | 
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, | 
