NuttX下实现周期任务管理服务
由于NuttX提供的Timer API与Linux类似,所以非常方便将Linux下周期性定时任务函数移植到NuttX下面。
例如提供一个周期性任务注册接口,接口申明如下:
typedef void (*timer_notify)(void* );
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
int init_timer_manager(int cycle_ms);
int attach_timer(timer_notify notify, int timeout,
e_periodic_attr attr, void* param);
int detach_timer(timer_notify notify);
init_timer_manager实现如下:
int init_timer_manager(int cycle_ms)
{
struct sigaction act;
struct sigaction oact;
struct sigevent notify;
struct itimerspec timer;
timer_t timerid;
int status;
struct sched_param sparam;
int prio_min;
int prio_max;
int prio_mid;
pthread_attr_t attr;
sem_init(&timer_sem, 0, 0);
INIT_LIST_HEAD(&oneshoot_list);
INIT_LIST_HEAD(&periodic_list);
pthread_mutex_init(&periodic_mut, NULL);
pthread_mutex_init(&oneshoot_mut,NULL);
status = pthread_attr_init(&attr);
if (status != OK)
{
printf("nsem_test: pthread_attr_init failed, status=%d\n", status);
}
prio_min = sched_get_priority_min(SCHED_FIFO);
prio_max = sched_get_priority_max(SCHED_FIFO);
prio_mid = (prio_min + prio_max) / 2;
sparam.sched_priority = (prio_mid + prio_max) / 2;
status = pthread_attr_setschedparam(&attr,&sparam);
if (status != OK)
{
printf("nsem_test: ERROR: pthread_attr_setschedparam failed, status=%d\n", status);
goto errorout;
}
status = pthread_create(&timer_threadid, &attr, timer_thread, NULL);
if (status != 0)
{
printf("%s: ERROR: thread creation failed\n", __FUNCTION__);
goto errorout;
}
/* Set timer timeout action */
act.sa_sigaction = timer_expiration;
act.sa_flags = SA_SIGINFO;
(void)sigfillset(&act.sa_mask);
(void)sigdelset(&act.sa_mask, TIMER_MANAGER_SIGNAL);
status = sigaction(TIMER_MANAGER_SIGNAL, &act, &oact);
if (status != OK)
{
printf("timer_test: ERROR sigaction failed, status=%d\n" , status);
goto errorout;
}
/* Create the POSIX timer */
notify.sigev_notify = SIGEV_SIGNAL;
notify.sigev_signo = TIMER_MANAGER_SIGNAL;
notify.sigev_value.sival_int = TIMER_SIGVALUE_INT;
#ifdef CONFIG_SIG_EVTHREAD
notify.sigev_notify_function = NULL;
notify.sigev_notify_attributes = NULL;
#endif
status = timer_create(CLOCK_REALTIME, ¬ify, &timerid);
if (status != OK)
{
printf("timer_test: timer_create failed, errno=%d\n", errno);
goto errorout;
}
/* Start the POSIX timer */
timer.it_value.tv_sec = 2; /* initial value shouldn't set to 0 */
timer.it_value.tv_nsec = 0;
timer.it_interval.tv_sec = (cycle_ms/NSEC_PER_USEC);
timer.it_interval.tv_nsec = ((cycle_ms%NSEC_PER_USEC)*NSEC_PER_MSEC);
status = timer_settime(timerid, TIMER_ABSTIME, &timer, NULL);
if (status != OK)
{
printf("timer_test: timer_settime failed, errno=%d\n", errno);
goto errorout;
}
return status;
errorout:
sem_destroy(&timer_sem);
return status;
}
attach_timer实现如下:
int attach_timer(timer_notify notify, int timeout,
e_periodic_attr attr, void* param)
{
int status;
s_timer_unit* new_timer;
pthread_mutex_t* mux;
struct list_head* list;
if ((notify == NULL) || (timeout == 0))
{
return -ENOENT;
}
new_timer = (s_timer_unit* )malloc(sizeof(s_timer_unit));
if (new_timer == NULL)
{
return -ENOMEM;
}
INIT_LIST_HEAD(&new_timer->list);
new_timer->notify = notify;
new_timer->curr_time = 0;
new_timer->timeout_time = timeout;
new_timer->timer_param = param;
if (attr == ONESHOOT_TYPE)
{
mux = &oneshoot_mut;
list = &oneshoot_list;
}
else if (attr == PERIODIC_TYPE)
{
mux = &periodic_mut;
list = &periodic_list;
}
else
{
goto error_out;
}
status = pthread_mutex_lock(mux);
if (status != 0)
{
printf("%s: mutex_lock error\n",__FUNCTION__);
goto error_out;
}
timer_taskcount++;
list_add_tail(&new_timer->list, list);
pthread_mutex_unlock(mux);
return status;
error_out:
free((void *)new_timer);
return status;
}
然后通过一个线程接收timer发出来的信号量,来查询任务列表中是否有超时任务需要得到执行,具体线程实现代码如下:
static void *timer_thread(FAR void *para)
{
int status;
s_timer_unit* timer;
struct list_head* curr_list;
while (1)
{
status = sem_wait(&timer_sem);
if (status != 0)
{
printf("%s: sem_wait ERROR \n", __FUNCTION__);
continue;
}
// printf("timer_thread run\n");
// fflush(stdout);
/* Scan oneshoot timer list and found if any timer task timeout */
status = pthread_mutex_lock(&oneshoot_mut);
if (status == 0)
{
for (curr_list = oneshoot_list.next; curr_list != &oneshoot_list; )
{
timer = container_of(curr_list, s_timer_unit, list);
curr_list = timer->list.next;
if(++timer->curr_time >= timer->timeout_time)
{
timer_taskcount--;
timer->notify(timer->timer_param);
list_del(&timer->list);
free((void *)timer);
}
}
pthread_mutex_unlock(&oneshoot_mut);
}
/* Scan periodic timer list and found if any timer task timeout */
status = pthread_mutex_lock(&periodic_mut);
if (status == 0)
{
for (curr_list = periodic_list.next; curr_list != &periodic_list; )
{
timer = container_of(curr_list, s_timer_unit, list);
curr_list = timer->list.next;
if(++timer->curr_time >= timer->timeout_time)
{
timer->notify(timer->timer_param);
timer->curr_time = 0;
}
}
pthread_mutex_unlock(&periodic_mut);
}
}
pthread_exit(NULL);
return NULL; /* Non-reachable -- needed for some compilers */
}
这就是NuttX RTOS的优势,非常方便你将以前Linux下的代码移植到NuttX平台下。