📄 picoos.c
字号:
/*
* Copyright (c) 2004-2005, Dennis Kuschel.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @file picoos.c
* @brief pico]OS core file
* @author Dennis Kuschel
*
* This file is originally from the pico]OS realtime operating system
* (http://picoos.sourceforge.net).
*
* CVS-ID $Id: picoos.c,v 1.15 2006/04/16 08:48:26 dkuschel Exp $
*/
#define _POSCORE_C
#define PICOS_PRIVINCL
#include <picoos.h>
/*---------------------------------------------------------------------------
* MACROS FOR MEMORY ALIGNMENT
*-------------------------------------------------------------------------*/
#if POSCFG_ALIGNMENT < 2
#define ALIGNEDSIZE(size) (size)
#define ALIGNEDBUFSIZE(elemsize, count) ((elemsize)*(count))
#define MEMALIGN(type, var) (type)((void*)(var))
#define NEXTALIGNED(type, var) (((type)((void*)(var))) + 1)
#else
#define ALIGNEDSIZE(size) \
(((size) + (POSCFG_ALIGNMENT - 1)) & ~(POSCFG_ALIGNMENT - 1))
#define ALIGNEDBUFSIZE(elemsize, count) \
(ALIGNEDSIZE(elemsize)*(count) + (POSCFG_ALIGNMENT - 1))
#define MEMALIGN(type, var) (type)((void*) \
((((MEMPTR_t)(var))+POSCFG_ALIGNMENT-1)&~(POSCFG_ALIGNMENT-1)))
#define NEXTALIGNED(type, var) \
(type)((void*)(((MEMPTR_t)(var)) + ALIGNEDSIZE(sizeof(*(var)))))
#endif /* POSCFG_ALIGNMENT */
#define STATICBUFFER(glblvar, size, count) static UVAR_t \
glblvar[((ALIGNEDSIZE(size)*count) + POSCFG_ALIGNMENT + sizeof(UVAR_t)-2) \
/ sizeof(UVAR_t)]
/*---------------------------------------------------------------------------
* LOCAL TYPES AND VARIABLES
*-------------------------------------------------------------------------*/
typedef struct TBITS {
UVAR_t xtable[SYS_TASKTABSIZE_Y];
#if SYS_TASKTABSIZE_Y > 1
UVAR_t ymask;
#endif
} TBITS_t;
#if SYS_FEATURE_EVENTS != 0
typedef union EVENT {
struct {
#if POSCFG_ARGCHECK > 1
UVAR_t magic;
#endif
union EVENT *next;
} l;
struct {
#if POSCFG_ARGCHECK > 1
UVAR_t magic;
#endif
union {
INT_t counter;
#if POSCFG_FEATURE_FLAGS != 0
UVAR_t flags;
#endif
} d;
TBITS_t pend;
#if POSCFG_FEATURE_MUTEXES != 0
POSTASK_t task;
#endif
#ifdef POS_DEBUGHELP
struct PICOEVENT deb;
#endif
} e;
} *EVENT_t;
static EVENT_t posFreeEvents_g;
#if (POSCFG_DYNAMIC_MEMORY == 0) && \
((POSCFG_MAX_EVENTS + SYS_MSGBOXEVENTS) != 0)
STATICBUFFER(posStaticEventMem_g, sizeof(union EVENT), \
(POSCFG_MAX_EVENTS + SYS_MSGBOXEVENTS));
#endif
#endif /* SYS_FEATURE_EVENTS */
#if POSCFG_FEATURE_MSGBOXES != 0
typedef struct MSGBUF {
#if POSCFG_MSG_MEMORY != 0
unsigned char buffer[POSCFG_MSG_BUFSIZE];
#else
void *bufptr;
#endif
#if POSCFG_ARGCHECK > 1
UVAR_t magic;
#endif
struct MSGBUF *next;
} MSGBUF_t;
static POSSEMA_t msgAllocSyncSem_g;
static POSSEMA_t msgAllocWaitSem_g;
static UVAR_t msgAllocWaitReq_g;
static MSGBUF_t *posFreeMessagebuf_g;
#if (POSCFG_DYNAMIC_MEMORY == 0) && (POSCFG_MAX_MESSAGES != 0)
STATICBUFFER(posStaticMessageMem_g, sizeof(MSGBUF_t), POSCFG_MAX_MESSAGES);
#endif
#endif /* POSCFG_FEATURE_MSGBOXES */
#if POSCFG_FEATURE_TIMER != 0
typedef struct TIMER {
#if POSCFG_ARGCHECK > 1
UVAR_t magic;
#endif
struct TIMER *prev;
struct TIMER *next;
POSSEMA_t sema;
UINT_t counter;
UINT_t wait;
UINT_t reload;
#if POSCFG_FEATURE_TIMERFIRED != 0
VAR_t fired;
#endif
} TIMER_t;
static TIMER_t *posFreeTimer_g;
static TIMER_t *posActiveTimers_g;
#if (POSCFG_DYNAMIC_MEMORY == 0) && (POSCFG_MAX_TIMER != 0)
STATICBUFFER(posStaticTmrMem_g, sizeof(TIMER_t), POSCFG_MAX_TIMER);
#endif
#endif /* POSCFG_FEATURE_TIMER */
#if POSCFG_FEATURE_JIFFIES != 0
#if POSCFG_FEATURE_LARGEJIFFIES == 0
volatile JIF_t jiffies;
#else
static volatile JIF_t pos_jiffies_g;
#endif
#endif /* POSCFG_FEATURE_JIFFIES */
static UVAR_t posMustSchedule_g;
static TBITS_t posReadyTasks_g;
static TBITS_t posAllocatedTasks_g;
static POSTASK_t posSleepingTasks_g;
static POSTASK_t posFreeTasks_g;
static POSTASK_t posTaskTable_g[SYS_TASKTABSIZE_X * SYS_TASKTABSIZE_Y];
#if POSCFG_CTXSW_COMBINE > 1
static UVAR_t posCtxCombineCtr_g;
#endif
#if POSCFG_FEATURE_INHIBITSCHED != 0
static UVAR_t posInhibitSched_g;
#endif
#if POSCFG_FEATURE_IDLETASKHOOK != 0
static POSIDLEFUNC_t posIdleTaskFuncHook_g;
#endif
#if (POSCFG_DYNAMIC_MEMORY == 0) && (POSCFG_MAX_TASKS != 0)
STATICBUFFER(posStaticTaskMem_g, sizeof(struct POSTASK), POSCFG_MAX_TASKS);
#endif
#if POSCFG_FEATURE_SOFTINTS != 0
static struct {
UVAR_t intno;
UVAR_t param;
} softintqueue_g[POSCFG_SOFTINTQUEUELEN + 1];
static POSINTFUNC_t softIntHandlers_g[POSCFG_SOFTINTERRUPTS];
static UVAR_t sintIdxIn_g;
static UVAR_t sintIdxOut_g;
#endif /* POSCFG_FEATURE_SOFTINTS */
#if MVAR_BITS == 8
UVAR_t posShift1lTab_g[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
#endif
/*-------------------------------------------------------------------------
* ARGUMENT CHECKING (3 different levels possible)
*-------------------------------------------------------------------------*/
#if MVAR_BITS == 8
#define POSMAGIC_TASK 0x4E
#define POSMAGIC_EVENTU 0x53
#define POSMAGIC_MSGBUF 0x7F
#define POSMAGIC_TIMER 0x14
#elif MVAR_BITS == 16
#define POSMAGIC_TASK 0x4E56
#define POSMAGIC_EVENTU 0x538E
#define POSMAGIC_MSGBUF 0x7FC4
#define POSMAGIC_TIMER 0x1455
#else
#define POSMAGIC_TASK 0x4E56A3FC
#define POSMAGIC_EVENTU 0x538EC75B
#define POSMAGIC_MSGBUF 0x7FC45AA2
#define POSMAGIC_TIMER 0x14552384
#endif
#define POSMAGIC_EVENTF (~POSMAGIC_EVENTU)
#if POSCFG_ARGCHECK == 0
#define POS_ARGCHECK_RET(ptr, pmagic, magic, ret) \
do { } while(0)
#define POS_ARGCHECK(ptr, pmagic, magic) \
do { } while(0)
#elif POSCFG_ARGCHECK == 1
#define POS_ARGCHECK_RET(ptr, pmagic, magic, ret) \
if ((ptr) == NULL) return (ret)
#define POS_ARGCHECK(ptr, pmagic, magic) \
if ((ptr) == NULL) return
#else
#define POS_ARGCHECK_RET(ptr, pmagic, magic, ret) \
if (((ptr) == NULL) || (pmagic != magic)) return (ret)
#define POS_ARGCHECK(ptr, pmagic, magic) \
if (((ptr) == NULL) || (pmagic != magic)) return
#endif
/*---------------------------------------------------------------------------
* ROUND ROBIN
*-------------------------------------------------------------------------*/
#if POSCFG_ROUNDROBIN != 0
static UVAR_t posNextRoundRobin_g[SYS_TASKTABSIZE_Y];
#define POS_NEXTROUNDROBIN(idx) posNextRoundRobin_g[idx]
#else /* ROUNDROBIN */
#define POS_NEXTROUNDROBIN(idx) 0
#endif /* ROUNDROBIN */
/*---------------------------------------------------------------------------
* PROTOTYPES OF PRIVATE FUNCTIONS
*-------------------------------------------------------------------------*/
static void pos_schedule(void);
static void pos_idletask(void *arg);
#if SYS_FEATURE_EVENTS != 0
static VAR_t pos_sched_event(EVENT_t ev);
#endif
#if (POSCFG_FEATURE_MSGBOXES != 0) && (POSCFG_MSG_MEMORY == 0)
static MSGBUF_t* pos_msgAlloc(void);
static void pos_msgFree(MSGBUF_t *mbuf);
#endif
#if POSCFG_FEATURE_SOFTINTS != 0
static void pos_execSoftIntQueue(void);
#endif
#if POSCFG_FEATURE_LISTS != 0
#if POSCFG_FEATURE_LISTJOIN != 0
static void pos_listJoin(POSLIST_t *prev, POSLIST_t *next,
POSLIST_t *newlist);
#endif
static void pos_listRemove(POSLIST_t *listelem);
#endif
/*---------------------------------------------------------------------------
* MACROS
*-------------------------------------------------------------------------*/
#ifndef POS_IRQ_DISABLE_ALL
#define POS_IRQ_DISABLE_ALL POS_SCHED_LOCK
#define POS_IRQ_ENABLE_ALL POS_SCHED_UNLOCK
#else
#define HAVE_IRQ_DISABLE_ALL
#endif
#ifdef POS_DEBUGHELP
#define tasktimerticks(task) (task)->deb.timeout
#define cleartimerticks(task) (task)->deb.timeout = 0
#else
#define tasktimerticks(task) (task)->ticks
#define cleartimerticks(task) do { } while(0)
#endif
#if (POSCFG_FEATURE_YIELD != 0) && \
(POSCFG_ROUNDROBIN != 0) && (SYS_TASKTABSIZE_Y != 1)
#if (MVAR_BITS == 8)
static UVAR_t posZeroMask_g[7] = {0xFE,0xFC,0xF8,0xF0,0xE0,0xC0,0x80};
#define pos_zmask(x) posZeroMask_g[(UVAR_t)(x)]
#else
#define pos_zmask(x) (~((pos_shift1l((x) + 1)) - 1))
#endif
#endif
#if SYS_TASKTABSIZE_Y > 1
#define pos_setTableBit(table, task) do { \
(table)->ymask |= (task)->bit_y; \
(table)->xtable[(task)->idx_y] |= (task)->bit_x; } while(0)
#define pos_delTableBit(table, task) do { \
UVAR_t tbt; \
tbt = (table)->xtable[(task)->idx_y] & ~(task)->bit_x; \
(table)->xtable[(task)->idx_y] = tbt; \
if (tbt == 0) (table)->ymask &= ~(task)->bit_y; } while(0)
#define pos_isTableBitSet(table, task) \
(((table)->xtable[(task)->idx_y] & (task)->bit_x) != 0)
#else
#define pos_setTableBit(table, task) do { \
(table)->xtable[0] |= (task)->bit_x; } while(0)
#define pos_delTableBit(table, task) do { \
(table)->xtable[0] &= ~(task)->bit_x;} while(0)
#define pos_isTableBitSet(table, task) \
(((table)->xtable[0] & (task)->bit_x) != 0)
#endif
#define pos_addToList(list, elem) do { \
(elem)->prev = NULL; \
(elem)->next = list; \
if (list != NULL) list->prev = elem; \
list = elem; } while(0)
#define pos_removeFromList(list, elem) do { \
if ((elem)->next != NULL) (elem)->next->prev = (elem)->prev; \
if ((elem)->prev != NULL) (elem)->prev->next = (elem)->next; \
else list = (elem)->next; } while(0)
#if POSCFG_FEATURE_SOFTINTS != 0
#define softIntsPending() (sintIdxIn_g != sintIdxOut_g)
#define pos_doSoftInts() \
if (softIntsPending()) pos_execSoftIntQueue();
#else
#define pos_doSoftInts() do { } while(0);
#endif /* POSCFG_FEATURE_SOFTINTS */
#ifndef HOOK_IDLETASK
#define HOOK_IDLETASK
#endif
#ifdef POS_DEBUGHELP
#define pos_taskHistory(debtask) do { \
picodeb_taskhistory[2] = picodeb_taskhistory[1]; \
picodeb_taskhistory[1] = picodeb_taskhistory[0]; \
picodeb_taskhistory[0] = debtask; \
} while(0)
#else
#define pos_taskHistory(debtask) do { } while(0);
#endif
/*---------------------------------------------------------------------------
* some HELPER FUNCTIONS (can be inlined)
*-------------------------------------------------------------------------*/
#if SYS_TASKDOUBLELINK == 0
#define pos_addToSleepList(task) do { \
(task)->next = posSleepingTasks_g; \
posSleepingTasks_g = task; } while(0)
#endif
#if SYS_FEATURE_EVENTS != 0
#if ((POSCFG_FASTCODE==0) || defined(POS_DEBUGHELP)) && (SYS_EVENTS_USED!=0)
static void pos_eventAddTask(EVENT_t ev, POSTASK_t task);
static void pos_eventAddTask(EVENT_t ev, POSTASK_t task)
{
#ifdef POS_DEBUGHELP
task->deb.event = &ev->e.deb;
#endif
pos_setTableBit(&ev->e.pend, task);
}
static void pos_eventRemoveTask(EVENT_t ev, POSTASK_t task);
static void pos_eventRemoveTask(EVENT_t ev, POSTASK_t task)
{
#ifdef POS_DEBUGHELP
task->deb.event = NULL;
#endif
pos_delTableBit(&ev->e.pend, task);
}
#else
#define pos_eventAddTask(event, curtask) \
pos_setTableBit(&((event)->e.pend), curtask)
#define pos_eventRemoveTask(event, curtask) \
pos_delTableBit(&((event)->e.pend), curtask)
#endif
#endif /* SYS_FEATURE_EVENTS */
#if POSCFG_FASTCODE != 0
#define pos_enableTask(task) pos_setTableBit(&posReadyTasks_g, task)
#define pos_disableTask(task) pos_delTableBit(&posReadyTasks_g, task)
#if SYS_TASKDOUBLELINK != 0
#define pos_addToSleepList(task) \
pos_addToList(posSleepingTasks_g, task)
#define pos_removeFromSleepList(task) \
pos_removeFromList(posSleepingTasks_g, task)
#endif /* SYS_TASKDOUBLELINK */
#if POSCFG_FEATURE_TIMER != 0
#define pos_addToTimerList(timer) \
pos_addToList(posActiveTimers_g, timer)
#define pos_removeFromTimerList(timer) do { \
pos_removeFromList(posActiveTimers_g, timer); \
timer->prev = timer; } while (0)
#endif /* POSCFG_FEATURE_TIMER */
#else /* POSCFG_FASTCODE */
static void pos_disableTask(POSTASK_t task);
static void pos_disableTask(POSTASK_t task)
{
pos_delTableBit(&posReadyTasks_g, task);
}
static void pos_enableTask(POSTASK_t task);
static void pos_enableTask(POSTASK_t task)
{
pos_setTableBit(&posReadyTasks_g, task);
}
#if SYS_TASKDOUBLELINK != 0
static void pos_addToSleepList(POSTASK_t task);
static void pos_addToSleepList(POSTASK_t task)
{
pos_addToList(posSleepingTasks_g, task);
}
static void pos_removeFromSleepList(POSTASK_t task);
static void pos_removeFromSleepList(POSTASK_t task)
{
pos_removeFromList(posSleepingTasks_g, task);
}
#endif /* SYS_TASKDOUBLELINK */
#if POSCFG_FEATURE_TIMER != 0
static void pos_addToTimerList(TIMER_t *timer);
static void pos_addToTimerList(TIMER_t *timer)
{
pos_addToList(posActiveTimers_g, timer);
}
static void pos_removeFromTimerList(TIMER_t *timer);
static void pos_removeFromTimerList(TIMER_t *timer)
{
pos_removeFromList(posActiveTimers_g, timer);
timer->prev = timer;
}
#endif /* POSCFG_FEATURE_TIMER */
#endif /* POSCFG_FASTCODE */
/*---------------------------------------------------------------------------
* PRIVATE FUNCTIONS
*-------------------------------------------------------------------------*/
#ifdef POS_DEBUGHELP
void posdeb_setEventName(void *event, const char *name)
{
EVENT_t ev = (EVENT_t) event;
if (ev != NULL) ev->e.deb.name = name;
}
#endif
#if POSCFG_FEATURE_LISTS != 0
#if POSCFG_FEATURE_LISTJOIN != 0
static void pos_listJoin(POSLIST_t *prev, POSLIST_t *next,
POSLIST_t *newlist)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -