Leopold Toetsch wrote:
> Attached is a test program, showing an implementations for multiple 
> timers. GNU/linux only, but implementing the platform interface (and the 
> sighandler/message queue) shouldn't be too hard.

don't know if it's worth something, but this is how your timer program
could look like under Win32.

rename timer_win32_c.txt to timer_win32.c and compile with:
cl timer_win32.c /link user32.lib

I had to comment out the signal(SIGALRM, sig_alarm_handler); line and
add a PeekMessage/DispatchMessage routine in the while loop.

the rest of the Win32-specific code is in the "platform interface"
section.

I realize this is really ugly, but Win32 doesn't seem to have support
for alarms, so you have to relay on windows messages instead. if
someone can come up with a better way to do it, I'm really curious to
see it :-)

cheers,
Aldo

__END__
$_=q,just perl,,s, , another ,,s,$, hacker,,print;
/*
 * itimer test
 */

/* #include <sys/time.h> */
#include <windows.h>
#include <signal.h>
#include <stdio.h>
#include <malloc.h>
#include <math.h>

volatile sig_atomic_t got_alarm = 0;

typedef struct timer_t {
    int ticks;
    int value;
    int repeat;
    int run;
    int nr;
    struct timer_t *next;
    struct timer_t *prev;
} timer;

timer *rtimer = 0;

void add_timer(timer *t) {
    timer *next = rtimer;
    rtimer = t;
    t->next = next;
    if (next) {
        t->nr = next->nr + 1;
        next->prev = t;
    }
    else
        t->nr = 1;
}

void del_timer(timer *t) {
    timer *next = t->next;
    timer *prev = t->prev;
    if (prev)
        prev->next = next;
    else
        rtimer = next;
    if (next)
        next->prev = prev;
    free(t);
}

timer * new_timer(void) {
    timer *t = calloc(1, sizeof(timer));
    add_timer(t);
    return t;
}
typedef unsigned int UINTVAL;
typedef double FLOATVAL;

UINTVAL gcd(UINTVAL a, UINTVAL b) {

    UINTVAL q = 0;
    UINTVAL c = 0;
    while (b != 0) {
        q = (UINTVAL)floor( (FLOATVAL)a/b );
        c = a - b*q;
        a = b;
        b = c;
    }
    return a;
}

void
sig_alarm_handler(int i) {
    got_alarm = 1;
}

/* platform interface */

typedef struct win32_timer_t {
        UINT_PTR id;
        UINT ms;
} win32_timer;

VOID CALLBACK proc_sys_timer_ms(
        HWND hwnd,
    UINT uMsg,
    UINT_PTR idEvent,
    DWORD dwTime
) {
        got_alarm = 1;
}

void start_sys_timer_ms(void *handle, int ms) {
        win32_timer * t = (win32_timer *) handle;
        t->id = SetTimer(NULL, 0, ms, proc_sys_timer_ms);
        t->ms = ms;
    printf("new ms = %d\n",
            ms);
}
void stop_sys_timer_ms(void *handle) {
        win32_timer * t = (win32_timer *) handle;
        KillTimer(NULL, t->id);
        free(t);
}
int get_sys_timer_ms(void *handle) {
    win32_timer * t = (win32_timer *) handle;
        return t->ms;
}
void * new_sys_timer_ms() {
    win32_timer *t = calloc(1, sizeof(win32_timer));
        t->ms = 0;
        t->id = (UINT_PTR) NULL;
        return (void *) t;
}

/* end platform interface */

void recalc_ticks(void);
void *handle;

void
do_alarm_handler() {
    timer *t;
    UINTVAL ms;
    int recalc = 0;

    ms = get_sys_timer_ms(handle);
    for (t = rtimer; t; t= t->next) {
        if (!--t->ticks) {
            t->run = 1;
            if (t->repeat) {
                t->ticks = t->value/ms;
                if (t->repeat != -1)
                    t->repeat--;
            }
        }
    }
again:
    for (t = rtimer; t; t= t->next) {
        if (t->run == 1) {
            t->run = 0;
            printf("alarm %d\n", t->nr);
            /* code run here may add timers, these have t->run = 2 */
            goto again;
        }
        if (!t->ticks && !t->repeat) {
            printf("del_timer %d\n", t->nr);
            del_timer(t);
            recalc = 1;
            goto again;
        }
    }
    if (recalc)
        recalc_ticks();
}

void p_add_timer(UINTVAL msecs, int repeat)
{
    timer *t;

    if (!msecs)
        return;
    t = new_timer();
    t->repeat = repeat;
    t->value = msecs;
    t->run = 2;
    recalc_ticks();
}

void p_del_timer(timer *t) {
    del_timer(t);
    recalc_ticks();
}

void recalc_ticks() {
    UINTVAL ms, oms;
    timer *t;

    oms = get_sys_timer_ms(handle);
    printf("gettimer oms = %d\n", oms);
    t = rtimer;
    if (t) {
        t->run = 0;
        if (oms && t->ticks)
            ms = oms*t->ticks;  /* time left */
        else
            ms = t->value;
        if (t->next) {
            for (t = t->next; t; t = t->next) {
                t->run = 0;
                if (oms && t->ticks) {
                    ms = gcd(oms*t->ticks, ms);
                }
                else
                    ms = gcd(t->value, ms);
            }
        }
        printf("new ms %d\n", ms);
again:
        for (t = rtimer; t; t= t->next) {
            int ot = t->ticks;
            printf("t%d oticks %d => ", t->nr, t->ticks);
            if (oms && ot)
                t->ticks = t->ticks * ((double)oms / (double)ms);
            else
                t->ticks = t->value / ms;
            if (!t->ticks) {
                ms = oms;
                t->ticks = ot;
                goto again;
            }
            printf("ticks %d value %d\n", t->ticks, t->value);
        }
    }
    else
        ms = 0;

    if (ms)
        start_sys_timer_ms(handle, ms);
    else
        stop_sys_timer_ms(handle);
}


int main(int argc, char **argv) {
    MSG msg = { 0, 0, 0, 0 };
        handle = new_sys_timer_ms();
    /* signal(SIGALRM, sig_alarm_handler); */
    p_add_timer(3000, 1);
    p_add_timer(2000, 3);
    p_add_timer(500, 1);
    while (rtimer) {
                if (got_alarm) {        /* CHECK_EVENTS */
                    got_alarm = 0;
                    do_alarm_handler();
                }
        if (PeekMessage(&msg, 0, WM_TIMER, WM_TIMER, PM_REMOVE) ) {
                    DispatchMessage(&msg);
                }

    }
    return 0;
}

Reply via email to