From 6d305e33413451a26a38e82a863685fb11bc6cba Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Tue, 13 Nov 2007 10:14:45 +0100 Subject: [PATCH] Implement setitimer() and sigaction(). The timer is implemented using a thread. Signed-off-by: Johannes Sixt --- compat/mingw.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++ git-compat-util.h | 19 +++++++- 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index befdb147ca..eaf6267025 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -650,3 +650,119 @@ struct passwd *mingw_getpwuid(int uid) p.pw_dir = NULL; 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 basically 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() does not wait indefinitely; instead, it interrupts the + * wait state every now and then, namely exactly after timer's interval + * length. At these opportunities it calls 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 create progress indicator"); + } else + return errno = ENOMEM, + error("cannot allocate resources for progress indicator"); + 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) +{ + static const struct timeval zero; + + if (out != NULL) + return errno = EINVAL, + error("setitmer 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("setitmer: 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_interval.tv_sec * 1000 + in->it_interval.tv_usec / 1000; + one_shot = is_timeval_eq(&in->it_value, &zero); + atexit(stop_timer_thread); + return start_timer_thread(); +} + +int sigaction(int sig, struct sigaction *in, struct sigaction *out) +{ + 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; +} diff --git a/git-compat-util.h b/git-compat-util.h index d85fdf5415..bdda57221a 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -454,7 +454,6 @@ typedef int pid_t; #define WNOHANG 1 #define SIGKILL 0 #define SIGCHLD 0 -#define SIGALRM 0 #define SIGPIPE 0 #define ECONNABORTED 0 @@ -548,6 +547,24 @@ struct passwd *mingw_getpwuid(int uid); static inline int getuid() { return 1; } static inline struct passwd *getpwnam(const char *name) { return NULL; } +struct itimerval { + struct timeval it_value, it_interval; +}; +int setitimer(int type, struct itimerval *in, struct itimerval *out); +#define ITIMER_REAL 0 + +typedef void (__cdecl *sig_handler_t)(int); +struct sigaction { + sig_handler_t sa_handler; + unsigned sa_flags; +}; +int sigaction(int sig, struct sigaction *in, struct sigaction *out); +#define sigemptyset(x) (void)0 +#define SA_RESTART 0 +#define SIGALRM 100 +sig_handler_t mingw_signal(int sig, sig_handler_t handler); +#define signal mingw_signal + #endif /* __MINGW32__ */ #endif