From c0bb696f867c466da80b7abc4213dd8acf99d8cb Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Fri, 10 Jul 2020 15:49:27 -0400 Subject: [PATCH] Fix #540, add OSAL event framework Define an interface to allow an app/PSP to be notified when state changes or other events occur at the OS level. Initially defined events are resource creation/deletion and task startup. The interface is easily extendable with more events as needed. This can be used to add platform-specific/nonstandard functions by putting the code inside the event handler at the PSP level. --- src/os/inc/osapi-os-core.h | 90 +++++++++++++++++++++++++++- src/os/shared/inc/os-shared-common.h | 16 +++++ src/os/shared/src/osapi-common.c | 43 +++++++++++++ src/os/shared/src/osapi-idmap.c | 17 ++++++ src/os/shared/src/osapi-task.c | 6 ++ src/ut-stubs/osapi-utstub-common.c | 28 +++++++++ 6 files changed, 199 insertions(+), 1 deletion(-) diff --git a/src/os/inc/osapi-os-core.h b/src/os/inc/osapi-os-core.h index a073ac12d..18a89749c 100644 --- a/src/os/inc/osapi-os-core.h +++ b/src/os/inc/osapi-os-core.h @@ -173,6 +173,75 @@ typedef enum OS_STREAM_STATE_WRITABLE = 0x08, /**< @brief whether the stream is writable */ } OS_StreamState_t; +/** + * @brief A set of events that can be used with event callback routines + */ +typedef enum +{ + OS_EVENT_RESERVED = 0, /**< no-op/reserved event id value */ + + /** + * resource/id has been newly allocated but not yet created. + * + * This event is invoked from WITHIN the locked region, in + * the context of the task which is allocating the resource. + * + * If the handler returns non-success, the error will be returned + * to the caller and the creation process is aborted. + */ + OS_EVENT_RESOURCE_ALLOCATED, + + /** + * resource/id has been fully created/finalized. + * + * Invoked outside locked region, in the context + * of the task which created the resource. + * + * Data object is not used, passed as NULL. + * + * Return value is ignored - this is for information purposes only. + */ + OS_EVENT_RESOURCE_CREATED, + + /** + * resource/id has been deleted. + * + * Invoked outside locked region, in the context + * of the task which deleted the resource. + * + * Data object is not used, passed as NULL. + * + * Return value is ignored - this is for information purposes only. + */ + OS_EVENT_RESOURCE_DELETED, + + /** + * New task is starting. + * + * Invoked outside locked region, in the context + * of the task which is currently starting, before + * the entry point is called. + * + * Data object is not used, passed as NULL. + * + * If the handler returns non-success, task startup is aborted + * and the entry point is not called. + */ + OS_EVENT_TASK_STARTUP, + + OS_EVENT_MAX /**< placeholder for end of enum, not used */ +} OS_Event_t; + +/** + * @brief A callback routine for event handling. + * + * @param[in] event The event that occurred + * @param[in] object_id The associated object_id, or 0 if not associated with an object + * @param[inout] data An abstract data/context object associated with the event, or NULL. + * @return status Execution status, see @ref OSReturnCodes. + */ +typedef int32 (*OS_EventHandler_t)(OS_Event_t event, uint32 object_id, void *data); + /** * @brief For the @ref OS_GetErrorName() function, to ensure * everyone is making an array of the same length. @@ -360,7 +429,6 @@ int32 OS_ConvertToArrayIndex (uint32 object_id, uint32 *ArrayIndex); * @param[in] callback_arg Opaque Argument to pass to callback function */ void OS_ForEachObject (uint32 creator_id, OS_ArgCallback_t callback_ptr, void *callback_arg); -/**@}*/ /*-------------------------------------------------------------------------------------*/ /** @@ -377,6 +445,26 @@ void OS_ForEachObject (uint32 creator_id, OS_ArgCallback_t callback_pt */ void OS_ForEachObjectOfType (uint32 objtype, uint32 creator_id, OS_ArgCallback_t callback_ptr, void *callback_arg); +/*-------------------------------------------------------------------------------------*/ +/** + * @brief Callback routine registration + * + * This hook enables the application code to perform extra platform-specific + * operations on various system events such as resource creation/deletion. + * + * @note Some events are invoked while the resource is "locked" and therefore + * application-defined handlers for these events should not block or attempt + * to access other OSAL resources. + * + * @param[in] handler The application-provided event handler + * @return Execution status, see @ref OSReturnCodes. + * @retval #OS_SUCCESS @copybrief OS_SUCCESS + * @retval #OS_ERROR @copybrief OS_ERROR + */ +int32 OS_RegisterEventHandler (OS_EventHandler_t handler); + +/**@}*/ + /** @defgroup OSAPITask OSAL Task APIs * @{ diff --git a/src/os/shared/inc/os-shared-common.h b/src/os/shared/inc/os-shared-common.h index dff48082a..6f88a16d7 100644 --- a/src/os/shared/inc/os-shared-common.h +++ b/src/os/shared/inc/os-shared-common.h @@ -57,6 +57,12 @@ struct OS_shared_global_vars int32 MicroSecPerTick; int32 TicksPerSecond; + /* + * The event handler is an application-defined callback + * that gets invoked as resources are created/configured/deleted. + */ + OS_EventHandler_t EventHandler; + #ifdef OSAL_CONFIG_DEBUG_PRINTF uint8 DebugLevel; #endif @@ -69,6 +75,16 @@ struct OS_shared_global_vars */ extern OS_SharedGlobalVars_t OS_SharedGlobalVars; +/*--------------------------------------------------------------------------------------- + Name: OS_NotifyEvent + + Purpose: Notify the user application of a change in the state of an OSAL resource + + returns: OS_SUCCESS on success, or relevant error code +---------------------------------------------------------------------------------------*/ +int32 OS_NotifyEvent(OS_Event_t event, uint32 object_id, void *data); + + /*--------------------------------------------------------------------------------------- Name: OS_API_Impl_Init diff --git a/src/os/shared/src/osapi-common.c b/src/os/shared/src/osapi-common.c index ffe53f7bb..7392cb818 100644 --- a/src/os/shared/src/osapi-common.c +++ b/src/os/shared/src/osapi-common.c @@ -65,11 +65,36 @@ OS_SharedGlobalVars_t OS_SharedGlobalVars = .ShutdownFlag = 0, .MicroSecPerTick = 0, /* invalid, _must_ be set by implementation init */ .TicksPerSecond = 0, /* invalid, _must_ be set by implementation init */ + .EventHandler = NULL, #if defined(OSAL_CONFIG_DEBUG_PRINTF) .DebugLevel = 1, #endif }; + +/*---------------------------------------------------------------- + * + * Function: OS_NotifyEvent + * + * Purpose: Helper function to invoke the user-defined event handler + * + *-----------------------------------------------------------------*/ +int32 OS_NotifyEvent(OS_Event_t event, uint32 object_id, void *data) +{ + int32 status; + + if (OS_SharedGlobalVars.EventHandler != NULL) + { + status = OS_SharedGlobalVars.EventHandler(event, object_id, data); + } + else + { + status = OS_SUCCESS; + } + + return status; +} + /* ********************************************************************************* * PUBLIC API (application-callable functions) @@ -199,6 +224,24 @@ int32 OS_API_Init(void) return(return_code); } /* end OS_API_Init */ +/*---------------------------------------------------------------- + * + * Function: OS_RegisterEventHandler + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +int32 OS_RegisterEventHandler (OS_EventHandler_t handler) +{ + if (handler == NULL) + { + return OS_INVALID_POINTER; + } + + OS_SharedGlobalVars.EventHandler = handler; + return OS_SUCCESS; +} /*---------------------------------------------------------------- * diff --git a/src/os/shared/src/osapi-idmap.c b/src/os/shared/src/osapi-idmap.c index c98319f54..e82b1aadc 100644 --- a/src/os/shared/src/osapi-idmap.c +++ b/src/os/shared/src/osapi-idmap.c @@ -766,6 +766,12 @@ int32 OS_ObjectIdFinalizeNew(int32 operation_status, OS_common_record_t *record, /* Either way we must unlock the object type */ OS_Unlock_Global(idtype); + /* Give event callback to the application */ + if (operation_status == OS_SUCCESS) + { + OS_NotifyEvent(OS_EVENT_RESOURCE_CREATED, record->active_id, NULL); + } + return operation_status; } /* end OS_ObjectIdFinalizeNew */ @@ -794,6 +800,12 @@ int32 OS_ObjectIdFinalizeDelete(int32 operation_status, OS_common_record_t *reco /* Either way we must unlock the object type */ OS_Unlock_Global(idtype); + /* Give event callback to the application */ + if (saved_id != 0) + { + OS_NotifyEvent(OS_EVENT_RESOURCE_DELETED, saved_id, NULL); + } + return operation_status; } @@ -1078,6 +1090,11 @@ int32 OS_ObjectIdAllocateNew(uint32 idtype, const char *name, uint32 *array_inde return_code = OS_ObjectIdFindNext(idtype, array_index, record); } + if (return_code == OS_SUCCESS) + { + return_code = OS_NotifyEvent(OS_EVENT_RESOURCE_ALLOCATED, (*record)->active_id, NULL); + } + /* If allocation failed for any reason, unlock the global. * otherwise the global should stay locked so remaining initialization can be done */ if (return_code != OS_SUCCESS) diff --git a/src/os/shared/src/osapi-task.c b/src/os/shared/src/osapi-task.c index a041db4f3..3c192ac25 100644 --- a/src/os/shared/src/osapi-task.c +++ b/src/os/shared/src/osapi-task.c @@ -120,6 +120,12 @@ static int32 OS_TaskPrepare(uint32 task_id, osal_task_entry *entrypt) return_code = OS_TaskRegister_Impl(task_id); } + if (return_code == OS_SUCCESS) + { + /* Give event callback to the application */ + return_code = OS_NotifyEvent(OS_EVENT_TASK_STARTUP, task_id, NULL); + } + if (return_code != OS_SUCCESS) { *entrypt = NULL; diff --git a/src/ut-stubs/osapi-utstub-common.c b/src/ut-stubs/osapi-utstub-common.c index 01d4d131a..32c7b4040 100644 --- a/src/ut-stubs/osapi-utstub-common.c +++ b/src/ut-stubs/osapi-utstub-common.c @@ -49,6 +49,34 @@ int32 OS_API_Init(void) return status; } +/***************************************************************************** + * + * Stub function for OS_NotifyEvent() + * + *****************************************************************************/ +int32 OS_NotifyEvent(OS_Event_t event, uint32 object_id, void *data) +{ + int32 status; + + status = UT_DEFAULT_IMPL(OS_NotifyEvent); + + return status; +} + +/***************************************************************************** + * + * Stub function for OS_RegisterEventHandler() + * + *****************************************************************************/ +int32 OS_RegisterEventHandler (OS_EventHandler_t handler) +{ + int32 status; + + status = UT_DEFAULT_IMPL(OS_RegisterEventHandler); + + return status; +} + /***************************************************************************** *