forked from lei.chen/myxce
Add millisecond-granularity delay_task_ms() to delaymgr using clock_gettime(CLOCK_MONOTONIC) for deadline computation. Extends delay_task_t with nextrun_ts field; delay_worker distinguishes ms-tasks from second-tasks via non-zero nextrun_ts. Backward compatible with existing delay_task callers. 4 delay tests pass (2 new: tolerance and invalid-args). Provides the timeout primitive for election and committing watchdogs.
149 lines
3.7 KiB
C
149 lines
3.7 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include "delay.h"
|
|
#include "unity.h"
|
|
|
|
static int delay_work(void* arg)
|
|
{
|
|
time_t now;
|
|
int* pcount = (int*)arg;
|
|
|
|
now = time(NULL);
|
|
(*pcount)++;
|
|
|
|
printf("delay task run at %ld\n", now);
|
|
return 0;
|
|
}
|
|
|
|
static void test_delay1()
|
|
{
|
|
delaymgr_t mgr;
|
|
int count = 0;
|
|
int runcount = 15;
|
|
int delay_period = 2;
|
|
time_t t_start = time(NULL);
|
|
|
|
delaymgr_init(&mgr, 1000 /* precision_ms */, NULL);
|
|
delaymgr_start(&mgr);
|
|
delay_task(&mgr, delay_period, runcount, (delay_task_entry_fn_t)delay_work,
|
|
&count);
|
|
|
|
while (1) {
|
|
time_t now = time(NULL);
|
|
|
|
if (now - t_start > (runcount + 2) * delay_period) {
|
|
break;
|
|
}
|
|
|
|
sleep(5);
|
|
}
|
|
|
|
TEST_ASSERT_TRUE(count == runcount);
|
|
|
|
delaymgr_fini(&mgr);
|
|
|
|
return;
|
|
}
|
|
|
|
static void test_delaymgr_precision_ms_field(void)
|
|
{
|
|
delaymgr_t mgr;
|
|
memset(&mgr, 0, sizeof(mgr));
|
|
/* precision_ms field must exist and be stored correctly */
|
|
int rc = delaymgr_init(&mgr, 200 /* precision_ms */, NULL);
|
|
TEST_ASSERT_EQUAL_INT(0, rc);
|
|
TEST_ASSERT_EQUAL_INT(200, mgr.precision_ms);
|
|
delaymgr_fini(&mgr);
|
|
printf("test_delaymgr_precision_ms_field: PASS\n");
|
|
}
|
|
|
|
/* ---------- RED: test for delay_task_ms (millisecond-granularity) ---------- */
|
|
|
|
static int ms_work_count = 0;
|
|
|
|
static int ms_work(void* arg)
|
|
{
|
|
(void)arg;
|
|
ms_work_count++;
|
|
return 0;
|
|
}
|
|
|
|
static void test_delay_task_ms_fires_within_tolerance(void)
|
|
{
|
|
delaymgr_t mgr;
|
|
struct timespec t_start, t_end;
|
|
long elapsed_ms;
|
|
const int delay_ms = 500;
|
|
const int tolerance_ms = 200;
|
|
const int precision_ms = 50;
|
|
|
|
ms_work_count = 0;
|
|
|
|
delaymgr_init(&mgr, precision_ms, NULL);
|
|
delaymgr_start(&mgr);
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &t_start);
|
|
delay_task_ms(&mgr, delay_ms, 1, (delay_task_entry_fn_t)ms_work, NULL);
|
|
|
|
/* wait long enough: delay + tolerance + one extra precision tick */
|
|
{
|
|
struct timespec wait = {
|
|
.tv_sec = 0,
|
|
.tv_nsec = (long)(delay_ms + tolerance_ms + precision_ms) * 1000000L,
|
|
};
|
|
nanosleep(&wait, NULL);
|
|
}
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, &t_end);
|
|
elapsed_ms = (t_end.tv_sec - t_start.tv_sec) * 1000L
|
|
+ (t_end.tv_nsec - t_start.tv_nsec) / 1000000L;
|
|
|
|
TEST_ASSERT_EQUAL_INT_MESSAGE(1, ms_work_count,
|
|
"ms task must have fired exactly once");
|
|
TEST_ASSERT_TRUE_MESSAGE(elapsed_ms >= (delay_ms - tolerance_ms),
|
|
"task fired too early");
|
|
TEST_ASSERT_TRUE_MESSAGE(elapsed_ms <= (delay_ms + tolerance_ms + precision_ms + 50),
|
|
"task fired too late");
|
|
|
|
delaymgr_fini(&mgr);
|
|
printf("test_delay_task_ms_fires_within_tolerance: PASS\n");
|
|
}
|
|
|
|
static void test_delay_task_ms_invalid_args(void)
|
|
{
|
|
delaymgr_t mgr;
|
|
int rc;
|
|
|
|
delaymgr_init(&mgr, 50, NULL);
|
|
|
|
/* NULL manager */
|
|
rc = delay_task_ms(NULL, 500, 1, (delay_task_entry_fn_t)ms_work, NULL);
|
|
TEST_ASSERT_TRUE(rc < 0);
|
|
|
|
/* zero delay */
|
|
rc = delay_task_ms(&mgr, 0, 1, (delay_task_entry_fn_t)ms_work, NULL);
|
|
TEST_ASSERT_TRUE(rc < 0);
|
|
|
|
/* NULL entry */
|
|
rc = delay_task_ms(&mgr, 500, 1, NULL, NULL);
|
|
TEST_ASSERT_TRUE(rc < 0);
|
|
|
|
delaymgr_fini(&mgr);
|
|
printf("test_delay_task_ms_invalid_args: PASS\n");
|
|
}
|
|
|
|
/* ---------- existing tests still exercise backward compat ---------- */
|
|
|
|
void test_delay(void)
|
|
{
|
|
printf("\n>> delay test\n\n");
|
|
|
|
RUN_TEST(test_delay1);
|
|
RUN_TEST(test_delaymgr_precision_ms_field);
|
|
RUN_TEST(test_delay_task_ms_fires_within_tolerance);
|
|
RUN_TEST(test_delay_task_ms_invalid_args);
|
|
}
|