kernel: Eliminate the need for command packet sets
Revises microkernel semaphore sub-system to allow ISRs and fibers to give a semaphore without having to define a command packet set. The microkernel server now supports a 3rd command type on its command stack, allowing a semaphore to be given in a similar manner to the one used for the existing "give event" command type. Change-Id: Ibd7fb1a77949792f72acd20a9ee304d6eabd62f7 Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
This commit is contained in:
parent
30f01d86e0
commit
7c4b9ce1f7
|
@ -20,23 +20,8 @@
|
|||
* @brief Microkernel command packet library
|
||||
*
|
||||
* A command packet is an opaque data structure that maps to a k_args without
|
||||
* exposing its innards. It allows a subsystem, like a driver, that needs its
|
||||
* fibers or ISRs to communicate with tasks to define a set of such packets to
|
||||
* be passed to the isr_xxx routines, such as isr_sem_give(), that, in turn,
|
||||
* needs to obtain command packets to interact with the microkernel.
|
||||
*
|
||||
* Each command packet set is created in global memory using ...
|
||||
* CMD_PKT_SET_INSTANCE(set variable name, # of command packets in the set);
|
||||
*
|
||||
* Once created, the command packet set is referenced as an ordinary structured
|
||||
* variable.
|
||||
|
||||
* A command packet set is a simple ring buffer. No error checking is performed
|
||||
* when a command packet is retrieved from the set. Each obtained command packet
|
||||
* is implicitly released once the command packet has been processed. Thus, it is
|
||||
* important that each command packet be processed in a near-FIFO order to prevent
|
||||
* corruption of command packets that are already in use. To this end, drivers
|
||||
* that have an ISR component should use their own command packet set.
|
||||
* exposing its innards. This library allows a subsystem that needs to define
|
||||
* a command packet the ability to do so.
|
||||
*/
|
||||
|
||||
#ifndef _COMMAND_PACKET_H
|
||||
|
@ -52,35 +37,10 @@ extern "C" {
|
|||
|
||||
#define CMD_PKT_SIZE_IN_WORDS (19)
|
||||
|
||||
/* define command packet set types */
|
||||
/* define command packet type */
|
||||
|
||||
typedef uint32_t cmdPkt_t[CMD_PKT_SIZE_IN_WORDS];
|
||||
|
||||
struct cmd_pkt_set {
|
||||
uint32_t num_packets; /* number of command packets in set */
|
||||
uint32_t index; /* index into command packet array */
|
||||
cmdPkt_t *command_packet; /* pointer to array of command packets */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Define a command packet set
|
||||
*
|
||||
* This macro is used to create a command packet set of the specified size.
|
||||
*
|
||||
* @param name Name of command packet set
|
||||
* @param num Number of packets in the set
|
||||
*
|
||||
* @warning The command packet set exists in the global namespace,
|
||||
* and cannot be hidden by prefixing the macro with "static".
|
||||
*/
|
||||
#define CMD_PKT_SET_INSTANCE(name, num) \
|
||||
uint32_t __noinit(_k_cmd_pkts_ ## name)[CMD_PKT_SIZE_IN_WORDS * (num)]; \
|
||||
struct cmd_pkt_set name = {(num), 0, (cmdPkt_t *)(_k_cmd_pkts_ ## name)}
|
||||
|
||||
/* externs */
|
||||
|
||||
extern struct k_args *_cmd_pkt_get(struct cmd_pkt_set *pSet);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -40,33 +40,27 @@ extern "C" {
|
|||
*
|
||||
* @brief Signal a semaphore from a fiber
|
||||
*
|
||||
* This routine (to only be called from a fiber) signals a semaphore. It
|
||||
* requires a statically allocated command packet (from a command packet set)
|
||||
* that is implicitly released once the command packet has been processed.
|
||||
* This routine (to only be called from a fiber) signals a semaphore.
|
||||
* To signal a semaphore from a task, task_sem_give() should be used instead.
|
||||
*
|
||||
* @param sema Semaphore to signal.
|
||||
* @param pSet Pointer to command packet set.
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
extern void isr_sem_give(ksem_t sema, struct cmd_pkt_set *pSet);
|
||||
extern void isr_sem_give(ksem_t sema);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Signal a semaphore from an ISR
|
||||
*
|
||||
* This routine (to only be called from an ISR) signals a semaphore. It
|
||||
* requires a statically allocated command packet (from a command packet set)
|
||||
* that is implicitly released once the command packet has been processed.
|
||||
* This routine (to only be called from an ISR) signals a semaphore.
|
||||
* To signal a semaphore from a task, task_sem_give() should be used instead.
|
||||
*
|
||||
* @param sema Semaphore to signal.
|
||||
* @param pSet Pointer to command packet set.
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
extern void fiber_sem_give(ksem_t sema, struct cmd_pkt_set *pSet);
|
||||
extern void fiber_sem_give(ksem_t sema);
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -142,6 +136,21 @@ extern void task_sem_group_reset(ksemg_t semagroup);
|
|||
/**
|
||||
* @cond internal
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Update value of semaphore structure
|
||||
*
|
||||
* This routine updates the value of the semaphore by 0 or more units, then
|
||||
* gives the semaphore to any waiting tasks that can now be satisfied.
|
||||
*
|
||||
* @param n Number of additional times semaphore has been given.
|
||||
* @param sema Semaphore structure to update.
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
extern void _k_sem_struct_value_update(int n, struct _k_sem_struct *S);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Test a semaphore
|
||||
|
|
|
@ -33,39 +33,6 @@
|
|||
uint32_t _k_test_cmd_pkt_size
|
||||
[0 - ((CMD_PKT_SIZE_IN_WORDS * sizeof(uint32_t)) != sizeof(struct k_args))];
|
||||
|
||||
/**
|
||||
* @brief Get the next command packet
|
||||
*
|
||||
* This routine gets the next command packet from the specified set.
|
||||
* @param pSet Pointer to set of command packets
|
||||
*
|
||||
* @return pointer to the command packet
|
||||
*
|
||||
* @internal
|
||||
* It is critical that the word corresponding to the [alloc] field in the
|
||||
* equivalent struct k_args command packet be zero so that the system knows the
|
||||
* command packet is not part of the free list.
|
||||
* @endinternal
|
||||
*/
|
||||
struct k_args *_cmd_pkt_get(struct cmd_pkt_set *pSet)
|
||||
{
|
||||
uint32_t index; /* index into command packet array */
|
||||
struct k_args *cmd_pkt; /* pointer to command packet */
|
||||
int key; /* interrupt lock level */
|
||||
|
||||
key = irq_lock();
|
||||
index = pSet->index;
|
||||
pSet->index++;
|
||||
if (pSet->index >= pSet->num_packets)
|
||||
pSet->index = 0;
|
||||
irq_unlock(key);
|
||||
|
||||
cmd_pkt = (struct k_args *)&pSet->command_packet[index];
|
||||
cmd_pkt->alloc = false;
|
||||
|
||||
return cmd_pkt;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Send command packet to be processed by _k_server
|
||||
|
|
|
@ -26,13 +26,7 @@
|
|||
|
||||
#include <micro_private.h>
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Common code for signaling a semaphore
|
||||
*
|
||||
* @return N/A
|
||||
*/
|
||||
static void signal_semaphore(int n, struct _k_sem_struct *S)
|
||||
void _k_sem_struct_value_update(int n, struct _k_sem_struct *S)
|
||||
{
|
||||
struct k_args *A, *X, *Y;
|
||||
|
||||
|
@ -127,7 +121,7 @@ void _k_sem_group_wait_cancel(struct k_args *A)
|
|||
ENDLIST)) {
|
||||
waitTaskArgs->args.s1.sema = A->args.s1.sema;
|
||||
} else {
|
||||
signal_semaphore(1, S);
|
||||
_k_sem_struct_value_update(1, S);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,7 +265,7 @@ void _k_sem_group_wait_request(struct k_args *A)
|
|||
} else {
|
||||
S->waiters = A;
|
||||
}
|
||||
signal_semaphore(0, S);
|
||||
_k_sem_struct_value_update(0, S);
|
||||
}
|
||||
|
||||
void _k_sem_group_wait_any(struct k_args *A)
|
||||
|
@ -371,7 +365,7 @@ void _k_sem_signal(struct k_args *A)
|
|||
uint32_t Sid = A->args.s1.sema;
|
||||
struct _k_sem_struct *S = (struct _k_sem_struct *)Sid;
|
||||
|
||||
signal_semaphore(1, S);
|
||||
_k_sem_struct_value_update(1, S);
|
||||
}
|
||||
|
||||
void _k_sem_group_signal(struct k_args *A)
|
||||
|
@ -403,15 +397,10 @@ void task_sem_group_give(ksemg_t group)
|
|||
|
||||
FUNC_ALIAS(isr_sem_give, fiber_sem_give, void);
|
||||
|
||||
void isr_sem_give(ksem_t sema, struct cmd_pkt_set *pSet)
|
||||
void isr_sem_give(ksem_t sema)
|
||||
{
|
||||
struct k_args *pCommand; /* ptr to command packet */
|
||||
|
||||
pCommand = _cmd_pkt_get(pSet);
|
||||
pCommand->Comm = _K_SVC_SEM_SIGNAL;
|
||||
pCommand->args.s1.sema = sema;
|
||||
|
||||
nano_isr_stack_push(&_k_command_stack, (uint32_t)pCommand);
|
||||
nano_isr_stack_push(&_k_command_stack,
|
||||
(uint32_t)sema | KERNEL_CMD_SEMAPHORE_TYPE);
|
||||
}
|
||||
|
||||
void _k_sem_reset(struct k_args *A)
|
||||
|
|
|
@ -110,9 +110,9 @@ FUNC_NORETURN void _k_server(int unused1, int unused2)
|
|||
}
|
||||
#endif
|
||||
(*pArgs->Comm)(pArgs);
|
||||
} else {
|
||||
} else if (cmd_type == KERNEL_CMD_EVENT_TYPE) {
|
||||
|
||||
/* cmd_type == KERNEL_CMD_EVENT_TYPE */
|
||||
/* give event */
|
||||
|
||||
#ifdef CONFIG_TASK_MONITOR
|
||||
if (_k_monitor_mask & MON_EVENT) {
|
||||
|
@ -122,6 +122,16 @@ FUNC_NORETURN void _k_server(int unused1, int unused2)
|
|||
kevent_t event = (int)pArgs & ~KERNEL_CMD_TYPE_MASK;
|
||||
|
||||
_k_do_event_signal(event);
|
||||
} else { /* cmd_type == KERNEL_CMD_SEMAPHORE_TYPE */
|
||||
|
||||
/* give semaphore */
|
||||
|
||||
#ifdef CONFIG_TASK_MONITOR
|
||||
/* task monitoring for giving semaphore not implemented */
|
||||
#endif
|
||||
ksem_t sem = (int)pArgs & ~KERNEL_CMD_TYPE_MASK;
|
||||
|
||||
_k_sem_struct_value_update(1, (struct _k_sem_struct *)sem);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -44,8 +44,6 @@ extern struct nano_sem fiberSem; /* semaphore that allows test control the fiber
|
|||
|
||||
static ksem_t testIsrInfo;
|
||||
|
||||
CMD_PKT_SET_INSTANCE(cmdPktSetIsr, 2);
|
||||
|
||||
/*
|
||||
* Note that semaphore group entries are arranged so that resultSems[TC_PASS]
|
||||
* refers to SEM_TASKDONE and resultSems[TC_FAIL] refers to SEM_TASKFAIL.
|
||||
|
@ -165,7 +163,7 @@ void LowPriTaskEntry(void)
|
|||
|
||||
static void testIsrHandler(void *isrData)
|
||||
{
|
||||
isr_sem_give(*(ksem_t *)isrData, &cmdPktSetIsr);
|
||||
isr_sem_give(*(ksem_t *)isrData);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -36,9 +36,6 @@ extern ksem_t semList[];
|
|||
|
||||
static char __stack fiberStack[FIBER_STACK_SIZE]; /* test fiber stack size */
|
||||
|
||||
/* command packet set used by test fiber to signal semaphores */
|
||||
CMD_PKT_SET_INSTANCE(cmdPktSetFiber, N_TESTS + 1);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief The test fiber entry function
|
||||
|
@ -57,18 +54,18 @@ static void testFiberEntry(void)
|
|||
int i;
|
||||
/* release semaphore test task is waiting for */
|
||||
nano_fiber_sem_take_wait(&fiberSem);
|
||||
fiber_sem_give(simpleSem, &cmdPktSetFiber);
|
||||
fiber_sem_give(simpleSem);
|
||||
|
||||
/* release the semaphore for N_TESTS times */
|
||||
nano_fiber_sem_take_wait(&fiberSem);
|
||||
for (i = 0; i < N_TESTS; i++) {
|
||||
fiber_sem_give(simpleSem, &cmdPktSetFiber);
|
||||
fiber_sem_give(simpleSem);
|
||||
}
|
||||
|
||||
/* signal each semaphore in the group */
|
||||
for (i = 0; semList[i] != ENDLIST; i++) {
|
||||
nano_fiber_sem_take_wait(&fiberSem);
|
||||
fiber_sem_give(semList[i], &cmdPktSetFiber);
|
||||
fiber_sem_give(semList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue