blob: 8a4fe019a1c2d2082b615e716acdd554ff79c0b0 [file] [log] [blame]
/*
* Copyright (c) 2016 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
*
* @brief Workqueue structures and routines.
*/
#ifndef _misc_nano_work__h_
#define _misc_nano_work__h_
#include <nanokernel.h>
#include <atomic.h>
#include <misc/__assert.h>
#ifdef __cplusplus
extern "C" {
#endif
struct nano_work;
typedef void (*work_handler_t)(struct nano_work *);
/**
* A workqueue is a fiber that executes @ref nano_work items that are
* queued to it. This is useful for drivers which need to schedule
* execution of code which might sleep from ISR context. The actual
* fiber identifier is not stored in the structure in order to save
* space.
*/
struct nano_workqueue {
struct nano_fifo fifo;
};
/**
* @brief Work flags.
*/
enum {
NANO_WORK_STATE_IDLE, /* Work item idle state */
};
/**
* @brief An item which can be scheduled on a @ref nano_workqueue.
*/
struct nano_work {
void *_reserved; /* Used by nano_fifo implementation. */
work_handler_t handler;
atomic_t flags[1];
};
/**
* @brief Initialize work item
*/
static inline void nano_work_init(struct nano_work *work,
work_handler_t handler)
{
atomic_set_bit(work->flags, NANO_WORK_STATE_IDLE);
work->handler = handler;
}
/**
* @brief Submit a work item to a workqueue.
*/
static inline void nano_work_submit_to_queue(struct nano_workqueue *wq,
struct nano_work *work)
{
if (!atomic_test_and_clear_bit(work->flags, NANO_WORK_STATE_IDLE)) {
__ASSERT_NO_MSG(0);
} else {
nano_fifo_put(&wq->fifo, work);
}
}
/**
* @brief Start a new workqueue. Call this from fiber context.
*/
extern void nano_fiber_workqueue_start(struct nano_workqueue *wq,
const struct fiber_config *config);
/**
* @brief Start a new workqueue. Call this from task context.
*/
extern void nano_task_workqueue_start(struct nano_workqueue *wq,
const struct fiber_config *config);
/**
* @brief Start a new workqueue. This routine can be called from either
* fiber or task context.
*/
extern void nano_workqueue_start(struct nano_workqueue *wq,
const struct fiber_config *config);
#if defined(CONFIG_NANO_TIMEOUTS)
/*
* @brief An item which can be scheduled on a @ref nano_workqueue with a
* delay.
*/
struct nano_delayed_work {
struct nano_work work;
struct _nano_timeout timeout;
struct nano_workqueue *wq;
};
/**
* @brief Initialize delayed work
*/
void nano_delayed_work_init(struct nano_delayed_work *work,
work_handler_t handler);
/**
* @brief Submit a delayed work item to a workqueue.
*
* This procedure schedules a work item to be processed after a delay.
* Once the delay has passed, the work item is submitted to the work queue:
* at this point, it is no longer possible to cancel it. Once the work item's
* handler is about to be executed, the work is considered complete and can be
* resubmitted.
*
* Care must be taken if the handler blocks or yield as there is no implicit
* mutual exclusion mechanism. Such usage is not recommended and if necessary,
* it should be explicitly done between the submitter and the handler.
*
* @param Workqueue to schedule the work item
* @param Delayed work item
* @param Ticks to wait before scheduling the work item
*
* @return 0 in case of success or negative value in case of error.
*/
int nano_delayed_work_submit_to_queue(struct nano_workqueue *wq,
struct nano_delayed_work *work,
int ticks);
/**
* @brief Cancel a delayed work item
*
* This procedure cancels a scheduled work item. If the work has been completed
* or is idle, this will do nothing. The only case where this can fail is when
* the work has been submitted to the work queue, but the handler has not run
* yet.
*
* @param Delayed work item to be canceled
*
* @return 0 in case of success or negative value in case of error.
*/
int nano_delayed_work_cancel(struct nano_delayed_work *work);
#endif /* CONFIG_NANO_TIMEOUTS */
#if defined(CONFIG_SYSTEM_WORKQUEUE)
extern struct nano_workqueue sys_workqueue;
/*
* @brief Submit a work item to the system workqueue.
*
* @ref nano_work_submit_to_queue
*
* When using the system workqueue it is not recommended to block or yield
* on the handler since its fiber is shared system wide it may cause
* unexpected behavior.
*/
static inline void nano_work_submit(struct nano_work *work)
{
nano_work_submit_to_queue(&sys_workqueue, work);
}
#if defined(CONFIG_NANO_TIMEOUTS)
/*
* @brief Submit a delayed work item to the system workqueue.
*
* @ref nano_delayed_work_submit_to_queue
*
* When using the system workqueue it is not recommended to block or yield
* on the handler since its fiber is shared system wide it may cause
* unexpected behavior.
*/
static inline int nano_delayed_work_submit(struct nano_delayed_work *work,
int ticks)
{
return nano_delayed_work_submit_to_queue(&sys_workqueue, work, ticks);
}
#endif /* CONFIG_NANO_TIMEOUTS */
#endif /* CONFIG_SYSTEM_WORKQUEUE */
#ifdef __cplusplus
}
#endif
#endif /* _misc_nano_work__h_ */