]> rtime.felk.cvut.cz Git - ulut.git/blob - ulut/ul_evcbase.c
Fix compilation on GCC 4.7 for ARM ABI.
[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 /* Local function to make initialization of empty va_list portable */
216 static inline
217 int evc_link_propagate_dead(evc_link_t *link, ...)
218 {
219   va_list no_args;
220   int res;
221
222   va_start(no_args, link);
223   res=link->propagate(link,no_args);
224   va_end(no_args);
225   return res;
226 }
227
228 /**
229  * evc_link_dispose - Disposes Link
230  * @link:       pointer to the possibly connected initialized link
231  *
232  * Deletes link from hubs, marks it as dead, calls final death propagate()
233  * for the link and if link is @malloced, releases link occupied memory.
234  */
235 void evc_link_dispose(evc_link_t *link)
236 {
237   if(!link->dead){
238     link->dead=1;
239     if(!evc_link_propagate_dead(link)) {
240       evc_link_inc_refcnt(link);
241       evc_link_delete(link);
242       if(link->malloced) free(link);
243       else if(link->refcnt>0) link->refcnt--;
244     }
245   }
246 }
247  
248 /**
249  * evc_tx_hub_init - Initializes Event Transmition Hub
250  * @hub:        pointer to the &evc_tx_hub_t type hub
251  *
252  * Return Value: negative return value indicates failure.
253  */
254 int evc_tx_hub_init(evc_tx_hub_t *hub)
255 {
256   evc_tx_list_init_head(hub);
257   return 0;
258 }
259
260 /**
261  * evc_tx_hub_done - Finalize Event Transmition Hub
262  * @hub:        pointer to the &evc_tx_hub_t type hub
263  */
264 void evc_tx_hub_done(evc_tx_hub_t *hub)
265 {
266   evc_link_t *link;
267   ul_list_for_each_cut(evc_tx_list, hub, link){
268     evc_link_inc_refcnt(link);
269     link->src.hub=NULL;
270     evc_link_delete(link);
271     evc_link_dec_refcnt(link);
272   }
273 }
274
275 static inline
276 int evc_prop_link_skip(evc_link_t *link)
277 {
278   if(link->dead || link->blocked || link->delete_pend) return 1;
279   if(!link->recursive && link->taken) return 1;
280   return 0;
281 }
282
283 /**
284  * evc_tx_hub_propagate - Propagate Event to Links Destinations
285  * @hub:        pointer to the &evc_tx_hub_t type hub
286  * @args:       pointer to the variable arguments list
287  *
288  * The function propagates event to the connected links,
289  * it skips links marked as @dead, @blocked or @delete_pend.
290  * If the link is not marked as @recursive, it ensures, that
291  * link is not called twice.
292  */
293 void evc_tx_hub_propagate(evc_tx_hub_t *hub, va_list args)
294 {
295   evc_link_t *link, *next;
296   
297   link=evc_tx_list_first(hub);
298   while(1){
299     if(!link) return;
300     if(!evc_prop_link_skip(link)) break;
301     link=evc_tx_list_next(hub,link);
302   }
303   evc_link_inc_refcnt(link);    /*prevents dispose of the link*/
304   link->taken++;                /*prevents delete of the link from the hub*/
305   do{
306     va_list args_copy;
307     va_copy(args_copy, args);
308     link->propagate(link, args_copy);
309     va_end(args_copy);
310
311     if(link->src.hub == hub){   /*check for correct hub relation*/
312       next=link;
313       while(1){
314         next=evc_tx_list_next(hub,next);
315         if(!next) break;
316         if(!evc_prop_link_skip(next)) {
317           evc_link_inc_refcnt(next); /*prevents dispose of the link*/
318           next->taken++;        /*prevents delete of the link from the hub*/
319           break;
320         }
321       }
322     }else{
323       /* link is already disconnected from the hub, 
324          result of evc_tx_hub_done  */
325       next=NULL;
326     }
327     if(!(--link->taken)){
328       if(link->delete_pend)
329         evc_link_delete(link);  /*process pending delete*/
330     }
331     evc_link_dec_refcnt(link);  /*can lead to dispose of the link*/
332   }while((link=next));
333 }
334
335 /**
336  * evc_tx_hub_emit - Emits Event to Hub
337  * @hub:        pointer to the &evc_tx_hub_t type hub
338  *
339  * The function hands over arguments to evc_tx_hub_propagate()
340  * as &va_list.
341  */
342 void evc_tx_hub_emit(evc_tx_hub_t *hub, ...)
343 {
344   va_list args;
345
346   va_start (args, hub);
347   evc_tx_hub_propagate(hub, args);
348   va_end (args);
349 }
350
351 int evc_tx_hub_eol_weakptr(evc_tx_hub_t *hub, void **weakptr)
352 {
353   evc_link_t *link, *next;
354   int ret=0;
355   
356   link=evc_tx_list_first(hub);
357   while(link){
358     next=evc_tx_list_next(hub,link);
359     if(link->standalone && (link->dst.standalone.weakptr==weakptr)){
360       link->dst.standalone.weakptr=NULL;
361       evc_link_delete(link);
362       ret++;
363     }
364     link=next;
365   }
366   return ret;
367 }
368
369
370 /**
371  * evc_rx_hub_init - Initializes Event Receiption Hub
372  * @hub:        pointer to the &evc_rx_hub_t type hub
373  * @rx_fnc:     pointer to the function invoked by event reception
374  * @context:    context for the rx_fnc() function invocation
375  *
376  * Return Value: negative return value indicates failure.
377  */
378 int evc_rx_hub_init(evc_rx_hub_t *hub, evc_rx_fnc_t *rx_fnc, void *context)
379 {
380   evc_rx_list_init_head(hub);
381   hub->rx_fnc=rx_fnc;
382   hub->context=context;
383   return 0;
384 }
385
386 /**
387  * evc_rx_hub_disconnect_all - Disconnect Receiption Hub from All Sources
388  * @hub:        pointer to the &evc_rx_hub_t type hub
389  */
390 void evc_rx_hub_disconnect_all(evc_rx_hub_t *hub)
391 {
392   evc_link_t *link;
393   ul_list_for_each_cut(evc_rx_list, hub, link){
394     evc_link_inc_refcnt(link);
395     link->dst.multi.hub=NULL;
396     evc_link_delete(link);
397     evc_link_dec_refcnt(link);
398   }
399 }
400
401 /**
402  * evc_rx_hub_done - Finalize Event Receiption Hub
403  * @hub:        pointer to the &evc_rx_hub_t type hub
404  */
405 void evc_rx_hub_done(evc_rx_hub_t *hub)
406 {
407   evc_rx_hub_disconnect_all(hub);
408 }
409
410 /*===========================================================*/
411 /* arguments propagation functions */
412
413 typedef int evc_fnc_propagate_i_p_l(void *, long);
414
415 int evc_link_propagate_i_p_l(evc_link_t *link, va_list args)
416 {
417   void *context;
418   evc_fnc_propagate_i_p_l *fnc;
419   
420   if(link->dead){
421     if(link->standalone && link->dst.standalone.weakptr){
422       *link->dst.standalone.weakptr=NULL;
423       link->dst.standalone.weakptr=NULL;
424     }
425     return 0;
426   }
427   if(link->standalone){
428     fnc=(evc_fnc_propagate_i_p_l*)link->dst.standalone.rx_fnc;
429     context=link->dst.standalone.context;
430   }else{
431     if(!link->dst.multi.hub) return 0;
432     fnc=(evc_fnc_propagate_i_p_l*)link->dst.multi.hub->rx_fnc;
433     context=link->dst.multi.hub->context;
434   }
435   if(fnc)
436     fnc(context, va_arg(args, long));
437   return 0;
438 }
439