]> rtime.felk.cvut.cz Git - ulut.git/blob - ulut/ul_evcbase.c
Structured comment added to unique IDs pool code and some memory leak correction.
[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     link->propagate(link, args);
294
295     if(link->src.hub == hub){   /*check for correct hub relation*/
296       next=link;
297       while(1){
298         next=evc_tx_list_next(hub,next);
299         if(!next) break;
300         if(!evc_prop_link_skip(next)) {
301           evc_link_inc_refcnt(next); /*prevents dispose of the link*/
302           next->taken++;        /*prevents delete of the link from the hub*/
303           break;
304         }
305       }
306     }else{
307       /* link is already disconnected from the hub, 
308          result of evc_tx_hub_done  */
309       next=NULL;
310     }
311     if(!(--link->taken)){
312       if(link->delete_pend)
313         evc_link_delete(link);  /*process pending delete*/
314     }
315     evc_link_dec_refcnt(link);  /*can lead to dispose of the link*/
316   }while((link=next));
317 }
318
319 /**
320  * evc_tx_hub_emit - Emits Event to Hub
321  * @hub:        pointer to the &evc_tx_hub_t type hub
322  *
323  * The function hands over arguments to evc_tx_hub_propagate()
324  * as &va_list.
325  */
326 void evc_tx_hub_emit(evc_tx_hub_t *hub, ...)
327 {
328   va_list args;
329
330   va_start (args, hub);
331   evc_tx_hub_propagate(hub, args);
332   va_end (args);
333 }
334
335 int evc_tx_hub_eol_weakptr(evc_tx_hub_t *hub, void **weakptr)
336 {
337   evc_link_t *link, *next;
338   int ret=0;
339   
340   link=evc_tx_list_first(hub);
341   while(link){
342     next=evc_tx_list_next(hub,link);
343     if(link->standalone && (link->dst.standalone.weakptr==weakptr)){
344       link->dst.standalone.weakptr=NULL;
345       evc_link_delete(link);
346       ret++;
347     }
348     link=next;
349   }
350   return ret;
351 }
352
353
354 /**
355  * evc_rx_hub_init - Initializes Event Receiption Hub
356  * @hub:        pointer to the &evc_rx_hub_t type hub
357  * @rx_fnc:     pointer to the function invoked by event reception
358  * @context:    context for the rx_fnc() function invocation
359  *
360  * Return Value: negative return value indicates failure.
361  */
362 int evc_rx_hub_init(evc_rx_hub_t *hub, evc_rx_fnc_t *rx_fnc, void *context)
363 {
364   evc_rx_list_init_head(hub);
365   hub->rx_fnc=rx_fnc;
366   hub->context=context;
367   return 0;
368 }
369
370 /**
371  * evc_rx_hub_disconnect_all - Disconnect Receiption Hub from All Sources
372  * @hub:        pointer to the &evc_rx_hub_t type hub
373  */
374 void evc_rx_hub_disconnect_all(evc_rx_hub_t *hub)
375 {
376   evc_link_t *link;
377   ul_list_for_each_cut(evc_rx_list, hub, link){
378     evc_link_inc_refcnt(link);
379     link->dst.multi.hub=NULL;
380     evc_link_delete(link);
381     evc_link_dec_refcnt(link);
382   }
383 }
384
385 /**
386  * evc_rx_hub_done - Finalize Event Receiption Hub
387  * @hub:        pointer to the &evc_rx_hub_t type hub
388  */
389 void evc_rx_hub_done(evc_rx_hub_t *hub)
390 {
391   evc_rx_hub_disconnect_all(hub);
392 }
393
394 /*===========================================================*/
395 /* arguments propagation functions */
396
397 typedef int evc_fnc_propagate_i_p_l(void *, long);
398
399 int evc_link_propagate_i_p_l(evc_link_t *link, va_list args)
400 {
401   void *context;
402   evc_fnc_propagate_i_p_l *fnc;
403   
404   if(link->dead){
405     if(link->standalone && link->dst.standalone.weakptr){
406       *link->dst.standalone.weakptr=NULL;
407       link->dst.standalone.weakptr=NULL;
408     }
409     return 0;
410   }
411   if(link->standalone){
412     fnc=(evc_fnc_propagate_i_p_l*)link->dst.standalone.rx_fnc;
413     context=link->dst.standalone.context;
414   }else{
415     if(!link->dst.multi.hub) return 0;
416     fnc=(evc_fnc_propagate_i_p_l*)link->dst.multi.hub->rx_fnc;
417     context=link->dst.multi.hub->context;
418   }
419   if(fnc)
420     fnc(context, va_arg(args, long));
421   return 0;
422 }
423