2 Star 14 Fork 10

cot软件包 / cotOs

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
cot_os.c 16.47 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612
/**
**********************************************************************************************************************
* @file cot_os.c
* @brief 该文件提供查询协作式多任务系统功能
* @author const_zpc any question please send mail to const_zpc@163.com
* @version V1.0.0
* @date 2024-02-04
*
* @details 功能详细说明:
* + 任务调度初始化
* + 任务调度功能启动
* + 该任务调度并非抢占式
*
**********************************************************************************************************************
* 源码路径:https://gitee.com/cot_package/cot_os.git 具体问题及建议可在该网址填写 Issue
*
* 使用方式:
* 1. 使用前初始化函数 cotOs_Init
* 2. 通过 cotOs_Creat 添加任务函数
* 3. 主函数调用 cotOs_Start 启动任务调度, 函数不会退出
* 4. 使用 cotOs_Wait 切换到下一个任务执行
*
**********************************************************************************************************************
*/
/* Includes ----------------------------------------------------------------------------------------------------------*/
#pragma GCC push_options
#pragma GCC optimize("O0")
#include <stdbool.h>
#include "cot_os_config.h"
#include <setjmp.h>
// #pragma GCC pop_options
#include "cot_os.h"
/* Private typedef ---------------------------------------------------------------------------------------------------*/
#if (COT_OS_MAX_TASK > 32)
#error "task max num can't over 32"
#endif
typedef struct stTCB
{
uint8_t *pBakStack;
uint8_t state : 2;
uint8_t joinWaitCnt :6;
CotOSCondition_t cond;
CotOSStackType_e eStackType;
uint32_t nextRunTime;
int param;
jmp_buf env;
size_t bakStackSize;
size_t stackTopAddr;
cotOsTask_f pfnOsTaskEnter;
CotOSCondition_t *pCondition;
struct stTCB *pNext;
} TCB_t;
/**
* @brief 中断任务信息结构体定义
*/
typedef struct
{
cotOsGetSysTime_f pfnGetTimerMs; /*!< 获取毫秒级别的时间回调函数 */
TCB_t *pCurTCB;
TCB_t *pTCBList;
uint32_t tcbMask;
jmp_buf env;
jmp_buf envResume;
uint8_t *pFreeBakStack;
} OsInfo_t;
/* Private define ----------------------------------------------------------------------------------------------------*/
#define COMMON_TASK_INTI 0
#define COMMON_TASK_RUN_NEXT 1
#define COMMON_TASK_RUN 2
#define MAIN_TASK_INTI 0
#define MAIN_TASK_EXIT 1
#define BACKUP_TASK_INTI 0
#define BACKUP_TASK_RUN 1
#define RESUME_TASK_INTI 0
#define RESUME_TASK_RUN 1
#define TASK_STATUS_READY 0
#define TASK_STATUS_RUNNING 1
#define TASK_STATUS_SUSPEND 2
#define TASK_STATUS_DELETED 3
/* Private macro -----------------------------------------------------------------------------------------------------*/
/* Private variables -------------------------------------------------------------------------------------------------*/
static OsInfo_t sg_OsInfo;
static TCB_t sg_TCB[COT_OS_MAX_TASK];
static uint8_t sg_sharedTaskStack[COT_OS_SHARED_STACK_BAK_SIZE];
static uint32_t sg_copyStack[512];
/* Private function prototypes ---------------------------------------------------------------------------------------*/
static TCB_t *CreatTCB(OsInfo_t *pObj);
static void DestroyTCB(OsInfo_t *pObj);
static void AddToTCBTaskList(OsInfo_t *pObj, TCB_t *pNewTCB);
static void DeleteFromTCBTaskList(OsInfo_t *pObj);
static void BackupCurTaskStack(void);
static void ResumeCurTaskStack(void);
static void JumpNextTask(OsInfo_t *pObj);
/* Private function --------------------------------------------------------------------------------------------------*/
static void tcbMemcpy(uint8_t *pdest, uint8_t *psrc, size_t length)
{
while (length--)
{
*pdest = *psrc;
pdest++;
psrc++;
}
}
static TCB_t *CreatTCB(OsInfo_t *pObj)
{
for (int i = 0; i < COT_OS_MAX_TASK; i++)
{
if (!((pObj->tcbMask >> i) & 0x01))
{
pObj->tcbMask |= (0x1 << i);
return &sg_TCB[i];
}
}
return NULL;
}
static void DestroyTCB(OsInfo_t *pObj)
{
for (int i = 0; i < COT_OS_MAX_TASK; i++)
{
if (&sg_TCB[i] == pObj->pCurTCB)
{
pObj->tcbMask &= ~(0x1 << i);
break;
}
}
}
static void AddToTCBTaskList(OsInfo_t *pObj, TCB_t *pNewTCB)
{
if (pObj->pTCBList == NULL)
{
pObj->pTCBList = pNewTCB;
pObj->pTCBList->pNext = pObj->pTCBList;
}
else
{
TCB_t *pTCB = pObj->pTCBList;
while (pTCB->pNext != NULL && pTCB->pNext != pObj->pTCBList)
{
pTCB = pTCB->pNext;
}
pNewTCB->pNext = pTCB->pNext;
pTCB->pNext = pNewTCB;
}
}
static void DeleteFromTCBTaskList(OsInfo_t *pObj)
{
TCB_t *pTCB = pObj->pTCBList;
if (pTCB->pNext == pObj->pTCBList)
{
pObj->pTCBList = NULL;
}
else
{
while (pTCB->pNext != pObj->pTCBList)
{
if (pTCB->pNext == pObj->pCurTCB)
{
break;
}
pTCB = pTCB->pNext;
}
pTCB->pNext = pObj->pCurTCB->pNext;
if (pObj->pCurTCB == pObj->pTCBList)
{
pObj->pTCBList = pObj->pCurTCB->pNext;
}
}
}
static uint8_t GetTaskNum(OsInfo_t *pObj)
{
uint8_t num = 0;
TCB_t *pTCB = sg_OsInfo.pTCBList;
if (pTCB == NULL)
{
return 0;
}
do {
if (pTCB->state != TASK_STATUS_DELETED)
{
num++;
}
pTCB = pTCB->pNext;
} while (pTCB != sg_OsInfo.pTCBList);
return num;
}
/**
* @brief 初始化协程OS系统
*
* @attention 回调函数不可为NULL
* @param pfOsTimer 获取毫秒级别的时间回调函数
*/
void cotOs_Init(cotOsGetSysTime_f pfnOsTimer)
{
sg_OsInfo.pfnGetTimerMs = pfnOsTimer;
sg_OsInfo.pTCBList = NULL;
sg_OsInfo.pCurTCB = NULL;
sg_OsInfo.tcbMask = 0;
sg_OsInfo.pFreeBakStack = sg_sharedTaskStack;
}
static void MallocBakStack(OsInfo_t *pObj, size_t length)
{
if ((&sg_sharedTaskStack[COT_OS_SHARED_STACK_BAK_SIZE] - pObj->pFreeBakStack) < length)
{
while (1){} // 剩余共享栈任务的共享备份栈内存大小不足够申请备份
}
sg_OsInfo.pCurTCB->pBakStack = sg_OsInfo.pFreeBakStack;
sg_OsInfo.pCurTCB->bakStackSize = length;
sg_OsInfo.pFreeBakStack += length;
}
static void FreeBakStack(OsInfo_t *pObj)
{
if (pObj->pCurTCB->pBakStack != NULL)
{
tcbMemcpy(pObj->pCurTCB->pBakStack, pObj->pCurTCB->pBakStack + pObj->pCurTCB->bakStackSize,
pObj->pFreeBakStack - (pObj->pCurTCB->pBakStack + pObj->pCurTCB->bakStackSize));
TCB_t *pTCB = pObj->pTCBList;
do {
if (pTCB != NULL && pTCB->pBakStack > pObj->pCurTCB->pBakStack)
{
pTCB->pBakStack -= pObj->pCurTCB->bakStackSize;
}
pTCB = pTCB->pNext;
} while (pTCB != sg_OsInfo.pTCBList);
pObj->pFreeBakStack -= pObj->pCurTCB->bakStackSize;
pObj->pCurTCB->pBakStack = NULL;
pObj->pCurTCB->bakStackSize = 0;
}
}
// #pragma GCC push_options
// #pragma GCC optimize("O0")
// 在备份运行栈中备份当前任务栈的数据
static void BackupCurTaskStack(void)
{
volatile size_t oldsp;
COT_OS_GET_STACK(oldsp);
if (sg_OsInfo.pCurTCB->eStackType == COT_OS_SHARED_STACK &&
sg_OsInfo.pCurTCB->pBakStack == NULL)
{
MallocBakStack(&sg_OsInfo, sg_OsInfo.pCurTCB->stackTopAddr - oldsp);
}
COT_OS_SET_STACK(((size_t)sg_copyStack + sizeof(sg_copyStack)));
if (BACKUP_TASK_RUN != setjmp(sg_OsInfo.envResume))
{
COT_OS_SET_STACK(oldsp);
longjmp(sg_OsInfo.envResume, BACKUP_TASK_RUN);
}
else
{
/* 在新的栈中进行拷贝 */
if (sg_OsInfo.pCurTCB->eStackType == COT_OS_SHARED_STACK)
{
tcbMemcpy(sg_OsInfo.pCurTCB->pBakStack, (uint8_t *)(sg_OsInfo.pCurTCB->stackTopAddr - sg_OsInfo.pCurTCB->bakStackSize), sg_OsInfo.pCurTCB->bakStackSize);
}
longjmp(sg_OsInfo.pCurTCB->env, COMMON_TASK_RUN_NEXT);
}
}
// 在备份运行栈中还原当前任务栈的数据
static void ResumeCurTaskStack(void)
{
volatile size_t oldsp;
COT_OS_GET_STACK(oldsp);
COT_OS_SET_STACK(((size_t)sg_copyStack + sizeof(sg_copyStack)));
if (RESUME_TASK_RUN != setjmp(sg_OsInfo.envResume))
{
COT_OS_SET_STACK(oldsp);
longjmp(sg_OsInfo.envResume, RESUME_TASK_RUN);
}
else
{
/* 在新的栈中进行拷贝并完成下一个任务的切换,避免共享栈之间切换任务时拷贝后被破坏 */
if (sg_OsInfo.pCurTCB->eStackType == COT_OS_SHARED_STACK)
{
tcbMemcpy((uint8_t *)(sg_OsInfo.pCurTCB->stackTopAddr - sg_OsInfo.pCurTCB->bakStackSize), sg_OsInfo.pCurTCB->pBakStack, sg_OsInfo.pCurTCB->bakStackSize);
}
longjmp(sg_OsInfo.pCurTCB->env, COMMON_TASK_RUN);
}
}
static void DestoryTask(OsInfo_t *pObj)
{
if (pObj->pCurTCB->state == TASK_STATUS_DELETED && pObj->pCurTCB->joinWaitCnt == 0)
{
FreeBakStack(&sg_OsInfo);
DeleteFromTCBTaskList(&sg_OsInfo);
DestroyTCB(&sg_OsInfo);
}
}
/**
* @brief 创建任务
*
* @attention 若选择共享栈,则使用`cotOs_Wait`和`cotOs_ConditionWait`仅限于在任务函数中使用,禁止在任务函数中的嵌套函数中使用
* @attention 同一个栈空间不能同时设置为共享栈和独立栈,即共享栈任务和独立栈任务不能使用相同的栈空间
* @note 独立栈任务必须有不同的栈空间,而共享栈任务可以有相同的栈空间
* @param pfnOsTaskEnter 任务函数
* @param eStackType 栈类型选择
* @param pStack 栈空间
* @param stackSize 栈空间大小
* @param arg 参数
* @return 任务句柄, 为NULL则创建失败
*/
cotOsTask_t cotOs_CreatTask(cotOsTask_f pfnOsTaskEnter, CotOSStackType_e eStackType, void *pStack, size_t stackSize, int arg)
{
size_t oldsp;
TCB_t *pNewTCB;
if (pStack == NULL || stackSize == 0 || sg_OsInfo.pfnGetTimerMs == NULL)
{
return NULL;
}
COT_OS_GET_STACK(oldsp);
pNewTCB = CreatTCB(&sg_OsInfo);
if (NULL != pNewTCB)
{
/* 解决在共享栈中使用同一个共享栈创建任务时异常的问题 */
if (sg_OsInfo.pCurTCB != NULL && sg_OsInfo.pCurTCB->eStackType == COT_OS_SHARED_STACK)
{
if (COMMON_TASK_RUN_NEXT != setjmp(sg_OsInfo.pCurTCB->env))
{
BackupCurTaskStack();
}
}
COT_OS_SET_STACK(((size_t)pStack + stackSize));
if (COMMON_TASK_INTI == setjmp(pNewTCB->env))
{
COT_OS_SET_STACK(oldsp);
pNewTCB->pfnOsTaskEnter = pfnOsTaskEnter;
pNewTCB->param = arg;
pNewTCB->stackTopAddr = (size_t)pStack + stackSize;
pNewTCB->eStackType = eStackType;
pNewTCB->pNext = NULL;
pNewTCB->state = TASK_STATUS_READY;
pNewTCB->bakStackSize = 0;
pNewTCB->pBakStack = NULL;
pNewTCB->pCondition = NULL;
pNewTCB->nextRunTime = 0;
pNewTCB->joinWaitCnt = 0;
cotOs_ConditionInit(&pNewTCB->cond);
AddToTCBTaskList(&sg_OsInfo, pNewTCB);
}
else
{
sg_OsInfo.pCurTCB->state = TASK_STATUS_RUNNING;
sg_OsInfo.pCurTCB->pfnOsTaskEnter(sg_OsInfo.pCurTCB->param);
sg_OsInfo.pCurTCB->state = TASK_STATUS_DELETED;
cotOs_ConditionNotify(&sg_OsInfo.pCurTCB->cond);
DestoryTask(&sg_OsInfo);
if (GetTaskNum(&sg_OsInfo) > 0)
{
JumpNextTask(&sg_OsInfo);
}
else
{
longjmp(sg_OsInfo.env, MAIN_TASK_EXIT);
}
}
/* 解决在共享栈中使用同一个共享栈创建任务时异常的问题 */
if (sg_OsInfo.pCurTCB != NULL && sg_OsInfo.pCurTCB->eStackType == COT_OS_SHARED_STACK)
{
if (COMMON_TASK_RUN != setjmp(sg_OsInfo.pCurTCB->env))
{
ResumeCurTaskStack();
}
}
}
return pNewTCB;
}
/**
* @brief 启动协程OS任务
*
* @attention 该函数不会退出, 因此一切准备就绪后最后调用该函数即可
* @return 0,成功; -1,失败
*/
int cotOs_Start(void)
{
if (sg_OsInfo.pTCBList == NULL || sg_OsInfo.pfnGetTimerMs == NULL)
{
return -1;
}
if (MAIN_TASK_EXIT != setjmp(sg_OsInfo.env))
{
sg_OsInfo.pCurTCB = sg_OsInfo.pTCBList;
longjmp(sg_OsInfo.pCurTCB->env, COMMON_TASK_RUN);
}
return 0;
}
static void JumpNextTask(OsInfo_t *pObj)
{
if (pObj->pTCBList != NULL)
{
while (1)
{
TCB_t *pTCB = pObj->pTCBList;
do {
if (pTCB->state != TASK_STATUS_DELETED &&
((pTCB->nextRunTime != 0 && pObj->pfnGetTimerMs() > pTCB->nextRunTime) ||
(pTCB->pCondition != NULL && pTCB->pCondition->flag == 1)))
{
pTCB->state = TASK_STATUS_READY;
}
pTCB = pTCB->pNext;
} while (pTCB != pObj->pTCBList);
do {
if (pTCB->pCondition != NULL)
pTCB->pCondition->flag = 0;
pTCB = pTCB->pNext;
} while (pTCB != pObj->pTCBList);
pTCB = pObj->pCurTCB->pNext;
do {
if (pTCB->state == TASK_STATUS_READY)
{
pObj->pCurTCB = pTCB;
pObj->pCurTCB->state = TASK_STATUS_RUNNING;
ResumeCurTaskStack();
}
pTCB = pTCB->pNext;
} while (pTCB != pObj->pCurTCB->pNext);
}
}
}
/**
* @brief 任务阻塞等待时间结束
*
* @note 等待n毫秒时长, 则会在 >= n 后的某个时刻才会运行, 具体要看其他协程任务什么时候让出资源
* @param time 等待时长,单位毫秒
*/
void cotOs_Wait(uint32_t time)
{
sg_OsInfo.pCurTCB->nextRunTime = sg_OsInfo.pfnGetTimerMs() + time;
sg_OsInfo.pCurTCB->pCondition = NULL;
sg_OsInfo.pCurTCB->state = TASK_STATUS_SUSPEND;
int ret = setjmp(sg_OsInfo.pCurTCB->env);
if (COMMON_TASK_INTI == ret)
{
BackupCurTaskStack();
}
else if (COMMON_TASK_RUN_NEXT == ret)
{
JumpNextTask(&sg_OsInfo);
}
}
/**
* @brief 等待任务退出
*
* @param task cotOs_CreatTask 返回的值
*/
void cotOs_Join(cotOsTask_t task)
{
TCB_t *pTaskTCB = (TCB_t *)task;
TCB_t *pTCB = sg_OsInfo.pTCBList;
if (NULL != pTaskTCB)
{
do {
if (pTCB == pTaskTCB && pTaskTCB->state != TASK_STATUS_DELETED)
{
pTCB->joinWaitCnt++;
cotOs_ConditionWait(&pTaskTCB->cond);
pTCB->joinWaitCnt--;
DestoryTask(&sg_OsInfo);
break;
}
pTCB = pTCB->pNext;
} while (pTCB != sg_OsInfo.pTCBList);
}
}
/**
* @brief 条件事件初始化
*
* @param pCondition 条件事件
*/
void cotOs_ConditionInit(CotOSCondition_t *pCondition)
{
if (pCondition == NULL)
{
return;
}
pCondition->flag = 0;
}
/**
* @brief 任务阻塞等待条件事件发生
*
* @note 等待条件事件发生, 则会在条件事件发生后的某个时刻才会运行, 具体要看其他协程任务什么时候让出资源
* @param pCondition 条件事件
*/
void cotOs_ConditionWait(CotOSCondition_t *pCondition)
{
if (pCondition == NULL)
{
return;
}
sg_OsInfo.pCurTCB->nextRunTime = 0;
sg_OsInfo.pCurTCB->pCondition = pCondition;
sg_OsInfo.pCurTCB->state = TASK_STATUS_SUSPEND;
int ret = setjmp(sg_OsInfo.pCurTCB->env);
if (COMMON_TASK_INTI == ret)
{
BackupCurTaskStack();
}
else if (COMMON_TASK_RUN_NEXT == ret)
{
JumpNextTask(&sg_OsInfo);
}
}
/**
* @brief 触发条件事件
*
* @param pCondition 条件事件
*/
void cotOs_ConditionNotify(CotOSCondition_t *pCondition)
{
if (pCondition == NULL)
{
return;
}
pCondition->flag = 1;
}
#pragma GCC pop_options
C
1
https://gitee.com/cot_package/cot_os.git
git@gitee.com:cot_package/cot_os.git
cot_package
cot_os
cotOs
master

搜索帮助