/* alarm.c (rsxnt) -- Copyright (c) 1996-1997 Rainer Schnitker */

#include "rsxnt.h"

static DWORD WINAPI alarm_thread(LPVOID lpThreadParameter)
{
    EMXPROCESS *p = _rsxnt_get_process_ptr();
    DWORD sec, start, end, sleepsec;

    sec = (DWORD) lpThreadParameter;

    start = GetTickCount();
    WaitForSingleObject(p->hEventAlarm, sec * 1000);
    end = GetTickCount();

    if (p->alarm_flags == ALARM_START) {
        _rsxnt_send_signal(p, SIGALRM);
        _rsxnt_do_signal(SIGALRM);
        p->hThreadAlarm = 0;
    }

    if (end < start)
        return 0;
    sleepsec = (end-start)/1000;
    if (sleepsec >= sec)
        return 0;
    else
        return (sec - sleepsec);
}

unsigned int __alarm(unsigned sec)
{
    EMXPROCESS *p = _rsxnt_get_process_ptr();
    DWORD tid;
    HANDLE h;
    DWORD retv;

    if (!p->hEventAlarm) {
        h = CreateEvent(NULL, FALSE, FALSE, NULL);
        if (h == INVALID_HANDLE_VALUE)
            return -1;
        else
            p->hEventAlarm = h;
    }

    /* kill old alarm */
    if (p->hThreadAlarm) {
        p->alarm_flags = ALARM_RESTART;
        PulseEvent(p->hEventAlarm);
        WaitForSingleObject(p->hThreadAlarm, INFINITE);
        GetExitCodeThread(p->hThreadAlarm, &retv);
        CloseHandle (p->hThreadAlarm);
        p->hThreadAlarm = 0;
    } else
        retv = 0;

    if (sec > 0) {
        h = CreateThread(NULL, 0, alarm_thread, (LPVOID) sec, CREATE_SUSPENDED, &tid);
        if (h == INVALID_HANDLE_VALUE)
            return -1;
        else
            p->hThreadAlarm = h;

        p->alarm_flags = ALARM_START;
        ResumeThread(p->hThreadAlarm);
    } else
        retv = 0;

    return retv;
}
