用户态下多定时器的实现

来源:互联网 发布:手机自动打开数据连接 编辑:程序博客网 时间:2024/06/05 10:02

参考书《网络编程与分层协议设计基于Linux平台实现》ISBN 978-7-111-35052-1

用链表实现多个定时器

snmp_aparm.h

#ifndef SNMP_ALARM_H#define SNMP_ALARM_H#define RETSIGTYPE voidtypedef void (SNMPAlarmCallback) (unsigned int clientreg, void *clientarg);/* * alarm flags  */#define SA_REPEAT 0x01          /* keep repeating every X seconds */struct snmp_alarm {    struct timeval t;    unsigned int flags;    unsigned int clientreg;    struct timeval t_last;    struct timeval t_next;    void *clientarg;    SNMPAlarmCallback *thecallback;    struct snmp_alarm *next;};/* * the ones you should need  */void snmp_alarm_unregister(unsigned int clientreg);void snmp_alarm_unregister_all(void);unsigned int snmp_alarm_register(unsigned int when,                                 unsigned int flags,                                 SNMPAlarmCallback * thecallback,                                 void *clientarg);unsigned int snmp_alarm_register_hr(struct timeval t,                                    unsigned int flags,                                    SNMPAlarmCallback * cb, void *cd);/* * the ones you shouldn't  */int init_alarm_post_config();void sa_update_entry(struct snmp_alarm *alrm);struct snmp_alarm *sa_find_next(void);void run_alarms(void);RETSIGTYPE alarm_handler(int a);void set_an_alarm(void);int get_next_alarm_delay_time(struct timeval *delta);#endif
snmp_alarm.c

#include <stdio.h>#include <unistd.h>#include <signal.h>#include <stdlib.h>#include <sys/types.h>#include <netinet/in.h>#include <string.h>#include <sys/time.h>#include <time.h>#include "snmp_alarm.h"#define SNMP_MALLOC_STRUCT(s)   (struct s *) calloc(1, sizeof(struct s))static struct snmp_alarm *thealarms = NULL;static int start_alarms = 0;static unsigned int regnum = 1;int init_alarm_post_config(){    start_alarms = 1;    set_an_alarm();    return 0;}void sa_update_entry(struct snmp_alarm *a){    if(a->t_last.tv_sec == 0 && a->t_last.tv_usec == 0) {        struct timeval t_now;        /*         * Never been called yet, call time `t' from now.           */        gettimeofday(&t_now, NULL);        a->t_last.tv_sec = t_now.tv_sec;        a->t_last.tv_usec = t_now.tv_usec;        a->t_next.tv_sec = t_now.tv_sec + a->t.tv_sec;        a->t_next.tv_usec = t_now.tv_usec + a->t.tv_usec;        while(a->t_next.tv_usec >= 1000000) {            a->t_next.tv_usec -= 1000000;            a->t_next.tv_sec += 1;        }    }    else if(a->t_next.tv_sec == 0 && a->t_next.tv_usec == 0) {        /*         * We've been called but not reset for the next call.           */        if(a->flags & SA_REPEAT) {            if(a->t.tv_sec == 0 && a->t.tv_usec == 0) {                printf("update_entry: illegal interval specified\n");                snmp_alarm_unregister(a->clientreg);                return;            }            a->t_next.tv_sec = a->t_last.tv_sec + a->t.tv_sec;            a->t_next.tv_usec = a->t_last.tv_usec + a->t.tv_usec;            while(a->t_next.tv_usec >= 1000000) {                a->t_next.tv_usec -= 1000000;                a->t_next.tv_sec += 1;            }        }        else {            /*             * Single time call, remove it.               */            snmp_alarm_unregister(a->clientreg);        }    }}/** * This function removes the callback function from a list of registered * alarms, unregistering the alarm. * * @param clientreg is a unique unsigned integer representing a registered *        alarm which the client wants to unregister. * * @return void * * @see snmp_alarm_register * @see snmp_alarm_register_hr * @see snmp_alarm_unregister_all */void snmp_alarm_unregister(unsigned int clientreg){    struct snmp_alarm *sa_ptr, **prevNext = &thealarms;    for(sa_ptr = thealarms;        sa_ptr != NULL && sa_ptr->clientreg != clientreg;        sa_ptr = sa_ptr->next) {        prevNext = &(sa_ptr->next);    }    if(sa_ptr != NULL) {        *prevNext = sa_ptr->next;        printf("unregistered alarm %d\n", sa_ptr->clientreg);        /*         * Note:  do not free the clientarg, its the clients responsibility          */        free(sa_ptr);    }    else {        printf("no alarm %d to unregister\n", clientreg);    }}/** * This function unregisters all alarms currently stored. * * @return void * * @see snmp_alarm_register * @see snmp_alarm_register_hr * @see snmp_alarm_unregister */void snmp_alarm_unregister_all(void){    struct snmp_alarm *sa_ptr, *sa_tmp;    for(sa_ptr = thealarms; sa_ptr != NULL; sa_ptr = sa_tmp) {        sa_tmp = sa_ptr->next;        free(sa_ptr);    }    printf("ALL alarms unregistered\n");    thealarms = NULL;}struct snmp_alarm *sa_find_next(void){    struct snmp_alarm *a, *lowest = NULL;    for(a = thealarms; a != NULL; a = a->next) {        if(lowest == NULL) {            lowest = a;        }        else if(a->t_next.tv_sec == lowest->t_next.tv_sec) {            if(a->t_next.tv_usec < lowest->t_next.tv_usec) {                lowest = a;            }        }        else if(a->t_next.tv_sec < lowest->t_next.tv_sec) {            lowest = a;        }    }    return lowest;}struct snmp_alarm *sa_find_specific(unsigned int clientreg){    struct snmp_alarm *sa_ptr;    for(sa_ptr = thealarms; sa_ptr != NULL; sa_ptr = sa_ptr->next) {        if(sa_ptr->clientreg == clientreg) {            return sa_ptr;        }    }    return NULL;}void run_alarms(void){    int done = 0;    struct snmp_alarm *a = NULL;    unsigned int clientreg;    struct timeval t_now;    /*     * Loop through everything we have repeatedly looking for the next thing to     * call until all events are finally in the future again.       */    while(!done) {        if((a = sa_find_next()) == NULL) {            return;        }        gettimeofday(&t_now, NULL);        if((a->t_next.tv_sec < t_now.tv_sec) ||           ((a->t_next.tv_sec == t_now.tv_sec) &&            (a->t_next.tv_usec < t_now.tv_usec))) {            clientreg = a->clientreg;            printf("run alarm %d\n", clientreg);            (*(a->thecallback)) (clientreg, a->clientarg);            printf("alarm %d completed\n", clientreg);            if((a = sa_find_specific(clientreg)) != NULL) {                a->t_last.tv_sec = t_now.tv_sec;                a->t_last.tv_usec = t_now.tv_usec;                a->t_next.tv_sec = 0;                a->t_next.tv_usec = 0;                sa_update_entry(a);            }            else {                printf("alarm %d deleted itself\n", clientreg);            }        }        else {            done = 1;        }    }}RETSIGTYPE alarm_handler(int a){    run_alarms();    set_an_alarm();}int get_next_alarm_delay_time(struct timeval *delta){    struct snmp_alarm *sa_ptr;    struct timeval t_diff, t_now;    sa_ptr = sa_find_next();    if(sa_ptr) {        gettimeofday(&t_now, 0);        if((t_now.tv_sec > sa_ptr->t_next.tv_sec) ||           ((t_now.tv_sec == sa_ptr->t_next.tv_sec) &&            (t_now.tv_usec > sa_ptr->t_next.tv_usec))) {            /*             * Time has already passed.  Return the smallest possible amount of             * time.               */            delta->tv_sec = 0;            delta->tv_usec = 1;            return sa_ptr->clientreg;        }        else {            /*             * Time is still in the future.               */            t_diff.tv_sec = sa_ptr->t_next.tv_sec - t_now.tv_sec;            t_diff.tv_usec = sa_ptr->t_next.tv_usec - t_now.tv_usec;            while(t_diff.tv_usec < 0) {                t_diff.tv_sec -= 1;                t_diff.tv_usec += 1000000;            }            delta->tv_sec = t_diff.tv_sec;            delta->tv_usec = t_diff.tv_usec;            return sa_ptr->clientreg;        }    }    /*     * Nothing Left.       */    return 0;}void set_an_alarm(void){    struct timeval delta;    int nextalarm = get_next_alarm_delay_time(&delta);    /*     * We don't use signals if they asked us nicely not to.  It's expected     * they'll check the next alarm time and do their own calling of     * run_alarms().       */    if(nextalarm) {        struct itimerval it;        it.it_value.tv_sec = delta.tv_sec;        it.it_value.tv_usec = delta.tv_usec;        it.it_interval.tv_sec = 0;        it.it_interval.tv_usec = 0;        signal(SIGALRM, alarm_handler);        setitimer(ITIMER_REAL, &it, NULL);        printf("schedule alarm %d in %d.%03d seconds\n",               nextalarm, (int) delta.tv_sec,               (int) (delta.tv_usec / 1000));    }    else {        printf("no alarms found to schedule\n");    }}/** * This function registers function callbacks to occur at a speciifc time * in the future. * * @param when is an unsigned integer specifying when the callback function *             will be called in seconds. * * @param flags is an unsigned integer that specifies how frequent the callback *        function is called in seconds.  Should be SA_REPEAT or 0.  If   *        flags  is  set with SA_REPEAT, then the registered callback function *        will be called every SA_REPEAT seconds.  If flags is 0 then the  *        function will only be called once and then removed from the  *        registered alarm list. * * @param thecallback is a pointer SNMPAlarmCallback which is the callback  *        function being stored and registered. * * @param clientarg is a void pointer used by the callback function.  This  *        pointer is assigned to snmp_alarm->clientarg and passed into the *        callback function for the client's specifc needs. * * @return Returns a unique unsigned integer(which is also passed as the first  *        argument of each callback), which can then be used to remove the *        callback from the list at a later point in the future using the *        snmp_alarm_unregister() function.  If memory could not be allocated *        for the snmp_alarm struct 0 is returned. * * @see snmp_alarm_unregister * @see snmp_alarm_register_hr * @see snmp_alarm_unregister_all */unsigned intsnmp_alarm_register(unsigned int when, unsigned int flags,                    SNMPAlarmCallback * thecallback, void *clientarg){    struct snmp_alarm **sa_pptr;    if(thealarms != NULL) {        for(sa_pptr = &thealarms; (*sa_pptr) != NULL;            sa_pptr = &((*sa_pptr)->next)) ;    }    else {        sa_pptr = &thealarms;    }    *sa_pptr = SNMP_MALLOC_STRUCT(snmp_alarm);    if(*sa_pptr == NULL)        return 0;    if(0 == when) {        (*sa_pptr)->t.tv_sec = 0;        (*sa_pptr)->t.tv_usec = 1;    }    else {        (*sa_pptr)->t.tv_sec = when;        (*sa_pptr)->t.tv_usec = 0;    }    (*sa_pptr)->flags = flags;    (*sa_pptr)->clientarg = clientarg;    (*sa_pptr)->thecallback = thecallback;    (*sa_pptr)->clientreg = regnum++;    (*sa_pptr)->next = NULL;    sa_update_entry(*sa_pptr);    printf("registered alarm %d, t = %d.%03d, flags=0x%02x\n",           (*sa_pptr)->clientreg, (int) (*sa_pptr)->t.tv_sec,           (int) ((*sa_pptr)->t.tv_usec / 1000), (*sa_pptr)->flags);    if(start_alarms){        set_an_alarm();    }    return (*sa_pptr)->clientreg;}/** * This function offers finer granularity as to when the callback  * function is called by making use of t->tv_usec value forming the  * "when" aspect of snmp_alarm_register(). * * @param t is a timeval structure used to specify when the callback  *        function(alarm) will be called.  Adds the ability to specify *        microseconds.  t.tv_sec and t.tv_usec are assigned *        to snmp_alarm->tv_sec and snmp_alarm->tv_usec respectively internally. *        The snmp_alarm_register function only assigns seconds(it's when  *        argument). * * @param flags is an unsigned integer that specifies how frequent the callback *        function is called in seconds.  Should be SA_REPEAT or NULL.  If   *        flags  is  set with SA_REPEAT, then the registered callback function *        will be called every SA_REPEAT seconds.  If flags is NULL then the  *        function will only be called once and then removed from the  *        registered alarm list. * * @param cb is a pointer SNMPAlarmCallback which is the callback  *        function being stored and registered. * * @param cd is a void pointer used by the callback function.  This  *        pointer is assigned to snmp_alarm->clientarg and passed into the *        callback function for the client's specifc needs. * * @return Returns a unique unsigned integer(which is also passed as the first  *        argument of each callback), which can then be used to remove the *        callback from the list at a later point in the future using the *        snmp_alarm_unregister() function.  If memory could not be allocated *        for the snmp_alarm struct 0 is returned. * * @see snmp_alarm_register * @see snmp_alarm_unregister * @see snmp_alarm_unregister_all */unsigned intsnmp_alarm_register_hr(struct timeval t, unsigned int flags,                       SNMPAlarmCallback * cb, void *cd){    struct snmp_alarm **s = NULL;    for(s = &(thealarms); *s != NULL; s = &((*s)->next)) ;    *s = SNMP_MALLOC_STRUCT(snmp_alarm);    if(*s == NULL) {        return 0;    }    (*s)->t.tv_sec = t.tv_sec;    (*s)->t.tv_usec = t.tv_usec;    (*s)->flags = flags;    (*s)->clientarg = cd;    (*s)->thecallback = cb;    (*s)->clientreg = regnum++;    (*s)->next = NULL;    sa_update_entry(*s);    printf("registered alarm %d, t = %d.%03d, flags=0x%02x\n",           (*s)->clientreg, (int) (*s)->t.tv_sec,           (int) ((*s)->t.tv_usec / 1000), (*s)->flags);    if(start_alarms) {        set_an_alarm();    }    return (*s)->clientreg;}/**  @} */void fun1(unsigned int clientreg, void *clientarg){    fprintf(stderr,"fun:%s clientreg:%d\n",__FUNCTION__,clientreg);}void fun2(unsigned int clientreg, void *clientarg){    fprintf(stderr,"fun:%s clientreg:%d\n",__FUNCTION__,clientreg);}//使用示例 很简单int main(){    start_alarms=1;set_an_alarm();    snmp_alarm_register(1, SA_REPEAT,fun1,NULL);    snmp_alarm_register(5, SA_REPEAT,fun2,NULL);    for(;;){        pause();    }    return 0;}



原创粉丝点击