1 Star 0 Fork 51

xiaoY/Open-NPStack

forked from onps协议栈/Open-NPStack 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
one_shot_timer.c 19.18 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559
/*
* 版权属于onps栈开发团队,遵循Apache License 2.0开源许可协议
*
*/
#include "port/datatype.h"
#include "port/sys_config.h"
#include "onps_errors.h"
#include "port/os_datatype.h"
#include "port/os_adapter.h"
#include "mmu/buddy.h"
#include "onps_utils.h"
#include "onps_input.h"
#define SYMBOL_GLOBALS
#include "one_shot_timer.h"
#undef SYMBOL_GLOBALS
#include "ip/tcp_link.h"
#include "ip/tcp.h"
typedef struct _ST_ONESHOTTIMER_ { //* 定时器
PST_ONESHOTTIMER pstNext;
PFUN_ONESHOTTIMEOUT_HANDLER pfunTimeoutHandler;
void *pvParam;
INT nTimeoutCount; //* 溢出值,单位:秒
} ST_ONESHOTTIMER, *PST_ONESHOTTIMER;
static HMUTEX l_hMtxFreeOneShotTimer; //* 可用定时器链表同步锁
static HMUTEX l_hMtxOneShotTimer; //* 正在计时的定时器链表同步锁
static ST_ONESHOTTIMER l_staOneShotTimerNode[ONE_SHOT_TIMER_NUM];
static PST_ONESHOTTIMER l_pstFreeOneShotTimerLink;
static PST_ONESHOTTIMER l_pstOneShotTimerLink = NULL;
static BOOL l_blIsRunning = TRUE;
static UCHAR l_ubThreadExitFlag = TRUE;
//* 定时器初始化(栈开始工作前必须要先调用这个函数进行定时器初始化)
BOOL one_shot_timer_init(EN_ONPSERR *penErr)
{
INT i;
for (i = 0; i < ONE_SHOT_TIMER_NUM - 1; i++) //* 将定时器链表链接起来
{
l_staOneShotTimerNode[i].pstNext = &l_staOneShotTimerNode[i + 1];
}
l_staOneShotTimerNode[ONE_SHOT_TIMER_NUM - 1].pstNext = NULL; //* 最后一个节点单独赋值
l_pstFreeOneShotTimerLink = &l_staOneShotTimerNode[0]; //* 接入链表头,形成真正的链表
do {
#if 1
//* 建立可用定时器队列同步锁
l_hMtxFreeOneShotTimer = os_thread_mutex_init();
if (INVALID_HMUTEX == l_hMtxFreeOneShotTimer)
{
*penErr = ERRMUTEXINITFAILED;
break;
}
//* 建立已开启计时的定时器队列同步锁
l_hMtxOneShotTimer = os_thread_mutex_init();
if (INVALID_HMUTEX == l_hMtxOneShotTimer)
{
*penErr = ERRMUTEXINITFAILED;
break;
}
#endif
return TRUE;
} while (FALSE);
if (INVALID_HMUTEX != l_hMtxFreeOneShotTimer)
os_thread_mutex_uninit(l_hMtxFreeOneShotTimer);
return FALSE;
}
//* 定时器去初始化
void one_shot_timer_uninit(void)
{
l_blIsRunning = FALSE;
while (!l_ubThreadExitFlag)
os_sleep_secs(1);
if (INVALID_HMUTEX != l_hMtxFreeOneShotTimer)
os_thread_mutex_uninit(l_hMtxFreeOneShotTimer);
if (INVALID_HMUTEX != l_hMtxOneShotTimer)
os_thread_mutex_uninit(l_hMtxOneShotTimer);
}
//* 结束两个定时器线程,并释放所有工作队列,并归还给系统
void one_shot_timer_stop(void)
{
l_blIsRunning = FALSE;
}
//#if SUPPORT_SACK
//void thread_one_shot_timer_count(void *pvParam)
//{
// PST_ONESHOTTIMER pstTimer, pstPrevTimer, pstNextTimer;
//
// //os_critical_init();
//
// l_ubThreadExitFlag = FALSE;
// while (l_blIsRunning)
// {
// os_thread_mutex_lock(l_hMtxOneShotTimer);
// //os_enter_critical();
// {
// pstNextTimer = l_pstOneShotTimerLink;
// pstPrevTimer = NULL;
// pstTimer = NULL;
// while (pstNextTimer)
// {
// if (pstNextTimer->nTimeoutCount-- <= 0)
// {
// //* 先从计时器队列摘除
// if (pstPrevTimer)
// pstPrevTimer->pstNext = NULL;
// else
// l_pstOneShotTimerLink = NULL;
// pstTimer = pstNextTimer;
// break;
// }
// else //* 计时尚未结束,检查下一个节点
// {
// pstPrevTimer = pstNextTimer;
// pstNextTimer = pstNextTimer->pstNext;
// }
// }
// }
// os_thread_mutex_unlock(l_hMtxOneShotTimer);
// //os_exit_critical();
//
// //* 如果存在溢出节点则开始执行溢出操作
// if (pstTimer)
// {
// pstNextTimer = pstTimer;
// while (pstNextTimer)
// {
// //* 保存当前要操作的定时器并在操作之前推进到下一个溢出定时器
// pstTimer = pstNextTimer;
// pstNextTimer = pstNextTimer->pstNext;
//
// //* 执行溢出函数并归还给系统
// pstTimer->pfunTimeoutHandler(pstTimer->pvParam);
// one_shot_timer_free(pstTimer);
// }
// }
//
// //* 这个休眠可以不用特别精确(1秒左右),我们的应用场景足够了
// os_sleep_secs(1);
// }
//
// //* 回收资源
// os_thread_mutex_lock(l_hMtxOneShotTimer);
// //os_enter_critical();
// {
// pstNextTimer = l_pstOneShotTimerLink;
// while (pstNextTimer)
// {
// //* 先从计时器队列摘除
// pstTimer = pstNextTimer;
// pstNextTimer = pstNextTimer->pstNext;
//
// //* 归还
// one_shot_timer_free(pstTimer);
// }
// }
// os_thread_mutex_unlock(l_hMtxOneShotTimer);
// //os_exit_critical();
//
// l_ubThreadExitFlag = TRUE;
//}
//#else
//* 这并不是一个精确的定时器计时队列,这依赖于休眠精度以及队列长度,但对于我们的应用场景来说已经足够使用
void thread_one_shot_timer_count(void *pvParam)
{
PST_ONESHOTTIMER pstTimer, pstPrevTimer, pstNextTimer;
#if 1
USHORT usTimeCount = 0;
PST_TCPLINK pstNextLink = NULL;
UINT unDelayAckTimeout = TCP_ACK_DELAY_MSECS < 40 || TCP_ACK_DELAY_MSECS > 200 ? 100 - 1 : TCP_ACK_DELAY_MSECS - 1;
#endif
//os_critical_init();
l_ubThreadExitFlag = FALSE;
while (l_blIsRunning)
{
#if SUPPORT_SACK
tcp_send_timer_lock();
{
PSTCB_TCPSENDTIMER pstcbTcpSndTimer = NULL;
do {
pstcbTcpSndTimer = tcp_send_timer_get_next(pstcbTcpSndTimer);
if (pstcbTcpSndTimer)
{
if (pstcbTcpSndTimer->pstLink->bState != TLSCONNECTED)
continue;
//* 是否大于RTO,大于rto则重新发送之
if (os_get_system_msecs() - pstcbTcpSndTimer->unSendMSecs > (UINT)pstcbTcpSndTimer->usRto && pstcbTcpSndTimer->bIsNotSacked)
{
//* 重新发送数据
EN_ONPSERR enErr;
UCHAR *pubData = (UCHAR *)buddy_alloc(pstcbTcpSndTimer->unRight - pstcbTcpSndTimer->unLeft, &enErr);
if (pubData)
{
UINT unStartReadIdx = pstcbTcpSndTimer->unLeft % TCPSNDBUF_SIZE;
UINT unEndReadIdx = pstcbTcpSndTimer->unRight % TCPSNDBUF_SIZE;
if (unEndReadIdx > unStartReadIdx)
memcpy(pubData, pstcbTcpSndTimer->pstLink->stcbSend.pubSndBuf + unStartReadIdx, unEndReadIdx - unStartReadIdx);
else
{
UINT unCpyBytes = TCPSNDBUF_SIZE - unStartReadIdx;
memcpy(pubData, pstcbTcpSndTimer->pstLink->stcbSend.pubSndBuf + unStartReadIdx, unCpyBytes);
memcpy(pubData + unCpyBytes, pstcbTcpSndTimer->pstLink->stcbSend.pubSndBuf, unEndReadIdx);
}
//* 重发dup ack的数据块
tcp_send_data_ext(pstcbTcpSndTimer->pstLink->stcbWaitAck.nInput, pubData, pstcbTcpSndTimer->unRight - pstcbTcpSndTimer->unLeft, pstcbTcpSndTimer->unLeft + 1);
buddy_free(pubData);
//* 每重发一次,rto加倍
if (pstcbTcpSndTimer->usRto < RTO_MAX)
pstcbTcpSndTimer->usRto *= 2;
//* 将timer从当前位置转移到队列的尾部,并重新开启重传计时
pstcbTcpSndTimer->unSendMSecs = os_get_system_msecs();
pstcbTcpSndTimer->bIsNotSacked = TRUE;
tcp_send_timer_node_del_unsafe(pstcbTcpSndTimer);
tcp_send_timer_node_put_unsafe(pstcbTcpSndTimer);
pstcbTcpSndTimer = NULL;
continue;
}
else
{
#if SUPPORT_PRINTF && DEBUG_LEVEL
#if PRINTF_THREAD_MUTEX
os_thread_mutex_lock(o_hMtxPrintf);
#endif
printf("thread_one_shot_timer_count() caught an error, %s\r\n", onps_error(enErr));
#if PRINTF_THREAD_MUTEX
os_thread_mutex_unlock(o_hMtxPrintf);
#endif
#endif
}
}
break; //* 新发送数据的节点会被放到尾部,换言之定时器队列发送时间为递增序列,所以当前节点一旦小于RTO,则后续的亦会小于,不必继续查找了
}
} while (pstcbTcpSndTimer);
}
tcp_send_timer_unlock();
#endif
#if 1
//* 延迟tcp ack处理
tcp_link_lock();
{
do {
pstNextLink = tcp_link_list_used_get_next(pstNextLink);
if (pstNextLink)
{
if (pstNextLink->bState == TLSCONNECTED)
{
if (!pstNextLink->uniFlags.stb16.no_delay_ack && pstNextLink->stPeer.bIsNotAcked)
{
if (os_get_system_msecs() - pstNextLink->stPeer.unStartMSecs > unDelayAckTimeout)
{
tcp_send_ack(pstNextLink, pstNextLink->stLocal.pstAddr->unNetifIp, pstNextLink->stLocal.pstAddr->usPort, pstNextLink->stPeer.stAddr.unIp, pstNextLink->stPeer.stAddr.usPort);
pstNextLink->stPeer.bIsNotAcked = FALSE;
}
}
}
}
} while (pstNextLink);
}
tcp_link_unlock();
if (usTimeCount++ > 999)
{
#endif
os_thread_mutex_lock(l_hMtxOneShotTimer);
//os_enter_critical();
{
pstNextTimer = l_pstOneShotTimerLink;
pstPrevTimer = NULL;
pstTimer = NULL;
while (pstNextTimer)
{
if (--pstNextTimer->nTimeoutCount <= 0)
{
//* 先从计时器队列摘除
if (pstPrevTimer)
pstPrevTimer->pstNext = NULL;
else
l_pstOneShotTimerLink = NULL;
pstTimer = pstNextTimer;
break;
}
else //* 计时尚未结束,检查下一个节点
{
pstPrevTimer = pstNextTimer;
pstNextTimer = pstNextTimer->pstNext;
}
}
}
os_thread_mutex_unlock(l_hMtxOneShotTimer);
//os_exit_critical();
//* 如果存在溢出节点则开始执行溢出操作
if (pstTimer)
{
pstNextTimer = pstTimer;
while (pstNextTimer)
{
//* 保存当前要操作的定时器并在操作之前推进到下一个溢出定时器
pstTimer = pstNextTimer;
pstNextTimer = pstNextTimer->pstNext;
//* 执行溢出函数并归还给系统
pstTimer->pfunTimeoutHandler(pstTimer->pvParam);
one_shot_timer_free(pstTimer);
}
}
#if 0
//* 这个休眠可以不用特别精确(1秒左右),我们的应用场景足够了
os_sleep_secs(1);
#else
usTimeCount = 0;
}
os_sleep_ms(1);
#endif
}
//* 回收资源
os_thread_mutex_lock(l_hMtxOneShotTimer);
//os_enter_critical();
{
pstNextTimer = l_pstOneShotTimerLink;
while (pstNextTimer)
{
//* 先从计时器队列摘除
pstTimer = pstNextTimer;
pstNextTimer = pstNextTimer->pstNext;
//* 归还
one_shot_timer_free(pstTimer);
}
}
os_thread_mutex_unlock(l_hMtxOneShotTimer);
//os_exit_critical();
l_ubThreadExitFlag = TRUE;
}
//#endif
//* 分配一个新的one-shot定时器
PST_ONESHOTTIMER one_shot_timer_new(PFUN_ONESHOTTIMEOUT_HANDLER pfunTimeoutHandler, void *pvParam, INT nTimeoutCount)
{
PST_ONESHOTTIMER pstTimer = NULL;
//os_critical_init();
//* 从可用队列中摘取一个空闲节点
os_thread_mutex_lock(l_hMtxFreeOneShotTimer);
//os_enter_critical();
{
pstTimer = l_pstFreeOneShotTimerLink;
if (l_pstFreeOneShotTimerLink)
l_pstFreeOneShotTimerLink = l_pstFreeOneShotTimerLink->pstNext;
}
os_thread_mutex_unlock(l_hMtxFreeOneShotTimer);
//os_exit_critical();
//* 存在空闲节点则赋值并挂接到计时队列中
if (pstTimer)
{
//* 先赋值再挂载,否则可能导致计数线程出现错误
pstTimer->pfunTimeoutHandler = pfunTimeoutHandler;
pstTimer->pvParam = pvParam;
pstTimer->nTimeoutCount = nTimeoutCount;
//* 挂接到计时队列中,开始计数
os_thread_mutex_lock(l_hMtxOneShotTimer);
//os_enter_critical();
{
//* 按照降序挂载到链表
PST_ONESHOTTIMER pstNextTimer = l_pstOneShotTimerLink;
PST_ONESHOTTIMER pstPrevTimer = NULL;
while (pstNextTimer)
{
if (pstNextTimer->nTimeoutCount > nTimeoutCount)
pstPrevTimer = pstNextTimer;
else
break;
pstNextTimer = pstNextTimer->pstNext;
}
if (pstPrevTimer) //* 说明是中间部分节点
{
pstTimer->pstNext = pstPrevTimer->pstNext;
pstPrevTimer->pstNext = pstTimer;
}
else //* 直接挂载到头部(头部节点计数比新分配的计数要小,直接挂载到头部)
{
pstTimer->pstNext = l_pstOneShotTimerLink;
l_pstOneShotTimerLink = pstTimer;
}
}
os_thread_mutex_unlock(l_hMtxOneShotTimer);
//os_exit_critical();
}
return pstTimer;
}
void one_shot_timer_recount(PST_ONESHOTTIMER pstTimer, INT nTimeoutCount)
{
PST_ONESHOTTIMER pstNextTimer;
//* 必须大于0才可
if (nTimeoutCount <= 0)
return;
//os_critical_init();
//* 确保计时队列中还存在这个节点,否则没必要重计数了
os_thread_mutex_lock(l_hMtxOneShotTimer);
//os_enter_critical();
{
PST_ONESHOTTIMER pstPrevTimer = NULL;
pstNextTimer = l_pstOneShotTimerLink;
while (pstNextTimer)
{
//* 找到了这个节点,则先从中摘除以重新排序
if (pstTimer == pstNextTimer)
{
if (pstPrevTimer)
pstPrevTimer->pstNext = pstTimer->pstNext;
else
l_pstOneShotTimerLink = l_pstOneShotTimerLink->pstNext;
break;
}
pstPrevTimer = pstNextTimer;
pstNextTimer = pstNextTimer->pstNext;
}
//* 如果不为空,意味着匹配,则重新排序后挂载到链表上
if (pstNextTimer)
{
pstTimer->nTimeoutCount = nTimeoutCount;
pstNextTimer = l_pstOneShotTimerLink;
pstPrevTimer = NULL;
while (pstNextTimer)
{
if (pstNextTimer->nTimeoutCount > nTimeoutCount)
pstPrevTimer = pstNextTimer;
else
break;
pstNextTimer = pstNextTimer->pstNext;
}
if (pstPrevTimer) //* 说明是中间部分节点
{
pstTimer->pstNext = pstPrevTimer->pstNext;
pstPrevTimer->pstNext = pstTimer;
}
else //* 直接挂载到头部(头部节点计数比新分配的计数要小,直接挂载到头部)
{
pstTimer->pstNext = l_pstOneShotTimerLink;
l_pstOneShotTimerLink = pstTimer;
}
}
}
os_thread_mutex_unlock(l_hMtxOneShotTimer);
//os_exit_critical();
}
//* 这个函数的目的是安全停止计时器并将其归还给系统,不再占用,与one_shot_timer_free()函数不同
//* ,该函数需要先判断其是否依然还在计数,是,则停止并归还给系统,否则不做任何处理
void one_shot_timer_safe_free(PST_ONESHOTTIMER pstTimer)
{
PST_ONESHOTTIMER pstNextTimer, pstPrevTimer;
BOOL blIsExist = FALSE;
if (NULL == pstTimer)
return;
//os_critical_init();
//* 确保计时队列中还存在这个节点,否则不做任何处理
os_thread_mutex_lock(l_hMtxOneShotTimer);
//os_enter_critical();
{
pstNextTimer = l_pstOneShotTimerLink;
pstPrevTimer = NULL;
while (pstNextTimer)
{
if (pstTimer == pstNextTimer) //* 存在这个定时器,从计时器队列摘除之
{
if (pstPrevTimer)
pstPrevTimer->pstNext = pstTimer->pstNext;
else
l_pstOneShotTimerLink = pstTimer->pstNext;
blIsExist = TRUE;
break;
}
pstPrevTimer = pstNextTimer;
pstNextTimer = pstNextTimer->pstNext;
}
}
os_thread_mutex_unlock(l_hMtxOneShotTimer);
//os_exit_critical();
//* 存在则归还给系统(这里未使用函数调用的方式以减少入栈出栈带来的内存及性能损耗)
if (blIsExist)
{
os_thread_mutex_lock(l_hMtxFreeOneShotTimer);
//os_enter_critical();
{
pstTimer->pstNext = l_pstFreeOneShotTimerLink;
l_pstFreeOneShotTimerLink = pstTimer;
}
os_thread_mutex_unlock(l_hMtxFreeOneShotTimer);
//os_exit_critical();
}
}
//* 释放占用的定时器资源,不做任何判断直接释放并归还给系统
void one_shot_timer_free(PST_ONESHOTTIMER pstTimer)
{
//os_critical_init();
if (NULL == pstTimer)
return;
os_thread_mutex_lock(l_hMtxFreeOneShotTimer);
//os_enter_critical();
{
pstTimer->pstNext = l_pstFreeOneShotTimerLink;
l_pstFreeOneShotTimerLink = pstTimer;
}
os_thread_mutex_unlock(l_hMtxFreeOneShotTimer);
//os_exit_critical();
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C/C++
1
https://gitee.com/yqg.tom/open-npstack.git
[email protected]:yqg.tom/open-npstack.git
yqg.tom
open-npstack
Open-NPStack
master

搜索帮助