2 * Implementation of event notification component.
4 * Copyright (C) 2013, Broadcom Corporation
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
8 * the contents of this file may not be disclosed to third parties, copied
9 * or duplicated in any form, in whole or in part, without the prior
10 * written permission of Broadcom Corporation.
19 #include "bcm_notif_priv.h"
20 #include <bcm_notif_pub.h>
21 #include <bcm_mpool_pub.h>
24 #if defined(BCMDBG) || defined(BCMDBG_ERR)
25 #define NOTIF_ERROR(args) printf args
27 #define NOTIF_ERROR(args)
31 static void dealloc_module(bcm_notif_module_t
*notif_module
);
37 * Notifier module attach-time initialization.
40 * osh Operating system handle.
41 * mpm Memory pool manager handle.
42 * max_notif_servers Maximum number of supported servers.
43 * max_notif_clients Maximum number of supported clients.
45 * Global notifier module object. NULL on error.
47 bcm_notif_module_t
* BCMATTACHFN(bcm_notif_attach
)(osl_t
*osh
,
49 int max_notif_servers
,
50 int max_notif_clients
)
52 bcm_notif_module_t
*notif_module
;
55 /* Allocate global notifier module state. */
56 if ((notif_module
= MALLOC(osh
, sizeof(*notif_module
))) == NULL
) {
57 NOTIF_ERROR(("%s: out of mem, malloced %d bytes\n",
58 __FUNCTION__
, MALLOCED(osh
)));
62 /* Init global notifier module state. */
63 memset(notif_module
, 0, sizeof(*notif_module
));
64 notif_module
->osh
= osh
;
65 notif_module
->mpm
= mpm
;
67 /* Create memory pool for server objects. */
68 ret
= bcm_mpm_create_prealloc_pool(mpm
,
69 sizeof(struct bcm_notif_list_struct
),
70 max_notif_servers
, NULL
, 0,
71 "notif_s", ¬if_module
->server_mem_pool
);
76 /* Create memory pool for client objects. */
77 ret
= bcm_mpm_create_prealloc_pool(mpm
,
78 sizeof(struct bcm_notif_client_request
),
79 max_notif_clients
, NULL
, 0,
80 "notif_c", ¬if_module
->client_mem_pool
);
87 return (notif_module
);
90 dealloc_module(notif_module
);
98 * Notifier module detach-time deinitialization.
101 * notif_module Global notifier module object.
105 void BCMATTACHFN(bcm_notif_detach
)(bcm_notif_module_t
*notif_module
)
107 dealloc_module(notif_module
);
114 * Helper function to perform common resource deallocation.
117 * notif_module Global notifier module object.
121 static void BCMATTACHFN(dealloc_module
)(bcm_notif_module_t
*notif_module
)
123 if (notif_module
!= NULL
) {
125 if (notif_module
->client_mem_pool
!= NULL
) {
126 bcm_mpm_delete_prealloc_pool(notif_module
->mpm
,
127 ¬if_module
->client_mem_pool
);
130 if (notif_module
->server_mem_pool
!= NULL
) {
131 bcm_mpm_delete_prealloc_pool(notif_module
->mpm
,
132 ¬if_module
->server_mem_pool
);
135 MFREE(notif_module
->osh
, notif_module
, sizeof(*notif_module
));
141 * bcm_notif_create_list()
143 * Initialize new list. Allocates memory.
146 * notif_module Global notifier module object.
147 * hdlp Pointer to opaque list handle.
149 * BCME_OK Object initialized successfully. May be used.
150 * BCME_NOMEM Initialization failed due to no memory. Object must not be used
152 int BCMATTACHFN(bcm_notif_create_list
)(bcm_notif_module_t
*notif_module
, bcm_notif_h
*hdlp
)
154 int result
= BCME_OK
;
156 if ((*hdlp
= bcm_mp_alloc(notif_module
->server_mem_pool
)) == NULL
) {
160 memset(*hdlp
, 0, sizeof(**hdlp
));
161 (*hdlp
)->allow_list_operations
= TRUE
;
162 (*hdlp
)->notif_module
= notif_module
;
169 * bcm_notif_add_interest()
171 * Add an interested client
174 * hdl Opaque list handle.
175 * callback Client callback routine
176 * passthru Client pass-thru data
178 * BCME_OK Client interest added successfully
179 * BCME_NOMEM Add failed due to no memory.
182 int bcm_notif_add_interest(bcm_notif_h hdl
,
183 bcm_notif_client_callback callback
,
184 bcm_notif_client_data passthru
)
186 int result
= BCME_OK
;
187 struct bcm_notif_client_request
*new_node
= NULL
;
188 bcm_notif_module_t
*notif_module
= hdl
->notif_module
;
191 /* Ensure that list operations are not performed within client callbacks. */
192 if (!(hdl
->allow_list_operations
))
196 /* Allocate a new node for the new client interest request */
197 if ((new_node
= bcm_mp_alloc(notif_module
->client_mem_pool
)) == NULL
) {
201 memset(new_node
, 0, sizeof(*new_node
));
203 /* Initialize the new node with the client's information */
204 new_node
->callback
= callback
;
205 new_node
->passthru
= passthru
;
206 /* Insert it at the tail of the linked list */
207 if (hdl
->tail
== NULL
) {
208 /* This is now the first node in the list. */
209 new_node
->next
= new_node
;
210 hdl
->tail
= new_node
;
213 /* This is not the first node in the list. */
214 /* Insert as new tail in circular list. */
215 new_node
->next
= hdl
->tail
->next
;
216 hdl
->tail
->next
= new_node
;
217 hdl
->tail
= new_node
;
225 * bcm_notif_remove_interest()
227 * Remove an interested client. The callback and passthru must be identical to the data
228 * supplied during registration.
231 * hdl Opaque list handle.
232 * callback Client callback routine
233 * passthru Client pass-thru data
235 * BCME_OK Client interest added successfully
236 * BCME_NOTFOUND Could not locate this specific client registration for removal.
239 int bcm_notif_remove_interest(bcm_notif_h hdl
,
240 bcm_notif_client_callback callback
,
241 bcm_notif_client_data passthru
)
243 int result
= BCME_NOTFOUND
;
244 struct bcm_notif_client_request
* nodep
= hdl
->tail
;
245 bcm_notif_module_t
*notif_module
= hdl
->notif_module
;
247 /* Ensure that list operations are not performed within client callbacks. */
248 if (!(hdl
->allow_list_operations
))
252 if (nodep
&& nodep
== nodep
->next
) {
254 * Special case: list with just one node.
255 * If we get a hit, the list becomes empty because we delete the last node.
257 if (nodep
->callback
== callback
&& nodep
->passthru
== passthru
) {
258 bcm_mp_free(notif_module
->client_mem_pool
, nodep
);
264 * List with 0 or 2+ elements.
266 struct bcm_notif_client_request
* prevp
;
270 if (nodep
->callback
== callback
&& nodep
->passthru
== passthru
) {
272 * If we got a hit at the tail of the list, need to adjust
273 * the main list "tail" pointer.
275 if (hdl
->tail
== nodep
)
278 prevp
->next
= nodep
->next
;
279 bcm_mp_free(notif_module
->client_mem_pool
, nodep
);
280 /* Setting nodep to be 0 breaks us out of the loop. */
292 * Notify all clients on an event list that the event has occured. Invoke their
293 * callbacks and provide both the server data and the client passthru data.
296 * hdl Opaque list handle.
297 * server_data Server data for the notification
299 * BCME_OK Client interest added successfully
300 * BCME_ERROR General error
302 int bcm_notif_signal(bcm_notif_h hdl
, bcm_notif_server_data data
)
304 int result
= BCME_OK
;
305 struct bcm_notif_client_request
* nodep
= hdl
->tail
;
307 /* Ensure that list operations are not performed within client callbacks. */
308 if (!(hdl
->allow_list_operations
))
313 struct bcm_notif_client_request
* firstp
;
317 /* Mark list to prevent against list operations within client callbacks. */
318 hdl
->allow_list_operations
= FALSE
;
321 /* Signal the current client */
322 nodep
->callback(nodep
->passthru
, data
);
323 /* Advance to next client registration */
325 } while (nodep
!= firstp
);
327 /* Done client callbacks - allow list operations again. */
328 hdl
->allow_list_operations
= TRUE
;
335 * bcm_notif_delete_list()
337 * Remove all the nodes and the list itself.
340 * hdlp Pointer to opaque list handle.
342 * BCME_OK Event list successfully deleted.
343 * BCME_ERROR General error
345 int BCMATTACHFN(bcm_notif_delete_list
)(bcm_notif_h
*hdl
)
347 /* First free all the nodes. */
348 struct bcm_notif_client_request
* nodep
= (*hdl
)->tail
;
349 struct bcm_notif_client_request
* prevp
;
350 bcm_notif_module_t
*notif_module
= (*hdl
)->notif_module
;
352 /* Ensure that list operations are not performed within client callbacks. */
353 if (!((*hdl
)->allow_list_operations
))
361 if (prevp
== nodep
) {
362 /* Deleting the last node. Special case. */
363 bcm_mp_free(notif_module
->client_mem_pool
, nodep
);
364 nodep
= prevp
= NULL
;
366 prevp
->next
= nodep
->next
;
367 bcm_mp_free(notif_module
->client_mem_pool
, nodep
);
372 /* Free the list itself in addition to the nodes. */
373 memset(*hdl
, 0, sizeof(**hdl
));
374 bcm_mp_free(notif_module
->server_mem_pool
, *hdl
);
381 * bcm_notif_dump_list()
383 * For debugging, display interest list
386 * hdl Opaque list handle.
389 * BCME_OK Event list successfully dumped.
390 * BCME_ERROR General error.
392 int bcm_notif_dump_list(bcm_notif_h hdl
, struct bcmstrbuf
*b
)
395 struct bcm_notif_client_request
* nodep
;
398 bcm_bprintf(b
, "<uninit list>\n");
402 bcm_bprintf(b
, "List id=0x%p: ", hdl
);
405 bcm_bprintf(b
, "(empty)");
407 /* List is not empty. Display all data in correct sequence. */
408 struct bcm_notif_client_request
* firstp
= hdl
->tail
->next
;
411 bcm_bprintf(b
, " [0x%p,0x%p]", nodep
->callback
,
414 } while (nodep
!= firstp
);
418 bcm_bprintf(b
, "\n");