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