]> rtime.felk.cvut.cz Git - ulut.git/blob - ulut/ul_evcbase.c
231da148d6f8fde3732b1c162907824c58115d30
[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  *
125  * Link reference count is set to 1 by this function
126  * Return Value: pointer to the new link or %NULL.
127  */
128 evc_link_t *evc_link_new_standalone(evc_rx_fnc_t *rx_fnc, void *context)
129 {
130   evc_link_t *link;
131   
132   link=malloc(sizeof(evc_link_t));
133   if(link==NULL) return NULL;
134
135   evc_link_init_standalone(link, rx_fnc, context);
136   link->malloced=1;
137   return link;
138 }
139
140 /**
141  * evc_link_connect_standalone - Connects Standalone Link to Source Hubs
142  * @link:       pointer to the non-connected initialized link
143  * @src:        pointer to the source hub of type &evc_tx_hub_t
144  * @prop:       propagation function corresponding to hub source
145  *              and standalone rx_fnc() expected event arguments
146  *
147  * If ready flag is not set, link state is set to ready
148  * and reference count is increased.
149  * Return Value: negative return value indicates failure.
150  */
151 int evc_link_connect_standalone(evc_link_t *link, evc_tx_hub_t *src,
152            evc_prop_fnc_t *prop)
153 {
154   int link_ready;
155
156   if(!link || !src || !prop) return -1;
157   if(!link->standalone) return -1;
158   evc_link_inc_refcnt(link);
159   link->delete_pend=0;
160   link->propagate=prop;
161   link->src.hub=src;
162   evc_tx_list_insert(src,link);
163   link_ready=link->ready;
164   link->ready=1;
165   if(link_ready){
166     evc_link_dec_refcnt(link);
167   }
168
169   return 0;
170 }
171
172
173 static inline
174 void evc_link_do_delete(evc_link_t *link)
175 {
176   evc_tx_list_del_item(link);
177   link->src.hub=NULL;
178   if(!link->standalone){
179     evc_rx_list_del_item(link);
180     link->dst.multi.hub=NULL;
181   }
182   link->delete_pend=0;
183 }
184
185
186 /**
187  * evc_link_delete - Deletes Link from Hubs Lists
188  * @link:       pointer to the possibly connected initialized link
189  *
190  * If ready flag is set, link ready flag is cleared and reference count
191  * is decreased. This could lead to link disappear, if nobody is holding
192  * reference.
193  * Return Value: positive return value indicates immediate delete,
194  *              zero return value informs about delayed delete.
195  */
196 int evc_link_delete(evc_link_t *link)
197 {
198   int res;
199   link->delete_pend=1;
200   if(!link->taken){
201     evc_link_do_delete(link);
202     res=1;
203   } else {
204     res=0;
205   }
206   if(link->ready){
207     link->ready=0;
208     evc_link_dec_refcnt(link);
209   }
210   return res;
211 }
212
213 /**
214  * evc_link_dispose - Disposes Link
215  * @link:       pointer to the possibly connected initialized link
216  *
217  * Deletes link from hubs, marks it as dead, calls final death propagate()
218  * for the link and if link is @malloced, releases link occupied memory.
219  */
220 void evc_link_dispose(evc_link_t *link)
221 {
222   if(!link->dead){
223     link->dead=1;
224     if(!link->propagate(link,0)){
225       evc_link_inc_refcnt(link);
226       evc_link_delete(link);
227       if(link->malloced) free(link);
228       else if(link->refcnt>0) link->refcnt--;
229     }
230   }
231 }
232  
233 /**
234  * evc_tx_hub_init - Initializes Event Transmition Hub
235  * @hub:        pointer to the &evc_tx_hub_t type hub
236  *
237  * Return Value: negative return value indicates failure.
238  */
239 int evc_tx_hub_init(evc_tx_hub_t *hub)
240 {
241   evc_tx_list_init_head(hub);
242   return 0;
243 }
244
245 /**
246  * evc_tx_hub_done - Initializes Event Transmition Hub
247  * @hub:        pointer to the &evc_tx_hub_t type hub
248  */
249 void evc_tx_hub_done(evc_tx_hub_t *hub)
250 {
251   evc_link_t *link;
252   ul_list_for_each_cut(evc_tx_list, hub, link){
253     evc_link_inc_refcnt(link);
254     link->src.hub=NULL;
255     evc_link_delete(link);
256     evc_link_dec_refcnt(link);
257   }
258 }
259
260 static inline
261 int evc_prop_link_skip(evc_link_t *link)
262 {
263   if(link->dead || link->blocked || link->delete_pend) return 1;
264   if(!link->recursive && link->taken) return 1;
265   return 0;
266 }
267
268 /**
269  * evc_tx_hub_propagate - Propagate Event to Links Destinations
270  * @hub:        pointer to the &evc_tx_hub_t type hub
271  * @args:       pointer to the variable arguments list
272  *
273  * The function propagates event to the connected links,
274  * it skips links marked as @dead, @blocked or @delete_pend.
275  * If the link is not marked as @recursive, it ensures, that
276  * link is not called twice.
277  */
278 void evc_tx_hub_propagate(evc_tx_hub_t *hub, va_list args)
279 {
280   evc_link_t *link, *next;
281   
282   link=evc_tx_list_first(hub);
283   while(1){
284     if(!link) return;
285     if(!evc_prop_link_skip(link)) break;
286     link=evc_tx_list_next(hub,link);
287   }
288   evc_link_inc_refcnt(link);    /*prevents dispose of the link*/
289   link->taken++;                /*prevents delete of the link from the hub*/
290   do{
291     link->propagate(link, args);
292
293     if(link->src.hub == hub){   /*check for correct hub relation*/
294       next=link;
295       while(1){
296         next=evc_tx_list_next(hub,next);
297         if(!next) break;
298         if(!evc_prop_link_skip(next)) {
299           evc_link_inc_refcnt(next); /*prevents dispose of the link*/
300           next->taken++;        /*prevents delete of the link from the hub*/
301           break;
302         }
303       }
304     }else{
305       /* link is already disconnected from the hub, 
306          result of evc_tx_hub_done  */
307       next=NULL;
308     }
309     if(!(--link->taken)){
310       if(link->delete_pend)
311         evc_link_delete(link);  /*process pending delete*/
312     }
313     evc_link_dec_refcnt(link);  /*can lead to dispose of the link*/
314   }while((link=next));
315 }
316
317 /**
318  * evc_tx_hub_emit - Emits Event to Hub
319  * @hub:        pointer to the &evc_tx_hub_t type hub
320  *
321  * The function hands over arguments to evc_tx_hub_propagate()
322  * as &va_list.
323  */
324 void evc_tx_hub_emit(evc_tx_hub_t *hub, ...)
325 {
326   va_list args;
327
328   va_start (args, hub);
329   evc_tx_hub_propagate(hub, args);
330   va_end (args);
331 }
332
333 int evc_tx_hub_eol_weakptr(evc_tx_hub_t *hub, void **weakptr)
334 {
335   evc_link_t *link, *next;
336   int ret=0;
337   
338   link=evc_tx_list_first(hub);
339   while(link){
340     next=evc_tx_list_next(hub,link);
341     if(link->standalone && (link->dst.standalone.weakptr==weakptr)){
342       link->dst.standalone.weakptr=NULL;
343       evc_link_delete(link);
344       ret++;
345     }
346     link=next;
347   }
348   return ret;
349 }
350
351
352 /**
353  * evc_rx_hub_init - Initializes Event Receiption Hub
354  * @hub:        pointer to the &evc_rx_hub_t type hub
355  * @rx_fnc:     pointer to the function invoked by event reception
356  * @context:    context for the rx_fnc() function invocation
357  *
358  * Return Value: negative return value indicates failure.
359  */
360 int evc_rx_hub_init(evc_rx_hub_t *hub, evc_rx_fnc_t *rx_fnc, void *context)
361 {
362   evc_rx_list_init_head(hub);
363   hub->rx_fnc=rx_fnc;
364   hub->context=context;
365   return 0;
366 }
367
368 /**
369  * evc_rx_hub_done - Finalize Event Receiption Hub
370  * @hub:        pointer to the &evc_rx_hub_t type hub
371  */
372 void evc_rx_hub_done(evc_rx_hub_t *hub)
373 {
374   evc_link_t *link;
375   ul_list_for_each_cut(evc_rx_list, hub, link){
376     evc_link_inc_refcnt(link);
377     link->dst.multi.hub=NULL;
378     evc_link_delete(link);
379     evc_link_dec_refcnt(link);
380   }
381 }
382
383 /*===========================================================*/
384 /* arguments propagation functions */
385
386 typedef int evc_fnc_propagate_i_p_l(void *, long);
387
388 int evc_link_propagate_i_p_l(evc_link_t *link, va_list args)
389 {
390   void *context;
391   evc_fnc_propagate_i_p_l *fnc;
392   
393   if(link->dead){
394     if(link->standalone && link->dst.standalone.weakptr){
395       *link->dst.standalone.weakptr=NULL;
396       link->dst.standalone.weakptr=NULL;
397     }
398     return 0;
399   }
400   if(link->standalone){
401     fnc=(evc_fnc_propagate_i_p_l*)link->dst.standalone.rx_fnc;
402     context=link->dst.standalone.context;
403   }else{
404     if(!link->dst.multi.hub) return 0;
405     fnc=(evc_fnc_propagate_i_p_l*)link->dst.multi.hub->rx_fnc;
406     context=link->dst.multi.hub->context;
407   }
408   if(fnc)
409     fnc(context, va_arg(args, long));
410   return 0;
411 }
412