arm-trusted-firmware/include/lib/el3_runtime/pubsub.h
Boyan Karatotev f8d2a0e5ca fix(pubsub): make sure LTO doesn't garbage collect the handlers
We never directly reference the event handlers so they look like fair
game to be garbage collected when building with LTO.

Tell the compiler that we definitely need them and to leave them alone.

Change-Id: Iac672ce85e20328d25acbc3f5e544ad157eebf48
Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com>
2024-12-17 13:27:18 +00:00

106 lines
3 KiB
C

/*
* Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PUBSUB_H
#define PUBSUB_H
#ifdef __LINKER__
/* For the linker ... */
#define __pubsub_start_sym(event) __pubsub_##event##_start
#define __pubsub_end_sym(event) __pubsub_##event##_end
#define __pubsub_section(event) .__pubsub_##event
/*
* REGISTER_PUBSUB_EVENT has a different definition between linker and compiler
* contexts. In linker context, this collects pubsub sections for each event,
* placing guard symbols around each.
*/
#if defined(USE_ARM_LINK)
#define REGISTER_PUBSUB_EVENT(event) \
__pubsub_start_sym(event) +0 FIXED \
{ \
*(__pubsub_section(event)) \
} \
__pubsub_end_sym(event) +0 FIXED EMPTY 0 \
{ \
/* placeholder */ \
}
#else
#define REGISTER_PUBSUB_EVENT(event) \
__pubsub_start_sym(event) = .; \
KEEP(*(__pubsub_section(event))); \
__pubsub_end_sym(event) = .
#endif
#else /* __LINKER__ */
/* For the compiler ... */
#include <assert.h>
#include <cdefs.h>
#include <stddef.h>
#include <arch_helpers.h>
#if defined(USE_ARM_LINK)
#define __pubsub_start_sym(event) Load$$__pubsub_##event##_start$$Base
#define __pubsub_end_sym(event) Load$$__pubsub_##event##_end$$Base
#else
#define __pubsub_start_sym(event) __pubsub_##event##_start
#define __pubsub_end_sym(event) __pubsub_##event##_end
#endif
#define __pubsub_section(event) __section(".__pubsub_" #event)
/*
* In compiler context, REGISTER_PUBSUB_EVENT declares the per-event symbols
* exported by the linker required for the other pubsub macros to work.
*/
#define REGISTER_PUBSUB_EVENT(event) \
extern pubsub_cb_t __pubsub_start_sym(event)[]; \
extern pubsub_cb_t __pubsub_end_sym(event)[]
/*
* Have the function func called back when the specified event happens. This
* macro places the function address into the pubsub section, which is picked up
* and invoked by the invoke_pubsubs() function via the PUBLISH_EVENT* macros.
*
* The extern declaration is there to satisfy MISRA C-2012 rule 8.4.
*/
#define SUBSCRIBE_TO_EVENT(event, func) \
extern pubsub_cb_t __cb_func_##func##event __pubsub_section(event); \
pubsub_cb_t __cb_func_##func##event __used __pubsub_section(event) = (func)
/*
* Iterate over subscribed handlers for a defined event. 'event' is the name of
* the event, and 'subscriber' a local variable of type 'pubsub_cb_t *'.
*/
#define for_each_subscriber(event, subscriber) \
for (subscriber = __pubsub_start_sym(event); \
subscriber < __pubsub_end_sym(event); \
subscriber++)
/*
* Publish a defined event supplying an argument. All subscribed handlers are
* invoked, but the return value of handlers are ignored for now.
*/
#define PUBLISH_EVENT_ARG(event, arg) \
do { \
pubsub_cb_t *subscriber; \
for_each_subscriber(event, subscriber) { \
(*subscriber)(arg); \
} \
} while (0)
/* Publish a defined event with NULL argument */
#define PUBLISH_EVENT(event) PUBLISH_EVENT_ARG(event, NULL)
/* Subscriber callback type */
typedef void* (*pubsub_cb_t)(const void *arg);
#endif /* __LINKER__ */
#endif /* PUBSUB_H */