Skip to content

Commit

Permalink
Fix nasa#540, add OSAL event framework
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jphickey committed Jul 10, 2020
1 parent 9eaf83b commit e176459
Show file tree
Hide file tree
Showing 17 changed files with 282 additions and 87 deletions.
90 changes: 89 additions & 1 deletion src/os/inc/osapi-os-core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
/**@}*/

/*-------------------------------------------------------------------------------------*/
/**
Expand All @@ -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
* @{
Expand Down
16 changes: 16 additions & 0 deletions src/os/shared/inc/os-shared-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
13 changes: 13 additions & 0 deletions src/os/shared/inc/os-shared-idmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,19 @@ int32 OS_ObjectIdAllocateNew(uint32 idtype, const char *name, uint32 *array_inde
------------------------------------------------------------------*/
int32 OS_ObjectIdFinalizeNew(int32 operation_status, OS_common_record_t *record, uint32 *outid);

/*----------------------------------------------------------------
Function: OS_ObjectIdFinalizeDelete
Purpose: Completes a delete operation
If the operation was successful, the OSAL ID is deleted and returned to the pool
If the operation was unsuccessful, no operation is performed.
The global table is unlocked for future operations
Returns: OS_SUCCESS on success, or relevant error code
------------------------------------------------------------------*/
int32 OS_ObjectIdFinalizeDelete(int32 operation_status, OS_common_record_t *record);


/*----------------------------------------------------------------
Function: OS_ObjectIdRefcountDecr
Expand Down
10 changes: 2 additions & 8 deletions src/os/shared/src/osapi-binsem.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,14 +157,8 @@ int32 OS_BinSemDelete (uint32 sem_id)
{
return_code = OS_BinSemDelete_Impl(local_id);

/* Free the entry in the master table now while still locked */
if (return_code == OS_SUCCESS)
{
/* Only need to clear the ID as zero is the "unused" flag */
record->active_id = 0;
}

OS_Unlock_Global(LOCAL_OBJID_TYPE);
/* Complete the operation via the common routine */
return_code = OS_ObjectIdFinalizeDelete(return_code, record);
}

return return_code;
Expand Down
43 changes: 43 additions & 0 deletions src/os/shared/src/osapi-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}

/*----------------------------------------------------------------
*
Expand Down
10 changes: 2 additions & 8 deletions src/os/shared/src/osapi-countsem.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,8 @@ int32 OS_CountSemDelete (uint32 sem_id)
{
return_code = OS_CountSemDelete_Impl(local_id);

/* Free the entry in the master table now while still locked */
if (return_code == OS_SUCCESS)
{
/* Only need to clear the ID as zero is the "unused" flag */
record->active_id = 0;
}

OS_Unlock_Global(LOCAL_OBJID_TYPE);
/* Complete the operation via the common routine */
return_code = OS_ObjectIdFinalizeDelete(return_code, record);
}

return return_code;
Expand Down
10 changes: 2 additions & 8 deletions src/os/shared/src/osapi-dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,8 @@ int32 OS_DirectoryClose(uint32 dir_id)
{
return_code = OS_DirClose_Impl(local_id);

/* Free the entry in the master table now while still locked */
if (return_code == OS_SUCCESS)
{
/* Only need to clear the ID as zero is the "unused" flag */
record->active_id = 0;
}

OS_Unlock_Global(LOCAL_OBJID_TYPE);
/* Complete the operation via the common routine */
return_code = OS_ObjectIdFinalizeDelete(return_code, record);
}

return return_code;
Expand Down
10 changes: 2 additions & 8 deletions src/os/shared/src/osapi-file.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,14 +223,8 @@ int32 OS_close (uint32 filedes)
{
return_code = OS_GenericClose_Impl(local_id);

/* Free the entry in the master table now while still locked */
if (return_code == OS_SUCCESS)
{
/* Only need to clear the ID as zero is the "unused" flag */
record->active_id = 0;
}

OS_Unlock_Global(LOCAL_OBJID_TYPE);
/* Complete the operation via the common routine */
return_code = OS_ObjectIdFinalizeDelete(return_code, record);
}

return return_code;
Expand Down
45 changes: 45 additions & 0 deletions src/os/shared/src/osapi-idmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -766,9 +766,49 @@ 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 */

/*----------------------------------------------------------------
Function: OS_ObjectIdFinalizeDelete
Purpose: Helper routine, not part of OSAL public API.
See description in prototype
------------------------------------------------------------------*/
int32 OS_ObjectIdFinalizeDelete(int32 operation_status, OS_common_record_t *record)
{
uint32 idtype = OS_ObjectIdToType_Impl(record->active_id);
uint32 saved_id;

/* Clear the OSAL ID if successful - this returns the record to the pool */
if (operation_status == OS_SUCCESS)
{
saved_id = record->active_id;
record->active_id = 0;
}
else
{
saved_id = 0;
}

/* 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;
}


/*----------------------------------------------------------------
*
Expand Down Expand Up @@ -1050,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)
Expand Down
10 changes: 2 additions & 8 deletions src/os/shared/src/osapi-module.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,14 +289,8 @@ int32 OS_ModuleUnload ( uint32 module_id )
*/
return_code = OS_ModuleUnload_Impl(local_id);

if (return_code == OS_SUCCESS)
{
/* Clear the ID to zero */
record->active_id = 0;
}

/* Unlock the global from OS_ObjectIdGetAndLock() */
OS_Unlock_Global(LOCAL_OBJID_TYPE);
/* Complete the operation via the common routine */
return_code = OS_ObjectIdFinalizeDelete(return_code, record);
}

return return_code;
Expand Down
10 changes: 2 additions & 8 deletions src/os/shared/src/osapi-mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,14 +145,8 @@ int32 OS_MutSemDelete (uint32 sem_id)
{
return_code = OS_MutSemDelete_Impl(local_id);

/* Free the entry in the master table now while still locked */
if (return_code == OS_SUCCESS)
{
/* Only need to clear the ID as zero is the "unused" flag */
record->active_id = 0;
}

OS_Unlock_Global(LOCAL_OBJID_TYPE);
/* Complete the operation via the common routine */
return_code = OS_ObjectIdFinalizeDelete(return_code, record);
}

return return_code;
Expand Down
Loading

0 comments on commit e176459

Please sign in to comment.