>From aeec1bcc629a722cba7413287f965e4ab3dc9495 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 16 Sep 2018 12:35:58 -0700 Subject: [PATCH 2/2] Adjust w32 to emulate timer_settime, not setitimer This adjusts the w32 code to emulate the current timer_settime etc. functions instead of the obsolescent setitimer etc. functions. * nt/inc/sys/time.h (ITIMER_REAL, ITIMER_PROF): Remove. All uses removed. (struct itimerspec, pthread_attr_t, union sigval, struct sigevent) (SIGEV_SIGNAL, TIMER_ABSTIME, CLOCK_REALTIME) (CLOCK_THREAD_CPUTIME_ID, timer_t): New definitions. * src/w32proc.c (struct itimer_data, stop_timer_thread): (start_timer_thread): Clock type is now clockid_t, not int. All uses changed. (timer_create, timer_gettime, timer_settime): New functions, replacing getitimer and setitimer. All uses changed. --- nt/inc/sys/time.h | 38 +++++++++--- src/w32proc.c | 143 ++++++++++++++++++++++++---------------------- 2 files changed, 106 insertions(+), 75 deletions(-) diff --git a/nt/inc/sys/time.h b/nt/inc/sys/time.h index 6f67e5db4e..d03bc456ea 100644 --- a/nt/inc/sys/time.h +++ b/nt/inc/sys/time.h @@ -3,19 +3,41 @@ #include_next -#define ITIMER_REAL 0 -#define ITIMER_PROF 1 +struct itimerspec +{ + struct timespec it_interval; /* timer interval */ + struct timespec it_value; /* current value */ +}; -struct itimerval +typedef struct pthread_attr_t *pthread_attr_t; +union sigval +{ + int sival_int; + void *sival_ptr; +}; +struct sigevent { - struct timeval it_interval; /* timer interval */ - struct timeval it_value; /* current value */ + int sigev_notify; + int sigev_signo; + union sigval sigev_value; + void (*sigev_notify_function) (union sigval); + pthread_attr_t *sigev_notify_attributes; }; +#define SIGEV_SIGNAL 0 -int getitimer (int, struct itimerval *); -int setitimer (int, struct itimerval *, struct itimerval *); +#define TIMER_ABSTIME 1 +typedef enum { CLOCK_REALTIME, CLOCK_THREAD_CPUTIME_ID } clockid_t; +#define CLOCK_REALTIME CLOCK_REALTIME +#define CLOCK_THREAD_CPUTIME_ID CLOCK_THREAD_CPUTIME_ID +typedef struct +{ + clockid_t clockid; +} timer_t; +int timer_create (clockid_t, struct sigevent *restrict, timer_t *restrict); +int timer_settime (timer_t, int, struct itimerspec const *, + struct itimerspec *restrict); +int timer_getoverrun (timer_t); #endif /* SYS_TIME_H_INCLUDED */ /* end of sys/time.h */ - diff --git a/src/w32proc.c b/src/w32proc.c index cb02ba6341..23869768cf 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -89,7 +89,7 @@ sys_signal (int sig, signal_handler handler) signal_handler old; /* SIGCHLD is needed for supporting subprocesses, see sys_kill - below. SIGALRM and SIGPROF are used by setitimer. All the + below. SIGALRM and SIGPROF are used by timer_settime. All the others are the only ones supported by the MS runtime. */ if (!(sig == SIGINT || sig == SIGSEGV || sig == SIGILL || sig == SIGFPE || sig == SIGABRT || sig == SIGTERM @@ -261,7 +261,8 @@ setsid (void) /* Emulations of interval timers. - Limitations: only ITIMER_REAL and ITIMER_PROF are supported. + Limitations: only CLOCK_REALTIME and CLOCK_THREAD_CPUTIME_ID are + supported, and only a single timer of each time is supported. Implementation: a separate thread is started for each timer type, the thread calls the appropriate signal handler when the timer @@ -271,7 +272,7 @@ struct itimer_data { volatile ULONGLONG expire; volatile ULONGLONG reload; volatile int terminate; - int type; + clockid_t type; HANDLE caller_thread; HANDLE timer_thread; }; @@ -357,11 +358,11 @@ static DWORD WINAPI timer_loop (LPVOID arg) { struct itimer_data *itimer = (struct itimer_data *)arg; - int which = itimer->type; - int sig = (which == ITIMER_REAL) ? SIGALRM : SIGPROF; - CRITICAL_SECTION *crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof; + bool realtime = itimer->type == CLOCK_REALTIME; + int sig = realtime ? SIGALRM : SIGPROF; + CRITICAL_SECTION *crit = realtime ? &crit_real : &crit_prof; const DWORD max_sleep = MAX_SINGLE_SLEEP * 1000 / TIMER_TICKS_PER_SEC; - HANDLE hth = (which == ITIMER_REAL) ? NULL : itimer->caller_thread; + HANDLE hth = realtime ? NULL : itimer->caller_thread; while (1) { @@ -369,7 +370,7 @@ timer_loop (LPVOID arg) signal_handler handler; ULONGLONG now, expire, reload; - /* Load new values if requested by setitimer. */ + /* Load new values if requested by timer_settime. */ EnterCriticalSection (crit); expire = itimer->expire; reload = itimer->reload; @@ -480,10 +481,10 @@ timer_loop (LPVOID arg) } static void -stop_timer_thread (int which) +stop_timer_thread (clockid_t clockid) { struct itimer_data *itimer = - (which == ITIMER_REAL) ? &real_itimer : &prof_itimer; + clockid == CLOCK_REALTIME ? &real_itimer : &prof_itimer; int i; DWORD err = 0, exit_code = 255; BOOL status; @@ -526,9 +527,9 @@ void term_timers (void) { if (real_itimer.timer_thread) - stop_timer_thread (ITIMER_REAL); + stop_timer_thread (CLOCK_REALTIME); if (prof_itimer.timer_thread) - stop_timer_thread (ITIMER_PROF); + stop_timer_thread (CLOCK_THREAD_CPUTIME_ID); /* We are going to delete the critical sections, so timers cannot work after this. */ @@ -564,12 +565,12 @@ init_timers (void) } static int -start_timer_thread (int which) +start_timer_thread (clockid_t clockid) { DWORD exit_code, tid; HANDLE th; struct itimer_data *itimer = - (which == ITIMER_REAL) ? &real_itimer : &prof_itimer; + clockid == CLOCK_REALTIME ? &real_itimer : &prof_itimer; if (itimer->timer_thread && GetExitCodeThread (itimer->timer_thread, &exit_code) @@ -597,7 +598,7 @@ start_timer_thread (int which) return -1; } itimer->terminate = 0; - itimer->type = which; + itimer->type = clockid; itimer->caller_thread = th; /* Request that no more than 64KB of stack be reserved for this thread, to avoid reserving too much memory, which would get in @@ -616,24 +617,42 @@ start_timer_thread (int which) /* This is needed to make sure that the timer thread running for profiling gets CPU as soon as the Sleep call terminates. */ - if (which == ITIMER_PROF) + if (clockid == CLOCK_THREAD_CPUTIME_ID) SetThreadPriority (itimer->timer_thread, THREAD_PRIORITY_TIME_CRITICAL); return 0; } -/* Most of the code of getitimer and setitimer (but not of their +int +timer_create (clockid_t clockid, struct sigevent *restrict evp, + timer_t *restrict timerid) +{ + if ((clockid == CLOCK_REALTIME || clockid == CLOCK_THREAD_CPUTIME_ID) + && (!evp || (evp->sigev_notify == SIGEV_SIGNAL + && evp->sigev_signo == (clockid == CLOCK_REALTIME + ? SIGALRM : SIGPROF) + && evp->sigev_value.sival_ptr == timerid))) + { + timerid->clockid = clockid; + return 0; + } + errno = EINVAL; + return -1; +} + +/* Most of the code of timer_gettime and timer_settime (but not of their subroutines) was shamelessly stolen from itimer.c in the DJGPP library, see www.delorie.com/djgpp. */ int -getitimer (int which, struct itimerval *value) +timer_gettime (timer_t timerid, struct itimerspec *value) { volatile ULONGLONG *t_expire; volatile ULONGLONG *t_reload; ULONGLONG expire, reload; - __int64 usecs; CRITICAL_SECTION *crit; struct itimer_data *itimer; + HANDLE thread_hand; + bool realtime = timerid.clockid == CLOCK_REALTIME; if (disable_itimers) return -1; @@ -644,21 +663,18 @@ getitimer (int which, struct itimerval *value) return -1; } - if (which != ITIMER_REAL && which != ITIMER_PROF) - { - errno = EINVAL; - return -1; - } - - itimer = (which == ITIMER_REAL) ? &real_itimer : &prof_itimer; + itimer = realtime ? &real_itimer : &prof_itimer; - ticks_now = w32_get_timer_time ((which == ITIMER_REAL) + ticks_now = w32_get_timer_time (realtime ? NULL : GetCurrentThread ()); + itimer = realtime ? &real_itimer : &prof_itimer; + + ticks_now = w32_get_timer_time (thread_hand); t_expire = &itimer->expire; t_reload = &itimer->reload; - crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof; + crit = realtime ? &crit_real : &crit_prof; EnterCriticalSection (crit); reload = *t_reload; @@ -669,25 +685,25 @@ getitimer (int which, struct itimerval *value) expire -= ticks_now; value->it_value.tv_sec = expire / TIMER_TICKS_PER_SEC; - usecs = - (expire % TIMER_TICKS_PER_SEC) * (__int64)1000000 / TIMER_TICKS_PER_SEC; - value->it_value.tv_usec = usecs; + value->it_value.tv_nsec = (expire % TIMER_TICKS_PER_SEC + * (1000000000 / TIMER_TICKS_PER_SEC)); value->it_interval.tv_sec = reload / TIMER_TICKS_PER_SEC; - usecs = - (reload % TIMER_TICKS_PER_SEC) * (__int64)1000000 / TIMER_TICKS_PER_SEC; - value->it_interval.tv_usec= usecs; - + value->it_interval.tv_nsec= (reload % TIMER_TICKS_PER_SEC + * (1000000000 / TIMER_TICKS_PER_SEC)); return 0; } int -setitimer(int which, struct itimerval *value, struct itimerval *ovalue) +timer_settime (timer_t timerid, int flags, + struct itimerspec const *restrict value, + struct itimerspec *restrict ovalue) { volatile ULONGLONG *t_expire, *t_reload; ULONGLONG expire, reload, expire_old, reload_old; - __int64 usecs; + int ns; CRITICAL_SECTION *crit; - struct itimerval tem, *ptem; + struct itimerspec tem, *ptem; + bool realtime = timerid.clockid == CLOCK_REALTIME; if (disable_itimers) return -1; @@ -710,18 +726,15 @@ setitimer(int which, struct itimerval *value, struct itimerval *ovalue) else ptem = &tem; - if (getitimer (which, ptem)) /* also sets ticks_now */ + if (timer_gettime (timerid, ptem)) /* also sets ticks_now */ return -1; /* errno already set */ - t_expire = - (which == ITIMER_REAL) ? &real_itimer.expire : &prof_itimer.expire; - t_reload = - (which == ITIMER_REAL) ? &real_itimer.reload : &prof_itimer.reload; - - crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof; + t_expire = realtime ? &real_itimer.expire : &prof_itimer.expire; + t_reload = realtime ? &real_itimer.reload : &prof_itimer.reload; + crit = realtime ? &crit_real : &crit_prof; if (!value - || (value->it_value.tv_sec == 0 && value->it_value.tv_usec == 0)) + || (value->it_value.tv_sec == 0 && value->it_value.tv_nsec == 0)) { EnterCriticalSection (crit); /* Disable the timer. */ @@ -733,28 +746,23 @@ setitimer(int which, struct itimerval *value, struct itimerval *ovalue) reload = value->it_interval.tv_sec * TIMER_TICKS_PER_SEC; - usecs = value->it_interval.tv_usec; + ns = value->it_interval.tv_nsec; if (value->it_interval.tv_sec == 0 - && usecs && usecs * TIMER_TICKS_PER_SEC < clocks_min * 1000000) + && 0 < ns && ns < clocks_min * (1000000000 / TIMER_TICKS_PER_SEC)) reload = clocks_min; else - { - usecs *= TIMER_TICKS_PER_SEC; - reload += usecs / 1000000; - } + reload += ns / (1000000000 / TIMER_TICKS_PER_SEC); - expire = value->it_value.tv_sec * TIMER_TICKS_PER_SEC; - usecs = value->it_value.tv_usec; - if (value->it_value.tv_sec == 0 - && usecs * TIMER_TICKS_PER_SEC < clocks_min * 1000000) + expire = ex.tv_sec * TIMER_TICKS_PER_SEC; + ns = ex.tv_nsec; + if (ex.tv_sec == 0 + && 0 < ns && ns < clocks_min * (1000000000 / TIMER_TICKS_PER_SEC)) expire = clocks_min; else - { - usecs *= TIMER_TICKS_PER_SEC; - expire += usecs / 1000000; - } + reload += ns / (1000000000 / TIMER_TICKS_PER_SEC); - expire += ticks_now; + if (flags & TIMER_ABSTIME) + expire += ticks_now; EnterCriticalSection (crit); expire_old = *t_expire; @@ -766,20 +774,21 @@ setitimer(int which, struct itimerval *value, struct itimerval *ovalue) } LeaveCriticalSection (crit); - return start_timer_thread (which); + return start_timer_thread (timerid.clockid); } int alarm (int seconds) { -#ifdef HAVE_SETITIMER - struct itimerval new_values, old_values; +#ifdef HAVE_ITIMERSPEC + struct itimerspec new_values, old_values; new_values.it_value.tv_sec = seconds; - new_values.it_value.tv_usec = 0; - new_values.it_interval.tv_sec = new_values.it_interval.tv_usec = 0; + new_values.it_value.tv_nsec = 0; + new_values.it_interval.tv_sec = new_values.it_interval.tv_nsec = 0; - if (setitimer (ITIMER_REAL, &new_values, &old_values) < 0) + timer_t id = { .clockid = CLOCK_REALTIME }; + if (timer_settime (id, 0, &new_values, &old_values) < 0) return 0; return old_values.it_value.tv_sec; #else -- 2.17.1