APUE Exercises 10.5 pp381

来源:互联网 发布:麟龙选股软件 编辑:程序博客网 时间:2024/05/22 07:46

Question: Using only a single timer (either alarm or the higher-precision setitimer), provide a set of functions that allows a process to set any number of timers.

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>#include <assert.h>#include <time.h>typedef void Func(int);struct __timer{    void *next;    unsigned int sec;    unsigned int intersec;    int id;    Func *sigactor;};typedef struct alarm *Timer;struct alarm{    union{        struct        {            Timer next;            unsigned int sec;        };        struct __timer __inner;    }; };typedef struct list *Header;struct list{    Timer head;};Func* sig_alarm_fun;struct list linkedlist;Header hdr_ptr = &linkedlist;Timer mallocTimer(int id, Func *actor,unsigned int sec, unsigned int interval){    Timer ret = (Timer)malloc(sizeof(struct alarm));    assert(ret);    ret->__inner.id = id;    ret->__inner.sigactor = actor;    ret->__inner.intersec = interval;    ret->sec = sec;    return ret;}Timer findTimerPrev(Header h, int id){    assert(h);    if(h->head == NULL)        return NULL;    Timer t = h->head;    Timer prev = NULL;    while(t)    {        if(t->__inner.id == id){            if(prev == NULL)                return (Timer)-1;            else                return prev;        }        prev = t;        t = t->next;    }    return NULL;}void delTimer(Header h, Timer t){    assert(h);    assert(t);    Timer prevtodel = findTimerPrev(h, t->__inner.id);    unsigned int base = 0;    if(prevtodel)    {        if(prevtodel == (Timer)-1){            unsigned int res = (h->head)->sec;            if(res != 0)            {                base = res;            }            else            {                kill(getpid(),SIGALRM);                return;            }            h->head = (h->head)->next;            Timer tmp = (h->head);            while(tmp){                tmp->sec += base;                tmp = tmp->next;            }            return;        }        else        {            base = (prevtodel->next)->sec;            prevtodel->next = (prevtodel->next)->next;            Timer tmp = (prevtodel->next);            while(tmp){                tmp->sec += base;                tmp = tmp->next;            }            return;        }    }    return;}int appendTimer(Header h, Timer t){    assert(h);    assert(t);    delTimer(h, t);    if(h->head == NULL)    {        h->head = t;        return 0;    }    Timer tmp = h->head;    Timer prev = NULL;    unsigned int prevbase = 0;    unsigned int base = 0;    while(tmp)    {        prevbase = base;        base += tmp->sec;        if(t->sec < base){            break;        }        else{            prev = tmp;            tmp = tmp->next;        }    }    if(prev == NULL)    {        (h->head)->sec -= t->sec;        t->next = h->head;        h->head = t;        return 0;    }    if(tmp == NULL)        t->sec -=base;    else        t->sec -=prevbase;    prev->next = t;    t->next = tmp;    if(tmp)        tmp->sec -= t->sec;    return 0;}Func* popTimer(Header h){    assert(h);    if(h->head == NULL)        return (Func *)-1;    Func *ret = (h->head)->__inner.sigactor;    Timer todel = h->head;    h->head = (h->head)->next;    if(todel->__inner.intersec > 0)    {        todel->sec = todel->__inner.intersec;        appendTimer(h, todel);    }    return ret;}void printList(Header h){    assert(h);    if(h->head == NULL)        return;    Timer tmp = h->head;    while(tmp)    {        printf("timer[%d] = %u saved %u\n", tmp->__inner.id, tmp->sec, tmp->__inner.intersec);        tmp = tmp->next;    }}static void sig_alarm_internal(int signo){     void funcWrapper(int signo, Func *func);    if(hdr_ptr->head == NULL)        return;    Func *recv;    if((recv = popTimer(hdr_ptr)) == (Func *)-1){        funcWrapper(SIGALRM, recv);    }      else    {        if(hdr_ptr->head){            ((hdr_ptr->head)->sec > 0?alarm((hdr_ptr->head)->sec):kill(getpid(), SIGALRM));        }        funcWrapper(SIGALRM, recv);    }}unsigned int Alarm(Header h, Timer mtimer){    sigset_t mask;    sigset_t old;    sigemptyset(&mask);    sigaddset(&mask, SIGALRM);    sigprocmask(SIG_BLOCK, &mask, &old);    unsigned int res = 0;    Timer t;    if((t = findTimerPrev(h, mtimer->__inner.id)) == NULL)        goto LL;    t = h->head;    while(t)    {        res += t->sec;        if(t->__inner.id == mtimer->__inner.id)            break;        t = t->next;    }LL:    if(mtimer->sec == 0)    {        delTimer(h, mtimer);        sigprocmask(SIG_SETMASK, &old, NULL);        return res;    }    appendTimer(h, mtimer);    if(mtimer->__inner.id == (h->head)->__inner.id)        ((h->head)->sec > 0?alarm((h->head)->sec):kill(getpid(), SIGALRM));    sigprocmask(SIG_SETMASK, &old, NULL);    return res;}static void init(){    struct sigaction act;    act.sa_handler = sig_alarm_internal;    act.sa_flags = SA_RESTART|SA_NODEFER;    sigemptyset(&act.sa_mask);    sigaction(SIGALRM, &act, NULL);}void funcWrapper(int signo, Func *func){    sigset_t mask;    sigset_t old;    sigemptyset(&mask);    sigaddset(&mask, SIGALRM);    sigprocmask(SIG_UNBLOCK, &mask, &old);    func(signo);    sigprocmask(SIG_SETMASK, &old, NULL);}//test//volatile clock_t new1, new2, new3, old1, old2, old3;void signal_forfun(signo){    new1 = clock();    printf("fun! %.4f seconds\n", ((double)(new1 - old1)/CLOCKS_PER_SEC));    old1 = new1;}void signal_forhello(signo){     new3 = clock();    printf("hello! %.4f seconds\n", ((double)(new3 - old3)/CLOCKS_PER_SEC));    old3 = new3;}void signal_forhi(signo){    new2 = clock();    printf("hi! %.4f seconds\n", ((double)(new2 - old2)/CLOCKS_PER_SEC));    old2 = new2;}intmain(void){    new1 =new2 =new3 = old1 =old2 = old3=clock();    init();    int i;    Alarm(hdr_ptr,mallocTimer(1, signal_forhi, 1, 1));    Alarm(hdr_ptr,mallocTimer(2, signal_forfun, 1, 2));    Alarm(hdr_ptr,mallocTimer(3, signal_forhello, 1, 3));    while(1){};    exit(0); }
0 0
原创粉丝点击