应用层timer_libc_posix timer

应用层除了通过setitimer/getitimer设置获取timer外,还可通过timer_create()等一系列函数实现应用层timer功能。

应用流程

The timers created by timer_create() are commonly known as "POSIX (interval) timers". The POSIX timers API consists of the following interfaces:

* timer_create(): Create a timer.

* timer_settime(2): Arm (start) or disarm (stop) a timer.

* timer_gettime(2): Fetch the time remaining until the next expiration of a timer, along with the interval setting of the timer.

* timer_getoverrun(2): Return the overrun count for the last timer expiration.

* timer_delete(2): Disarm and delete a timer.

timer_create

#include <signal.h>
#include <time.h>

int timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid);

timer_create() creates a new per-process interval timer. The ID of the new timer is returned in the buffer pointed to by timerid, which must be a non-null pointer.

参数clockid

CLOCK_REALTIME   A settable system-wide real-time clock. 一般此id。

CLOCK_MONOTONIC
A nonsettable monotonically increasing clock that measures time from some unspecified point in the past that does not change after system startup.

CLOCK_PROCESS_CPUTIME_ID (since Linux 2.6.12)
A clock that measures (user and system) CPU time consumed by (all of the threads in) the calling process.

CLOCK_THREAD_CPUTIME_ID (since Linux 2.6.12)
A clock that measures (user and system) CPU time consumed by the calling thread.

参数sigevent

指定超时的动作,详见man sigevent。

The sevp.sigev_notify field can have the following values:SIGEV_NONE(不处理),SIGEV_SIGNAL(产生信号),SIGEV_THREAD(新线程处理),SIGEV_THREAD_ID(指定线程处理)。

参数timerid

typedef void * timer_t;

timer_t timerid;
printf("timer ID is 0x%lx
", (long)timerid);

返回值

成功返回0,timerid保存创建的timer。

manpage示例--SIGEV_SIGNAL:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <signal.h>

#define SIG SIGTERM

#define errExit(msg) 
    do {perror(msg); exit(EXIT_FAILURE); } while(0)

static void print_siginfo(siginfo_t *si)
{
    timer_t *tidp;
    int or; 

    tidp = si->si_value.sival_ptr;

    printf("sigval_ptr = %p; ", si->si_value.sival_ptr);
    printf(" *sival_ptr =0x%lx
", (long) *tidp);

    or = timer_getoverrun(*tidp);
    if(or == -1){
        errExit("timer_getoverrun");
    } else {
        printf(" overrun count = %d
", or);
    }   
}

static void handler(int sig, siginfo_t *si, void *uc)
{
   /* Note: calling printf() from a signal handler is not
    strictly correct, since printf() is not async-signal-safe;
    see signal(7) */
    printf("Caught signal %d
", sig);
    print_siginfo(si);
    signal(sig, SIG_IGN);
}
int main(int argc, char **argv)
{
    int ret = 0;
    timer_t timerid;
    struct sigevent se; 
    struct itimerspec its;
    long long freq_nanosecs;
    sigset_t mask;
    struct sigaction sa;

    if(argc != 3){
        fprintf(stderr, "Usage:%s <sleep-secs> <freq_nanosecs>
", argv[0]);
        exit(EXIT_FAILURE);
    }

    printf("Establishing handler for signal %d
", SIG);
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = handler;
    sigemptyset(&sa.sa_mask);
    if(sigaction(SIG, &sa, NULL) == -1){
        errExit("sigaction");
    }

    printf("Blocking signal %d
", SIG);
    sigemptyset(&mask);
    sigaddset(&mask, SIG);
    if(sigprocmask(SIG_SETMASK, &mask, NULL) == -1){
        errExit("sigprocmask");
    }

    memset(&se, 0, sizeof(struct sigevent));
    se.sigev_notify = SIGEV_SIGNAL;
    se.sigev_signo = SIG;
    se.sigev_value.sival_ptr = &timerid;
    ret = timer_create(CLOCK_REALTIME, &se, &timerid);
    if(!ret){
        printf("timer create successfully, timeid is 0x%lx
", (long)timerid);
    } else {
        perror("timer_create");
    }

    /* Start the timer */
    freq_nanosecs = atoll(argv[2]);
    its.it_value.tv_sec = freq_nanosecs /1000000000;
    its.it_value.tv_nsec = freq_nanosecs %1000000000;
    its.it_interval.tv_sec = freq_nanosecs /1000000000;
    its.it_interval.tv_nsec = freq_nanosecs %1000000000;

    if(timer_settime(timerid, 0, &its, NULL) == -1){
        errExit("timer_settime");
    }
    printf("Sleeping for %d secs
", atoi(argv[1]));
    sleep(atoi(argv[1]));

    printf("Unblocking signal %d
", SIG);
    if(sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1){
        errExit("sigprocmask");
    }

    exit(EXIT_SUCCESS);
}

 SIGEV_THREAD示例:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>
#include <time.h>

//void * timer_thread(void *arg)
void timer_thread(union sigval sv)
{
    printf("thread run: %lu...[%s]
", pthread_self(), (char *)sv.sival_ptr);
//    printf("thread run: %lu...[%d]
", pthread_self(), (char *)sv.sival_int);

//    return NULL;
}

timer_t timer_add(long sec, long usec, void (*func)(union sigval), void *arg)
{
    int ret = 0;
    timer_t tid;
    struct sigevent sev;
    
    memset(&sev, 0, sizeof(sev));
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = func;
    sev.sigev_value.sival_ptr = arg;

    ret = timer_create(CLOCK_MONOTONIC, &sev, &tid);
    if(ret < 0){
        printf("timer_create failed.
");
        return (timer_t)-1;
    }else {
        printf("create timer id: %lx
", (long)tid);
    }
    
    struct itimerspec its;

    memset(&its, 0, sizeof(its));
    its.it_interval.tv_sec = sec;
    its.it_interval.tv_nsec = usec * 1000;
    its.it_value.tv_sec = 0;
    its.it_value.tv_nsec = 1;
    
    ret = timer_settime(tid, 0, &its, NULL);
    if(ret < 0){
        printf("timer_settime failed.
");
        return (timer_t)-1;
    }

    return tid;
}

int main(int argc, char *argv[])
{
    timer_t tid;
    char str[] ="I love CHINA";
/*
    int ret = 0;
    pthread_t thid = 0;

    ret = pthread_create(&thid, NULL, timer_thread, NULL);
    if(ret < 0){
        printf("create thread failed.
");
        return -1;
    }
    ret = pthread_detach(thid);
    if(ret < 0){
        printf("pthread_detach failed.
");
        return -1;
    }
*/
    tid = timer_add(2, 0, timer_thread, (void *)str);
    if(tid < 0){
        printf("timer add failed.
");
        return -1;
    }

    while(1);
//    sleep(5);
    
    timer_delete(tid);
    return 0;    
}

参考:

1. Linux 下定时器的实现方式分析

原文地址:https://www.cnblogs.com/embedded-linux/p/9093924.html