1 /*
2  * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef PUBSUB_H
8 #define PUBSUB_H
9 
10 #ifdef __LINKER__
11 
12 /* For the linker ... */
13 #define __pubsub_start_sym(event)	__pubsub_##event##_start
14 #define __pubsub_end_sym(event)		__pubsub_##event##_end
15 #define __pubsub_section(event)		.__pubsub_##event
16 
17 /*
18  * REGISTER_PUBSUB_EVENT has a different definition between linker and compiler
19  * contexts. In linker context, this collects pubsub sections for each event,
20  * placing guard symbols around each.
21  */
22 #if defined(USE_ARM_LINK)
23 #define REGISTER_PUBSUB_EVENT(event) \
24 	__pubsub_start_sym(event) +0 FIXED \
25 	{ \
26 		*(__pubsub_section(event)) \
27 	} \
28 	__pubsub_end_sym(event) +0 FIXED EMPTY 0 \
29 	{ \
30 		/* placeholder */ \
31 	}
32 #else
33 #define REGISTER_PUBSUB_EVENT(event) \
34 	__pubsub_start_sym(event) = .; \
35 	KEEP(*(__pubsub_section(event))); \
36 	__pubsub_end_sym(event) = .
37 #endif
38 
39 #else /* __LINKER__ */
40 
41 /* For the compiler ... */
42 
43 #include <assert.h>
44 #include <cdefs.h>
45 #include <stddef.h>
46 
47 #include <arch_helpers.h>
48 
49 #if defined(USE_ARM_LINK)
50 #define __pubsub_start_sym(event)	Load$$__pubsub_##event##_start$$Base
51 #define __pubsub_end_sym(event)		Load$$__pubsub_##event##_end$$Base
52 #else
53 #define __pubsub_start_sym(event)	__pubsub_##event##_start
54 #define __pubsub_end_sym(event)		__pubsub_##event##_end
55 #endif
56 
57 #define __pubsub_section(event)		__section(".__pubsub_" #event)
58 
59 /*
60  * In compiler context, REGISTER_PUBSUB_EVENT declares the per-event symbols
61  * exported by the linker required for the other pubsub macros to work.
62  */
63 #define REGISTER_PUBSUB_EVENT(event) \
64 	extern pubsub_cb_t __pubsub_start_sym(event)[]; \
65 	extern pubsub_cb_t __pubsub_end_sym(event)[]
66 
67 /*
68  * Have the function func called back when the specified event happens. This
69  * macro places the function address into the pubsub section, which is picked up
70  * and invoked by the invoke_pubsubs() function via the PUBLISH_EVENT* macros.
71  *
72  * The extern declaration is there to satisfy MISRA C-2012 rule 8.4.
73  */
74 #define SUBSCRIBE_TO_EVENT(event, func) \
75 	extern pubsub_cb_t __cb_func_##func##event __pubsub_section(event); \
76 	pubsub_cb_t __cb_func_##func##event __pubsub_section(event) = (func)
77 
78 /*
79  * Iterate over subscribed handlers for a defined event. 'event' is the name of
80  * the event, and 'subscriber' a local variable of type 'pubsub_cb_t *'.
81  */
82 #define for_each_subscriber(event, subscriber) \
83 	for (subscriber = __pubsub_start_sym(event); \
84 			subscriber < __pubsub_end_sym(event); \
85 			subscriber++)
86 
87 /*
88  * Publish a defined event supplying an argument. All subscribed handlers are
89  * invoked, but the return value of handlers are ignored for now.
90  */
91 #define PUBLISH_EVENT_ARG(event, arg) \
92 	do { \
93 		pubsub_cb_t *subscriber; \
94 		for_each_subscriber(event, subscriber) { \
95 			(*subscriber)(arg); \
96 		} \
97 	} while (0)
98 
99 /* Publish a defined event with NULL argument */
100 #define PUBLISH_EVENT(event)	PUBLISH_EVENT_ARG(event, NULL)
101 
102 /* Subscriber callback type */
103 typedef void* (*pubsub_cb_t)(const void *arg);
104 
105 #endif	/* __LINKER__ */
106 #endif /* PUBSUB_H */
107