]> rtime.felk.cvut.cz Git - ulut.git/blob - ulut/ul_evcbase.c
Fix non-typesafe/void * variant of GAVL to support non-unique keys.
[ulut.git] / ulut / ul_evcbase.c
1 /*******************************************************************
2   uLan Utilities Library - C library of basic reusable constructions
3
4   ul_evcbase.c  - event connectors
5
6   (C) Copyright 2001-2003 by Pavel Pisa - Originator
7
8   The uLan utilities library can be used, copied and modified under
9   next licenses
10     - GPL - GNU General Public License
11     - LGPL - GNU Lesser General Public License
12     - MPL - Mozilla Public License
13     - and other licenses added by project originators
14   Code can be modified and re-distributed under any combination
15   of the above listed licenses. If contributor does not agree with
16   some of the licenses, he/she can delete appropriate line.
17   Warning, if you delete all lines, you are not allowed to
18   distribute source code and/or binaries utilizing code.
19   
20   See files COPYING and README for details.
21
22  *******************************************************************/
23
24 #include <stdarg.h>
25 #include <string.h>
26 #include "ul_utmalloc.h"
27 #include "ul_list.h"
28 #include "ul_evcbase.h"
29
30 UL_LIST_CUST_DEC(evc_tx_list, evc_tx_hub_t, evc_link_t, links, src.peers)
31 UL_LIST_CUST_DEC(evc_rx_list, evc_rx_hub_t, evc_link_t, links, dst.multi.peers)
32
33 /**
34  * evc_link_init - Initialize Event Connector Link
35  * @link:       pointer to the link
36  *
37  * Link reference count is set to 1 by this function
38  * Return Value: negative value informs about failure.
39  */
40 int evc_link_init(evc_link_t *link)
41 {
42   memset(link,0,sizeof(evc_link_t));
43   evc_rx_list_init_detached(link);
44   evc_tx_list_init_detached(link);
45   evc_link_inc_refcnt(link);
46   return 0;
47 }
48
49 /**
50  * evc_link_new - Allocates New Event Connector Link
51  *
52  * Link reference count is set to 1 by this function
53  * Return Value: pointer to the new link or %NULL.
54  */
55 evc_link_t *evc_link_new(void)
56 {
57   evc_link_t *link;
58   
59   link=malloc(sizeof(evc_link_t));
60   if(link==NULL) return NULL;
61
62   evc_link_init(link);
63   link->malloced=1;
64   return link;
65 }
66
67 /**
68  * evc_link_connect - Connects Link between Two Hubs
69  * @link:       pointer to the non-connected initialized link
70  * @src:        pointer to the source hub of type &evc_tx_hub_t
71  * @dst:        pointer to the destination hub of type &evc_rx_hub_t
72  * @prop:       propagation function corresponding to source and destination
73  *              expected event arguments
74  *
75  * If ready flag is not set, link state is set to ready
76  * and reference count is increased.
77  * Return Value: negative return value indicates fail.
78  */
79 int evc_link_connect(evc_link_t *link, evc_tx_hub_t *src, evc_rx_hub_t *dst,
80                      evc_prop_fnc_t *prop)
81 {
82   int link_ready;
83
84   if(!link || !src || !dst || !prop) return -1;
85   if(link->standalone) return -1;
86   evc_link_inc_refcnt(link);
87   link->delete_pend=0;
88   link->propagate=prop;
89   link->src.hub=src;
90   evc_tx_list_insert(src,link);
91   link->dst.multi.hub=dst;
92   evc_rx_list_insert(dst,link);
93   link_ready=link->ready;
94   link->ready=1;
95   if(link_ready){
96     evc_link_dec_refcnt(link);
97   }
98
99   return 0;
100 }
101
102 /**
103  * evc_link_init_standalone - Initialize Standalone Link
104  * @link:       pointer to the link
105  * @rx_fnc:     pointer to the function invoked by event reception
106  * @context:    context for the rx_fnc() function invocation
107  *
108  * Link reference count is set to 1 by this function
109  * Return Value: negative value informs about failure.
110  */
111 int evc_link_init_standalone(evc_link_t *link, evc_rx_fnc_t *rx_fnc, void *context)
112 {
113   memset(link,0,sizeof(evc_link_t));
114   evc_rx_list_init_detached(link);
115   link->standalone=1;
116   link->dst.standalone.rx_fnc=rx_fnc;
117   link->dst.standalone.context=context;
118   evc_link_inc_refcnt(link);
119   return 0;
120 }
121
122 /**
123  * evc_link_new_standalone - Allocates New Standalone Link
124  * @rx_fnc:   callback function invoked if event is delivered
125  * @context:  context provided to the callback function
126  *
127  * Link reference count is set to 1 by this function
128  * Return Value: pointer to the new link or %NULL.
129  */
130 evc_link_t *evc_link_new_standalone(evc_rx_fnc_t *rx_fnc, void *context)
131 {
132   evc_link_t *link;
133   
134   link=malloc(sizeof(evc_link_t));
135   if(link==NULL) return NULL;
136
137   evc_link_init_standalone(link, rx_fnc, context);
138   link->malloced=1;
139   return link;
140 }
141
142 /**
143  * evc_link_connect_standalone - Connects Standalone Link to Source Hubs
144  * @link:       pointer to the non-connected initialized link
145  * @src:        pointer to the source hub of type &evc_tx_hub_t
146  * @prop:       propagation function corresponding to hub source
147  *              and standalone rx_fnc() expected event arguments
148  *
149  * If ready flag is not set, link state is set to ready
150  * and reference count is increased.
151  * Return Value: negative return value indicates failure.
152  */
153 int evc_link_connect_standalone(evc_link_t *link, evc_tx_hub_t *src,
154            evc_prop_fnc_t *prop)
155 {
156   int link_ready;
157
158   if(!link || !src || !prop) return -1;
159   if(!link->standalone) return -1;
160   evc_link_inc_refcnt(link);
161   link->delete_pend=0;
162   link->propagate=prop;
163   link->src.hub=src;
164   evc_tx_list_insert(src,link);
165   link_ready=link->ready;
166   link->ready=1;
167   if(link_ready){
168     evc_link_dec_refcnt(link);
169   }
170
171   return 0;
172 }
173
174
175 static inline
176 void evc_link_do_delete(evc_link_t *link)
177 {
178   evc_tx_list_del_item(link);
179   link->src.hub=NULL;
180   if(!link->standalone){
181     evc_rx_list_del_item(link);
182     link->dst.multi.hub=NULL;
183   }
184   link->delete_pend=0;
185 }
186
187
188 /**
189  * evc_link_delete - Deletes Link from Hubs Lists
190  * @link:       pointer to the possibly connected initialized link
191  *
192  * If ready flag is set, link ready flag is cleared and reference count
193  * is decreased. This could lead to link disappear, if nobody is holding
194  * reference.
195  * Return Value: positive return value indicates immediate delete,
196  *              zero return value informs about delayed delete.
197  */
198 int evc_link_delete(evc_link_t *link)
199 {
200   int res;
201   link->delete_pend=1;
202   if(!link->taken){
203     evc_link_do_delete(link);
204     res=1;
205   } else {
206     res=0;
207   }
208   if(link->ready){
209     link->ready=0;
210     evc_link_dec_refcnt(link);
211   }
212   return res;
213 }
214
215 /**
216  * evc_link_dispose - Disposes Link
217  * @link:       pointer to the possibly connected initialized link
218  *
219  * Deletes link from hubs, marks it as dead, calls final death propagate()
220  * for the link and if link is @malloced, releases link occupied memory.
221  */
222 void evc_link_dispose(evc_link_t *link)
223 {
224   if(!link->dead){
225     link->dead=1;
226     if(!link->propagate(link,0)){
227       evc_link_inc_refcnt(link);
228       evc_link_delete(link);
229       if(link->malloced) free(link);
230       else if(link->refcnt>0) link->refcnt--;
231     }
232   }
233 }
234  
235 /**
236  * evc_tx_hub_init - Initializes Event Transmition Hub
237  * @hub:        pointer to the &evc_tx_hub_t type hub
238  *
239  * Return Value: negative return value indicates failure.
240  */
241 int evc_tx_hub_init(evc_tx_hub_t *hub)
242 {
243   evc_tx_list_init_head(hub);
244   return 0;
245 }
246
247 /**
248  * evc_tx_hub_done - Finalize Event Transmition Hub
249  * @hub:        pointer to the &evc_tx_hub_t type hub
250  */
251 void evc_tx_hub_done(evc_tx_hub_t *hub)
252 {
253   evc_link_t *link;
254   ul_list_for_each_cut(evc_tx_list, hub, link){
255     evc_link_inc_refcnt(link);
256     link->src.hub=NULL;
257     evc_link_delete(link);
258     evc_link_dec_refcnt(link);
259   }
260 }
261
262 static inline
263 int evc_prop_link_skip(evc_link_t *link)
264 {
265   if(link->dead || link->blocked || link->delete_pend) return 1;
266   if(!link->recursive && link->taken) return 1;
267   return 0;
268 }
269
270 /**
271  * evc_tx_hub_propagate - Propagate Event to Links Destinations
272  * @hub:        pointer to the &evc_tx_hub_t type hub
273  * @args:       pointer to the variable arguments list
274  *
275  * The function propagates event to the connected links,
276  * it skips links marked as @dead, @blocked or @delete_pend.
277  * If the link is not marked as @recursive, it ensures, that
278  * link is not called twice.
279  */
280 void evc_tx_hub_propagate(evc_tx_hub_t *hub, va_list args)
281 {
282   evc_link_t *link, *next;
283   
284   link=evc_tx_list_first(hub);
285   while(1){
286     if(!link) return;
287     if(!evc_prop_link_skip(link)) break;
288     link=evc_tx_list_next(hub,link);
289   }
290   evc_link_inc_refcnt(link);    /*prevents dispose of the link*/
291   link->taken++;                /*prevents delete of the link from the hub*/
292   do{
293     va_list args_copy;
294     va_copy(args_copy, args);
295     link->propagate(link, args_copy);
296     va_end(args_copy);
297
298     if(link->src.hub == hub){   /*check for correct hub relation*/
299       next=link;
300       while(1){
301         next=evc_tx_list_next(hub,next);
302         if(!next) break;
303         if(!evc_prop_link_skip(next)) {
304           evc_link_inc_refcnt(next); /*prevents dispose of the link*/
305           next->taken++;        /*prevents delete of the link from the hub*/
306           break;
307         }
308       }
309     }else{
310       /* link is already disconnected from the hub, 
311          result of evc_tx_hub_done  */
312       next=NULL;
313     }
314     if(!(--link->taken)){
315       if(link->delete_pend)
316         evc_link_delete(link);  /*process pending delete*/
317     }
318     evc_link_dec_refcnt(link);  /*can lead to dispose of the link*/
319   }while((link=next));
320 }
321
322 /**
323  * evc_tx_hub_emit - Emits Event to Hub
324  * @hub:        pointer to the &evc_tx_hub_t type hub
325  *
326  * The function hands over arguments to evc_tx_hub_propagate()
327  * as &va_list.
328  */
329 void evc_tx_hub_emit(evc_tx_hub_t *hub, ...)
330 {
331   va_list args;
332
333   va_start (args, hub);
334   evc_tx_hub_propagate(hub, args);
335   va_end (args);
336 }
337
338 int evc_tx_hub_eol_weakptr(evc_tx_hub_t *hub, void **weakptr)
339 {
340   evc_link_t *link, *next;
341   int ret=0;
342   
343   link=evc_tx_list_first(hub);
344   while(link){
345     next=evc_tx_list_next(hub,link);
346     if(link->standalone && (link->dst.standalone.weakptr==weakptr)){
347       link->dst.standalone.weakptr=NULL;
348       evc_link_delete(link);
349       ret++;
350     }
351     link=next;
352   }
353   return ret;
354 }
355
356
357 /**
358  * evc_rx_hub_init - Initializes Event Receiption Hub
359  * @hub:        pointer to the &evc_rx_hub_t type hub
360  * @rx_fnc:     pointer to the function invoked by event reception
361  * @context:    context for the rx_fnc() function invocation
362  *
363  * Return Value: negative return value indicates failure.
364  */
365 int evc_rx_hub_init(evc_rx_hub_t *hub, evc_rx_fnc_t *rx_fnc, void *context)
366 {
367   evc_rx_list_init_head(hub);
368   hub->rx_fnc=rx_fnc;
369   hub->context=context;
370   return 0;
371 }
372
373 /**
374  * evc_rx_hub_disconnect_all - Disconnect Receiption Hub from All Sources
375  * @hub:        pointer to the &evc_rx_hub_t type hub
376  */
377 void evc_rx_hub_disconnect_all(evc_rx_hub_t *hub)
378 {
379   evc_link_t *link;
380   ul_list_for_each_cut(evc_rx_list, hub, link){
381     evc_link_inc_refcnt(link);
382     link->dst.multi.hub=NULL;
383     evc_link_delete(link);
384     evc_link_dec_refcnt(link);
385   }
386 }
387
388 /**
389  * evc_rx_hub_done - Finalize Event Receiption Hub
390  * @hub:        pointer to the &evc_rx_hub_t type hub
391  */
392 void evc_rx_hub_done(evc_rx_hub_t *hub)
393 {
394   evc_rx_hub_disconnect_all(hub);
395 }
396
397 /*===========================================================*/
398 /* arguments propagation functions */
399
400 typedef int evc_fnc_propagate_i_p_l(void *, long);
401
402 int evc_link_propagate_i_p_l(evc_link_t *link, va_list args)
403 {
404   void *context;
405   evc_fnc_propagate_i_p_l *fnc;
406   
407   if(link->dead){
408     if(link->standalone && link->dst.standalone.weakptr){
409       *link->dst.standalone.weakptr=NULL;
410       link->dst.standalone.weakptr=NULL;
411     }
412     return 0;
413   }
414   if(link->standalone){
415     fnc=(evc_fnc_propagate_i_p_l*)link->dst.standalone.rx_fnc;
416     context=link->dst.standalone.context;
417   }else{
418     if(!link->dst.multi.hub) return 0;
419     fnc=(evc_fnc_propagate_i_p_l*)link->dst.multi.hub->rx_fnc;
420     context=link->dst.multi.hub->context;
421   }
422   if(fnc)
423     fnc(context, va_arg(args, long));
424   return 0;
425 }
426