2 * ion/libmainloop/defer.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * See the included file LICENSE for details.
9 /* This file contains routines for deferred execution of potentially
10 * dangerous actions. They're called upon returning to the main
14 #include <libtu/obj.h>
15 #include <libtu/objp.h>
16 #include <libtu/types.h>
17 #include <libtu/misc.h>
18 #include <libtu/dlist.h>
19 #include <libtu/output.h>
20 #include <libtu/locale.h>
24 DECLSTRUCT(WDeferred){
26 WDeferredAction *action;
28 WDeferred *next, *prev;
33 static WDeferred *deferred=NULL;
38 /* To avoid allocating memory all the time, we use a small
39 * buffer that should be able to contain the small expected
40 * number of simultaneous deferred actions.
42 static WDeferred dbuf[N_DBUF];
43 static int dbuf_used=0;
46 static WDeferred *alloc_defer()
50 /* Keeping it simple -- this naive loop should do it
53 for(i=0; i<N_DBUF; i++){
54 if(!dbuf_used&(1<<i)){
59 return ALLOC(WDeferred);
63 static void free_defer(WDeferred *d)
65 if(d>=dbuf && d<dbuf+N_DBUF){
66 dbuf_used&=~1<<((d-dbuf)/sizeof(WDeferred));
73 static void defer_watch_handler(Watch *w, Obj *obj)
75 WDeferred *d=(WDeferred*)w;
77 UNLINK_ITEM(*(WDeferred**)(d->list), d, next, prev);
81 warn(TR("Object destroyed while deferred actions are still pending."));
85 static bool already_deferred(Obj *obj, WDeferredAction *action,
90 for(d=list; d!=NULL; d=d->next){
91 if(d->action==action && d->watch.obj==obj)
99 bool mainloop_defer_action_on_list(Obj *obj, WDeferredAction *action,
104 if(already_deferred(obj, action, *list))
116 d->fn=extl_fn_none();
117 watch_init(&(d->watch));
120 watch_setup(&(d->watch), obj, defer_watch_handler);
122 LINK_ITEM(*list, d, next, prev);
128 bool mainloop_defer_action(Obj *obj, WDeferredAction *action)
130 return mainloop_defer_action_on_list(obj, action, &deferred);
134 bool mainloop_defer_destroy(Obj *obj)
136 if(OBJ_IS_BEING_DESTROYED(obj))
139 return mainloop_defer_action(obj, destroy_obj);
143 bool mainloop_defer_extl_on_list(ExtlFn fn, WDeferred **list)
156 d->fn=extl_ref_fn(fn);
157 watch_init(&(d->watch));
159 LINK_ITEM(*list, d, next, prev);
166 * Defer execution of \var{fn} until the main loop.
169 EXTL_EXPORT_AS(mainloop, defer)
170 bool mainloop_defer_extl(ExtlFn fn)
172 return mainloop_defer_extl_on_list(fn, &deferred);
176 static void do_execute(WDeferred *d)
178 Obj *obj=d->watch.obj;
179 WDeferredAction *a=d->action;
182 watch_reset(&(d->watch));
186 /* The deferral should not be on the list, if there
187 * was an object, and it got destroyed.
191 }else if(fn!=extl_fn_none()){
192 extl_call(fn, NULL, NULL);
198 void mainloop_execute_deferred_on_list(WDeferred **list)
201 void (*action)(Obj*);
205 UNLINK_ITEM(*list, d, next, prev);
211 void mainloop_execute_deferred()
213 mainloop_execute_deferred_on_list(&deferred);