-
Notifications
You must be signed in to change notification settings - Fork 2
/
one_shot_timer.c
581 lines (516 loc) · 19.4 KB
/
one_shot_timer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
/*
* Copyright 2022-2024 The Onps Project Author All Rights Reserved.
*
* Author:Neo-T
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* http://www.onps.org.cn/apache2.0.txt
*
*/
#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)
{
if (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
}
}
else
continue;
}
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)
{
#if SUPPORT_IPV6
if(AF_INET == pstNextLink->stLocal.pstHandle->bFamily)
tcp_send_ack(pstNextLink, pstNextLink->stLocal.pstHandle->stSockAddr.saddr_ipv4, pstNextLink->stLocal.pstHandle->stSockAddr.usPort, pstNextLink->stPeer.stSockAddr.saddr_ipv4, pstNextLink->stPeer.stSockAddr.usPort);
else
tcpv6_send_ack(pstNextLink, pstNextLink->stLocal.pstHandle->stSockAddr.saddr_ipv6, pstNextLink->stLocal.pstHandle->stSockAddr.usPort, pstNextLink->stPeer.stSockAddr.saddr_ipv6, pstNextLink->stPeer.stSockAddr.usPort);
#else
tcp_send_ack(pstNextLink, pstNextLink->stLocal.pstHandle->stSockAddr.saddr_ipv4, pstNextLink->stLocal.pstHandle->stSockAddr.usPort, pstNextLink->stPeer.stSockAddr.saddr_ipv4, pstNextLink->stPeer.stSockAddr.usPort);
#endif
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;
nTimeoutCount = (nTimeoutCount == 1 ? 2 : nTimeoutCount);
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();
}