1 /*******************************************************************
2 uLan Utilities Library - C library of basic reusable constructions
4 ul_evcbase.c - event connectors
6 (C) Copyright 2001-2003 by Pavel Pisa - Originator
8 The uLan utilities library can be used, copied and modified under
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.
20 See files COPYING and README for details.
22 *******************************************************************/
26 #include "ul_utmalloc.h"
28 #include "ul_evcbase.h"
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)
34 * evc_link_init - Initialize Event Connector Link
35 * @link: pointer to the link
37 * Link reference count is set to 1 by this function
38 * Return Value: negative value informs about failure.
40 int evc_link_init(evc_link_t *link)
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);
50 * evc_link_new - Allocates New Event Connector Link
52 * Link reference count is set to 1 by this function
53 * Return Value: pointer to the new link or %NULL.
55 evc_link_t *evc_link_new(void)
59 link=malloc(sizeof(evc_link_t));
60 if(link==NULL) return NULL;
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
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.
79 int evc_link_connect(evc_link_t *link, evc_tx_hub_t *src, evc_rx_hub_t *dst,
84 if(!link || !src || !dst || !prop) return -1;
85 if(link->standalone) return -1;
86 evc_link_inc_refcnt(link);
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;
96 evc_link_dec_refcnt(link);
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
108 * Link reference count is set to 1 by this function
109 * Return Value: negative value informs about failure.
111 int evc_link_init_standalone(evc_link_t *link, evc_rx_fnc_t *rx_fnc, void *context)
113 memset(link,0,sizeof(evc_link_t));
114 evc_rx_list_init_detached(link);
116 link->dst.standalone.rx_fnc=rx_fnc;
117 link->dst.standalone.context=context;
118 evc_link_inc_refcnt(link);
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
127 * Link reference count is set to 1 by this function
128 * Return Value: pointer to the new link or %NULL.
130 evc_link_t *evc_link_new_standalone(evc_rx_fnc_t *rx_fnc, void *context)
134 link=malloc(sizeof(evc_link_t));
135 if(link==NULL) return NULL;
137 evc_link_init_standalone(link, rx_fnc, context);
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
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.
153 int evc_link_connect_standalone(evc_link_t *link, evc_tx_hub_t *src,
154 evc_prop_fnc_t *prop)
158 if(!link || !src || !prop) return -1;
159 if(!link->standalone) return -1;
160 evc_link_inc_refcnt(link);
162 link->propagate=prop;
164 evc_tx_list_insert(src,link);
165 link_ready=link->ready;
168 evc_link_dec_refcnt(link);
176 void evc_link_do_delete(evc_link_t *link)
178 evc_tx_list_del_item(link);
180 if(!link->standalone){
181 evc_rx_list_del_item(link);
182 link->dst.multi.hub=NULL;
189 * evc_link_delete - Deletes Link from Hubs Lists
190 * @link: pointer to the possibly connected initialized link
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
195 * Return Value: positive return value indicates immediate delete,
196 * zero return value informs about delayed delete.
198 int evc_link_delete(evc_link_t *link)
203 evc_link_do_delete(link);
210 evc_link_dec_refcnt(link);
215 /* Local function to make initialization of empty va_list portable */
217 int evc_link_propagate_dead(evc_link_t *link, ...)
222 va_start(no_args, link);
223 res=link->propagate(link,no_args);
229 * evc_link_dispose - Disposes Link
230 * @link: pointer to the possibly connected initialized link
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.
235 void evc_link_dispose(evc_link_t *link)
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--;
249 * evc_tx_hub_init - Initializes Event Transmition Hub
250 * @hub: pointer to the &evc_tx_hub_t type hub
252 * Return Value: negative return value indicates failure.
254 int evc_tx_hub_init(evc_tx_hub_t *hub)
256 evc_tx_list_init_head(hub);
261 * evc_tx_hub_done - Finalize Event Transmition Hub
262 * @hub: pointer to the &evc_tx_hub_t type hub
264 void evc_tx_hub_done(evc_tx_hub_t *hub)
267 ul_list_for_each_cut(evc_tx_list, hub, link){
268 evc_link_inc_refcnt(link);
270 evc_link_delete(link);
271 evc_link_dec_refcnt(link);
276 int evc_prop_link_skip(evc_link_t *link)
278 if(link->dead || link->blocked || link->delete_pend) return 1;
279 if(!link->recursive && link->taken) return 1;
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
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.
293 void evc_tx_hub_propagate(evc_tx_hub_t *hub, va_list args)
295 evc_link_t *link, *next;
297 link=evc_tx_list_first(hub);
300 if(!evc_prop_link_skip(link)) break;
301 link=evc_tx_list_next(hub,link);
303 evc_link_inc_refcnt(link); /*prevents dispose of the link*/
304 link->taken++; /*prevents delete of the link from the hub*/
307 va_copy(args_copy, args);
308 link->propagate(link, args_copy);
311 if(link->src.hub == hub){ /*check for correct hub relation*/
314 next=evc_tx_list_next(hub,next);
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*/
323 /* link is already disconnected from the hub,
324 result of evc_tx_hub_done */
327 if(!(--link->taken)){
328 if(link->delete_pend)
329 evc_link_delete(link); /*process pending delete*/
331 evc_link_dec_refcnt(link); /*can lead to dispose of the link*/
336 * evc_tx_hub_emit - Emits Event to Hub
337 * @hub: pointer to the &evc_tx_hub_t type hub
339 * The function hands over arguments to evc_tx_hub_propagate()
342 void evc_tx_hub_emit(evc_tx_hub_t *hub, ...)
346 va_start (args, hub);
347 evc_tx_hub_propagate(hub, args);
351 int evc_tx_hub_eol_weakptr(evc_tx_hub_t *hub, void **weakptr)
353 evc_link_t *link, *next;
356 link=evc_tx_list_first(hub);
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);
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
376 * Return Value: negative return value indicates failure.
378 int evc_rx_hub_init(evc_rx_hub_t *hub, evc_rx_fnc_t *rx_fnc, void *context)
380 evc_rx_list_init_head(hub);
382 hub->context=context;
387 * evc_rx_hub_disconnect_all - Disconnect Receiption Hub from All Sources
388 * @hub: pointer to the &evc_rx_hub_t type hub
390 void evc_rx_hub_disconnect_all(evc_rx_hub_t *hub)
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);
402 * evc_rx_hub_done - Finalize Event Receiption Hub
403 * @hub: pointer to the &evc_rx_hub_t type hub
405 void evc_rx_hub_done(evc_rx_hub_t *hub)
407 evc_rx_hub_disconnect_all(hub);
410 /*===========================================================*/
411 /* arguments propagation functions */
413 typedef int evc_fnc_propagate_i_p_l(void *, long);
415 int evc_link_propagate_i_p_l(evc_link_t *link, va_list args)
418 evc_fnc_propagate_i_p_l *fnc;
421 if(link->standalone && link->dst.standalone.weakptr){
422 *link->dst.standalone.weakptr=NULL;
423 link->dst.standalone.weakptr=NULL;
427 if(link->standalone){
428 fnc=(evc_fnc_propagate_i_p_l*)link->dst.standalone.rx_fnc;
429 context=link->dst.standalone.context;
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;
436 fnc(context, va_arg(args, long));