projects/bare_metal/event_task_bare_metal.c (116 lines of code) (raw):
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "event_task_bare_metal.h"
#include "common/unused.h"
int event_task_bare_metal_lock (const struct event_task *task)
{
const struct event_task_bare_metal *bare_metal = (const struct event_task_bare_metal*) task;
if (bare_metal == NULL) {
return EVENT_TASK_INVALID_ARGUMENT;
}
/* No need for a lock in a bare-metal environment. */
return 0;
}
int event_task_bare_metal_unlock (const struct event_task *task)
{
const struct event_task_bare_metal *bare_metal = (const struct event_task_bare_metal*) task;
if (bare_metal == NULL) {
return EVENT_TASK_INVALID_ARGUMENT;
}
return 0;
}
int event_task_bare_metal_get_event_context (const struct event_task *task,
struct event_task_context **context)
{
const struct event_task_bare_metal *bare_metal = (const struct event_task_bare_metal*) task;
int status;
if ((bare_metal == NULL) || (context == NULL)) {
return EVENT_TASK_INVALID_ARGUMENT;
}
if (!bare_metal->state->notifying) {
bare_metal->state->notifying = true;
*context = &bare_metal->state->context;
status = 0;
}
else {
status = EVENT_TASK_BUSY;
}
return status;
}
/**
* Task routine to handle notifications for registered handlers.
*
* @param task The task to process event notifications.
*/
static void event_task_bare_metal_process_notification (const struct event_task_bare_metal *task)
{
bool reset = false;
/* Sanity check the handler index before using it. */
if ((task->state->running >= 0) && ((size_t) task->state->running < task->num_handlers)) {
/* Execute the selected handler for the event. */
task->handlers[task->state->running]->execute (task->handlers[task->state->running],
&task->state->context, &reset);
}
if (reset) {
/* If the event requires it, reset the system. We need to wait a bit before triggering
* the reset to allow time for any execution status to be reported. */
platform_msleep (5000);
system_reset (task->system);
reset = false; /* We should never get here, but clear the flag if the reset fails. */
}
task->state->running = -1;
}
int event_task_bare_metal_notify (const struct event_task *task,
const struct event_task_handler *handler)
{
const struct event_task_bare_metal *bare_metal = (const struct event_task_bare_metal*) task;
int status;
if (task == NULL) {
return EVENT_TASK_INVALID_ARGUMENT;
}
if (bare_metal->state->notifying) {
/* Make sure the requested handler is registered with the task. */
status = event_task_find_handler (handler, bare_metal->handlers, bare_metal->num_handlers);
if (!ROT_IS_ERROR (status)) {
bare_metal->state->running = status;
status = 0;
}
bare_metal->state->notifying = false;
if (status == 0) {
/* If the handler is valid, handle the notification. Since there is no task, just
* process the notification directly. */
event_task_bare_metal_process_notification (bare_metal);
}
}
else {
status = EVENT_TASK_NOT_READY;
}
return status;
}
/**
* Initialize an event handler task.
*
* @param task The event handler task to initialize.
* @param state Variable context for the task. This must be uninitialized.
* @param system The manager for system operations.
* @param handlers The list of event handlers that can be used with this task instance.
* @param num_handlers The number of event handlers in the list.
*
* @return 0 if the task was initialized or an error code
*/
int event_task_bare_metal_init (struct event_task_bare_metal *task,
struct event_task_bare_metal_state *state, struct system *system,
const struct event_task_handler **handlers, size_t num_handlers)
{
if (task == NULL) {
return EVENT_TASK_INVALID_ARGUMENT;
}
memset (task, 0, sizeof (struct event_task_bare_metal));
task->base.lock = event_task_bare_metal_lock;
task->base.unlock = event_task_bare_metal_unlock;
task->base.get_event_context = event_task_bare_metal_get_event_context;
task->base.notify = event_task_bare_metal_notify;
task->state = state;
task->system = system;
task->handlers = handlers;
task->num_handlers = num_handlers;
return event_task_bare_metal_init_state (task);
}
/**
* Initialize only the variable state for an event handler task. The rest of the task instance is
* assumed to have already been initialized.
*
* This would generally be used with a statically initialized instance.
*
* @param task The task instance that contains the state to initialize.
*
* @return 0 if the state was successfully initialized or an error code.
*/
int event_task_bare_metal_init_state (const struct event_task_bare_metal *task)
{
if ((task == NULL) || (task->state == NULL) || (task->system == NULL) ||
(task->handlers == NULL) || (task->num_handlers == 0)) {
return EVENT_TASK_INVALID_ARGUMENT;
}
memset (task->state, 0, sizeof (struct event_task_bare_metal_state));
return 0;
}
/**
* Release the event task resources. No handlers will be released.
*
* @param task The task to release.
*/
void event_task_bare_metal_release (const struct event_task_bare_metal *task)
{
UNUSED (task);
}
/**
* Prepare the events handler for execution.
*
* @param task The event task to start.
*
* @return 0 if the task was started or an error code.
*/
int event_task_bare_metal_start (const struct event_task_bare_metal *task)
{
if (task == NULL) {
return EVENT_TASK_INVALID_ARGUMENT;
}
event_task_prepare_handlers (task->handlers, task->num_handlers);
return 0;
}