diff options
Diffstat (limited to 'include/asterisk/optional_api.h')
-rw-r--r-- | include/asterisk/optional_api.h | 148 |
1 files changed, 131 insertions, 17 deletions
diff --git a/include/asterisk/optional_api.h b/include/asterisk/optional_api.h index 1af596ec1..df875a849 100644 --- a/include/asterisk/optional_api.h +++ b/include/asterisk/optional_api.h @@ -32,14 +32,14 @@ * * To accomodate this situation, the AST_OPTIONAL_API macro allows an API * function to be declared in a special way, if Asterisk being built on a - * platform that supports the GCC 'weak' and 'alias' attributes. If so, - * the API function is actually a weak symbol, which means if the provider - * of the API is not loaded, the symbol can still be referenced (unlike a + * platform that supports special compiler and dynamic linker attributes. + * If so the API function will actually be a weak symbol, which means if the + * provider of the API is not loaded, the symbol can still be referenced (unlike a * strong symbol, which would cause an immediate fault if not defined when * referenced), but it will return NULL signifying the linker/loader was * not able to resolve the symbol. In addition, the macro defines a hidden * 'stub' version of the API call, using a provided function body, and uses - * the alias attribute to make the API function symbol actually resolve to + * various methods to make the API function symbol actually resolve to * that hidden stub, but only when the *real* provider of the symbol has * not been found. * @@ -57,13 +57,25 @@ * safely know that the API is not available, and to avoid using any * other APIs from the not-present provider. * + * In addition to this declaration in the header file, the actual definition of + * the API function must use the AST_OPTIONAL_API_NAME macro to (possibly) + * modify the real name of the API function, depending on the specific + * implementation requirements. The corresponding example from res_agi.c: + * + * \code + * int AST_OPTIONAL_API_NAME(ast_agi_register)(struct ast_module *mod, agi_command *cmd) + * { + * ... + * } + * \endcode + * * In the module providing the API, the AST_OPTIONAL_API macro must * be informed that it should not build the hidden stub function or * apply special aliases to the function prototype; this can be done * by defining AST_API_MODULE just before including the header file * containing the AST_OPTIONAL_API macro calls. * - * \note If the GCC 'weak' and 'alias' attributes are not available, + * \note If the platform does not provide adequate resources, * then the AST_OPTIONAL_API macro will result in a non-optional function * definition; this means that any consumers of the API functions so * defined will require that the provider of the API functions be @@ -83,17 +95,115 @@ */ #define AST_OPTIONAL_API_UNAVAILABLE INT_MIN -#if defined(HAVE_ATTRIBUTE_weak_import) && !defined(AST_API_MODULE) -#define AST_OPTIONAL_API(result, name, proto, stub) result name proto __attribute__((weak_import)); -#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) result name proto __attribute__((weak_import,attr)); -#elif defined(HAVE_ATTRIBUTE_weak) && defined(HAVE_ATTRIBUTE_alias) && !defined(AST_API_MODULE) && !defined(HAVE_ATTRIBUTE_weak_import) -#define AST_OPTIONAL_API(result, name, proto, stub) \ - static result __##name proto stub; \ - result __attribute__((weak, alias("__" __stringify(name)))) name proto; -#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ - static result __attribute__((attr)) __##name proto stub; \ - result __attribute__((weak, alias("__" __stringify(name)), attr)) name proto; + +#if defined(HAVE_ATTRIBUTE_weak_import) + +/* + * This is the Darwin (Mac OS/X) implementation, that only provides the + * 'weak_import' compiler attribute for weak symbols. On this platform, + * + * - The module providing the API will only provide a '__' prefixed version + * of the API function to other modules (this will be hidden from the other + * modules by the macros), so any modules compiled against older versions + * of the module that provided a non-prefixed version of the API function + * will fail to link at runtime. + * - In the API module itself, access to the API function without using a + * prefixed name is provided by a static pointer variable that holds the + * function address. + * - 'Consumer' modules of the API will use a combination of a weak_import + * symbol, a local stub function, a pointer variable and a constructor function + * (which initializes that pointer variable as the module is being loaded) + * to provide safe, optional access to the API function without any special + * code being required. + */ + +#define AST_OPTIONAL_API_NAME(name) __##name + +#if defined(AST_API_MODULE) + +#define AST_OPTIONAL_API(result, name, proto, stub) \ + result AST_OPTIONAL_API_NAME(name) proto; \ + static attribute_unused typeof(AST_OPTIONAL_API_NAME(name)) * const name = AST_OPTIONAL_API_NAME(name); + +#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ + result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto; \ + static attribute_unused typeof(AST_OPTIONAL_API_NAME(name)) * const name = AST_OPTIONAL_API_NAME(name); + +#else + +#define AST_OPTIONAL_API(result, name, proto, stub) \ + static result __stub__##name proto stub; \ + __attribute__((weak_import)) typeof(__stub__##name) AST_OPTIONAL_API_NAME(name); \ + static attribute_unused typeof(__stub__##name) * name; \ + static void __attribute__((constructor)) __init__##name(void) { name = AST_OPTIONAL_API_NAME(name) ? : __stub__##name; } + +#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ + static __attribute__((attr)) result __stub__##name proto stub; \ + __attribute__((attr, weak_import)) typeof(__stub__##name) AST_OPTIONAL_API_NAME(name); \ + static attribute_unused __attribute__((attr)) typeof(__stub__##name) * name; \ + static void __attribute__((constructor)) __init__##name(void) { name = AST_OPTIONAL_API_NAME(name) ? : __stub__##name; } + + +#endif + +/* End of Darwin (Mac OS/X) implementation */ + +#elif defined(HAVE_ATTRIBUTE_weakref) + +/* + * This is the generic GCC implementation, used when the 'weakref' + * compiler attribute is available. On these platforms: + * + * - The module providing the API will provide a '__' prefixed version + * of the API function to other modules (this will be hidden from the other + * modules by the macros), and also a non-prefixed alias so that modules + * compiled against older versions of the module that provided a non-prefixed + * version of the API function will continue to link properly. + * - In the API module itself, access to the API function without using a + * prefixed name is provided by the non-prefixed alias described above. + * - 'Consumer' modules of the API will use a combination of a weakref + * symbol, a local stub function, a pointer variable and a constructor function + * (which initializes that pointer variable as the module is being loaded) + * to provide safe, optional access to the API function without any special + * code being required. + */ + +#define AST_OPTIONAL_API_NAME(name) __##name + +#if defined(AST_API_MODULE) + +#define AST_OPTIONAL_API(result, name, proto, stub) \ + result AST_OPTIONAL_API_NAME(name) proto; \ + __attribute__((alias(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(AST_OPTIONAL_API_NAME(name)) name; + +#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ + result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto; \ + __attribute__((alias(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(AST_OPTIONAL_API_NAME(name)) name; + +#else + +#define AST_OPTIONAL_API(result, name, proto, stub) \ + static result __stub__##name proto stub; \ + static __attribute__((weakref(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(__stub__##name) __ref__##name; \ + static attribute_unused typeof(__stub__##name) * name; \ + static void __attribute__((constructor)) __init__##name(void) { name = __ref__##name ? : __stub__##name; } + +#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) \ + static __attribute__((attr)) result __stub__##name proto stub; \ + static __attribute__((attr, weakref(__stringify(AST_OPTIONAL_API_NAME(name))))) typeof(__stub__##name) __ref__##name; \ + static attribute_unused __attribute__((attr)) typeof(__stub__##name) * name; \ + static void __attribute__((constructor)) __init__##name(void) { name = __ref__##name ? : __stub__##name; } + +#endif + +/* End of GCC implementation */ + #else + +/* This is the non-optional implementation. */ + +#define AST_OPTIONAL_API_NAME(name) name + /*! * \brief Define an optional API function * @@ -108,7 +218,8 @@ * { return AST_OPTIONAL_API_UNAVAILABLE; }); * \endcode */ -#define AST_OPTIONAL_API(result, name, proto, stub) result name proto; +#define AST_OPTIONAL_API(result, name, proto, stub) result AST_OPTIONAL_API_NAME(name) proto + /*! * \brief Define an optional API function with compiler attributes * @@ -118,7 +229,10 @@ * \param proto The prototype (arguments) of the function * \param stub The code block that will be used by the hidden stub when needed */ -#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) result __attribute__((attr)) name proto; +#define AST_OPTIONAL_API_ATTR(result, attr, name, proto, stub) result __attribute__((attr)) AST_OPTIONAL_API_NAME(name) proto + +/* End of non-optional implementation */ + #endif #undef AST_API_MODULE |