Windows: Implement setitimer() and sigaction().
The timer is implemented using a thread that calls the signal handler at regular intervals. We also replace Windows's signal() function because we must intercept that SIGALRM is set (which is used when a timer is canceled). Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>
This commit is contained in:
parent
82f8d969f5
commit
6072fc314e
112
compat/mingw.c
112
compat/mingw.c
@ -125,12 +125,120 @@ struct passwd *getpwuid(int uid)
|
||||
return &p;
|
||||
}
|
||||
|
||||
static HANDLE timer_event;
|
||||
static HANDLE timer_thread;
|
||||
static int timer_interval;
|
||||
static int one_shot;
|
||||
static sig_handler_t timer_fn = SIG_DFL;
|
||||
|
||||
/* The timer works like this:
|
||||
* The thread, ticktack(), is a trivial routine that most of the time
|
||||
* only waits to receive the signal to terminate. The main thread tells
|
||||
* the thread to terminate by setting the timer_event to the signalled
|
||||
* state.
|
||||
* But ticktack() interrupts the wait state after the timer's interval
|
||||
* length to call the signal handler.
|
||||
*/
|
||||
|
||||
static __stdcall unsigned ticktack(void *dummy)
|
||||
{
|
||||
while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
|
||||
if (timer_fn == SIG_DFL)
|
||||
die("Alarm");
|
||||
if (timer_fn != SIG_IGN)
|
||||
timer_fn(SIGALRM);
|
||||
if (one_shot)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start_timer_thread(void)
|
||||
{
|
||||
timer_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (timer_event) {
|
||||
timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL);
|
||||
if (!timer_thread )
|
||||
return errno = ENOMEM,
|
||||
error("cannot start timer thread");
|
||||
} else
|
||||
return errno = ENOMEM,
|
||||
error("cannot allocate resources for timer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stop_timer_thread(void)
|
||||
{
|
||||
if (timer_event)
|
||||
SetEvent(timer_event); /* tell thread to terminate */
|
||||
if (timer_thread) {
|
||||
int rc = WaitForSingleObject(timer_thread, 1000);
|
||||
if (rc == WAIT_TIMEOUT)
|
||||
error("timer thread did not terminate timely");
|
||||
else if (rc != WAIT_OBJECT_0)
|
||||
error("waiting for timer thread failed: %lu",
|
||||
GetLastError());
|
||||
CloseHandle(timer_thread);
|
||||
}
|
||||
if (timer_event)
|
||||
CloseHandle(timer_event);
|
||||
timer_event = NULL;
|
||||
timer_thread = NULL;
|
||||
}
|
||||
|
||||
static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *i2)
|
||||
{
|
||||
return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec;
|
||||
}
|
||||
|
||||
int setitimer(int type, struct itimerval *in, struct itimerval *out)
|
||||
{
|
||||
return -1;
|
||||
static const struct timeval zero;
|
||||
static int atexit_done;
|
||||
|
||||
if (out != NULL)
|
||||
return errno = EINVAL,
|
||||
error("setitimer param 3 != NULL not implemented");
|
||||
if (!is_timeval_eq(&in->it_interval, &zero) &&
|
||||
!is_timeval_eq(&in->it_interval, &in->it_value))
|
||||
return errno = EINVAL,
|
||||
error("setitimer: it_interval must be zero or eq it_value");
|
||||
|
||||
if (timer_thread)
|
||||
stop_timer_thread();
|
||||
|
||||
if (is_timeval_eq(&in->it_value, &zero) &&
|
||||
is_timeval_eq(&in->it_interval, &zero))
|
||||
return 0;
|
||||
|
||||
timer_interval = in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000;
|
||||
one_shot = is_timeval_eq(&in->it_interval, &zero);
|
||||
if (!atexit_done) {
|
||||
atexit(stop_timer_thread);
|
||||
atexit_done = 1;
|
||||
}
|
||||
return start_timer_thread();
|
||||
}
|
||||
|
||||
int sigaction(int sig, struct sigaction *in, struct sigaction *out)
|
||||
{
|
||||
return -1;
|
||||
if (sig != SIGALRM)
|
||||
return errno = EINVAL,
|
||||
error("sigaction only implemented for SIGALRM");
|
||||
if (out != NULL)
|
||||
return errno = EINVAL,
|
||||
error("sigaction: param 3 != NULL not implemented");
|
||||
|
||||
timer_fn = in->sa_handler;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef signal
|
||||
sig_handler_t mingw_signal(int sig, sig_handler_t handler)
|
||||
{
|
||||
if (sig != SIGALRM)
|
||||
return signal(sig, handler);
|
||||
sig_handler_t old = timer_fn;
|
||||
timer_fn = handler;
|
||||
return old;
|
||||
}
|
||||
|
@ -154,6 +154,9 @@ char *mingw_getcwd(char *pointer, int len);
|
||||
int mingw_rename(const char*, const char*);
|
||||
#define rename mingw_rename
|
||||
|
||||
sig_handler_t mingw_signal(int sig, sig_handler_t handler);
|
||||
#define signal mingw_signal
|
||||
|
||||
/*
|
||||
* git specific compatibility
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user