diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 7f5cae4cb..61060a8cc 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,31 @@ +2011-05-17 Yaakov Selkowitz + + * cygwin.din (clock_getcpuclockid): Export. + (pthread_getcpuclockid): Export. + * hires.h (PID_TO_CLOCKID): New macro. + (CLOCKID_TO_PID): New macro. + (CLOCKID_IS_PROCESS): New macro. + (THREADID_TO_CLOCKID): New macro. + (CLOCKID_TO_THREADID): New macro. + (CLOCKID_IS_THREAD): New macro. + * ntdll.h (enum _THREAD_INFORMATION_CLASS): Add ThreadTimes. + * posix.sgml (std-notimpl): Add clock_getcpuclockid and + pthread_getcpuclockid from here... + (std-susv4): ... to here. + (std-notes): Remove limitations of clock_getres and clock_gettime. + Note limitation of timer_create to CLOCK_REALTIME. + * sysconf.cc (sca): Set _SC_CPUTIME to _POSIX_CPUTIME, and + _SC_THREAD_CPUTIME to _POSIX_THREAD_CPUTIME. + * thread.cc (pthread_getcpuclockid): New function. + * timer.cc (timer_create): Set errno to ENOTSUP for CPU-time clocks. + * times.cc (clock_gettime): Handle CLOCK_PROCESS_CPUTIME_ID and + CLOCK_THREAD_CPUTIME_ID. + (clock_getres): Ditto. + (clock_settime): Set errno to EPERM for CPU-time clocks. + (clock_getcpuclockid): New function. + * include/pthread.h (pthread_getcpuclockid): Declare. + * include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump. + 2011-05-17 Corinna Vinschen * miscfuncs.cc (thread_wrapper): Remove unused _cygtls record. diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 12c3f3d57..8d1e7032e 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -217,6 +217,7 @@ clearerr SIGFE _clearerr = clearerr SIGFE clock SIGFE _clock = clock SIGFE +clock_getcpuclockid SIGFE clock_getres SIGFE clock_gettime SIGFE clock_setres SIGFE @@ -1212,6 +1213,7 @@ pthread_equal SIGFE pthread_exit SIGFE pthread_getattr_np SIGFE pthread_getconcurrency SIGFE +pthread_getcpuclockid SIGFE pthread_getschedparam SIGFE pthread_getsequence_np SIGFE pthread_getspecific SIGFE diff --git a/winsup/cygwin/hires.h b/winsup/cygwin/hires.h index 0acfafdbd..15c8d209d 100644 --- a/winsup/cygwin/hires.h +++ b/winsup/cygwin/hires.h @@ -13,6 +13,14 @@ details. */ #include +/* Conversions for per-process and per-thread clocks */ +#define PID_TO_CLOCKID(pid) (pid * 8 + CLOCK_PROCESS_CPUTIME_ID) +#define CLOCKID_TO_PID(cid) ((cid - CLOCK_PROCESS_CPUTIME_ID) / 8) +#define CLOCKID_IS_PROCESS(cid) ((cid % 8) == CLOCK_PROCESS_CPUTIME_ID) +#define THREADID_TO_CLOCKID(tid) (tid * 8 + CLOCK_THREAD_CPUTIME_ID) +#define CLOCKID_TO_THREADID(cid) ((cid - CLOCK_THREAD_CPUTIME_ID) / 8) +#define CLOCKID_IS_THREAD(cid) ((cid % 8) == CLOCK_THREAD_CPUTIME_ID) + /* Largest delay in ms for sleep and alarm calls. Allow actual delay to exceed requested delay by 10 s. Express as multiple of 1000 (i.e. seconds) + max resolution diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index ea66d4097..fed1c0ccc 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -412,12 +412,14 @@ details. */ 244: Export clock_settime. 245: Export pthread_attr_getguardsize, pthread_attr_setguardsize, pthread_attr_setstack, pthread_attr_setstackaddr. + 246: Add CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID. + Export clock_getcpuclockid, pthread_getcpuclockid. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 245 +#define CYGWIN_VERSION_API_MINOR 246 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/pthread.h b/winsup/cygwin/include/pthread.h index e963eba54..4ed53ab08 100644 --- a/winsup/cygwin/include/pthread.h +++ b/winsup/cygwin/include/pthread.h @@ -141,6 +141,7 @@ int pthread_create (pthread_t *, const pthread_attr_t *, int pthread_detach (pthread_t); int pthread_equal (pthread_t, pthread_t); void pthread_exit (void *); +int pthread_getcpuclockid (pthread_t, clockid_t *); int pthread_getschedparam (pthread_t, int *, struct sched_param *); void *pthread_getspecific (pthread_key_t); int pthread_join (pthread_t, void **); diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 9c5597ec1..77aeeece0 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -938,6 +938,7 @@ typedef enum _EVENT_INFORMATION_CLASS typedef enum _THREAD_INFORMATION_CLASS { ThreadBasicInformation = 0, + ThreadTimes = 1, ThreadImpersonationToken = 5 } THREAD_INFORMATION_CLASS, *PTHREAD_INFORMATION_CLASS; diff --git a/winsup/cygwin/posix.sgml b/winsup/cygwin/posix.sgml index a576b353f..f6ec0b0e2 100644 --- a/winsup/cygwin/posix.sgml +++ b/winsup/cygwin/posix.sgml @@ -90,8 +90,9 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008). cimagf clearerr clock - clock_getres (see chapter "Implementation Notes") - clock_gettime (see chapter "Implementation Notes") + clock_getcpuclockid + clock_getres + clock_gettime clock_settime (see chapter "Implementation Notes") clog clogf @@ -564,6 +565,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008). pthread_equal pthread_exit pthread_getconcurrency + pthread_getcpuclockid pthread_getschedparam pthread_getspecific pthread_join @@ -836,7 +838,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008). tgamma tgammaf time - timer_create + timer_create (see chapter "Implementation Notes") timer_delete timer_gettime timer_settime @@ -1292,7 +1294,6 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008). ceill cexpl cimagl - clock_getcpuclockid clogl conjl copysignl @@ -1386,7 +1387,6 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008). pthread_barrier[...] pthread_condattr_getclock pthread_condattr_setclock - pthread_getcpuclockid pthread_mutexattr_getrobust pthread_mutexattr_setrobust pthread_mutex_consistent @@ -1441,9 +1441,8 @@ by keeping track of the current root and accomodating this in the file related function calls. A real chroot functionality is not supported by Windows however. -clock_getres and clock_gettime -only support CLOCK_REALTIME and CLOCK_MONOTONIC for now. clock_setres -and clock_settime only support CLOCK_REALTIME. +clock_setres, clock_settime, and +timer_create only support CLOCK_REALTIME. BSD file locks created via flock are not propagated to the parent process and sibling processes. The locks are diff --git a/winsup/cygwin/sysconf.cc b/winsup/cygwin/sysconf.cc index 73c44fe36..0dbb17610 100644 --- a/winsup/cygwin/sysconf.cc +++ b/winsup/cygwin/sysconf.cc @@ -160,7 +160,7 @@ static struct {cons, {c:BC_STRING_MAX}}, /* 60, _SC_BC_STRING_MAX */ {cons, {c:-1L}}, /* 61, _SC_CLOCK_SELECTION */ {nsup, {c:0}}, /* 62, _SC_COLL_WEIGHTS_MAX */ - {cons, {c:-1L}}, /* 63, _SC_CPUTIME */ + {cons, {c:_POSIX_CPUTIME}}, /* 63, _SC_CPUTIME */ {cons, {c:EXPR_NEST_MAX}}, /* 64, _SC_EXPR_NEST_MAX */ {cons, {c:HOST_NAME_MAX}}, /* 65, _SC_HOST_NAME_MAX */ {cons, {c:IOV_MAX}}, /* 66, _SC_IOV_MAX */ @@ -177,7 +177,7 @@ static struct {cons, {c:-1L}}, /* 77, _SC_SPORADIC_SERVER */ {nsup, {c:0}}, /* 78, _SC_SS_REPL_MAX */ {cons, {c:SYMLOOP_MAX}}, /* 79, _SC_SYMLOOP_MAX */ - {cons, {c:-1L}}, /* 80, _SC_THREAD_CPUTIME */ + {cons, {c:_POSIX_THREAD_CPUTIME}}, /* 80, _SC_THREAD_CPUTIME */ {cons, {c:-1L}}, /* 81, _SC_THREAD_SPORADIC_SERVER */ {cons, {c:-1L}}, /* 82, _SC_TIMEOUTS */ {cons, {c:-1L}}, /* 83, _SC_TRACE */ diff --git a/winsup/cygwin/thread.cc b/winsup/cygwin/thread.cc index b53fc7f70..c70709bff 100644 --- a/winsup/cygwin/thread.cc +++ b/winsup/cygwin/thread.cc @@ -2510,6 +2510,15 @@ pthread_getconcurrency () return MT_INTERFACE->concurrency; } +extern "C" int +pthread_getcpuclockid (pthread_t thread, clockid_t *clk_id) +{ + if (!pthread::is_good_object (&thread)) + return (ESRCH); + *clk_id = (clockid_t) THREADID_TO_CLOCKID (thread->getsequence_np ()); + return 0; +} + /* keep this in sync with sched.cc */ extern "C" int pthread_getschedparam (pthread_t thread, int *policy, diff --git a/winsup/cygwin/timer.cc b/winsup/cygwin/timer.cc index 91e71146c..be740e07a 100644 --- a/winsup/cygwin/timer.cc +++ b/winsup/cygwin/timer.cc @@ -300,6 +300,13 @@ timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid) myfault efault; if (efault.faulted (EFAULT)) return -1; + + if (CLOCKID_IS_PROCESS (clock_id) || CLOCKID_IS_THREAD (clock_id)) + { + set_errno (ENOTSUP); + return -1; + } + if (clock_id != CLOCK_REALTIME) { set_errno (EINVAL); diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc index 4e6697e76..6bb68ecd1 100644 --- a/winsup/cygwin/times.cc +++ b/winsup/cygwin/times.cc @@ -15,6 +15,7 @@ details. */ #include #include #include +#include #include "cygerrno.h" #include "security.h" #include "path.h" @@ -22,6 +23,7 @@ details. */ #include "dtable.h" #include "cygheap.h" #include "pinfo.h" +#include "thread.h" #include "cygtls.h" #include "ntdll.h" @@ -594,6 +596,63 @@ hires_ms::nsecs () extern "C" int clock_gettime (clockid_t clk_id, struct timespec *tp) { + if (CLOCKID_IS_PROCESS (clk_id)) + { + pid_t pid = CLOCKID_TO_PID (clk_id); + HANDLE hProcess; + KERNEL_USER_TIMES kut; + ULONG sizeof_kut = sizeof (KERNEL_USER_TIMES); + long long x; + + if (pid == 0) + pid = getpid (); + + pinfo p (pid); + if (!p->exists ()) + { + set_errno (EINVAL); + return -1; + } + + hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, 0, p->dwProcessId); + NtQueryInformationProcess (hProcess, ProcessTimes, &kut, sizeof_kut, &sizeof_kut); + + x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart; + tp->tv_sec = x / (long long) NSPERSEC; + tp->tv_nsec = (x % (long long) NSPERSEC) * 100LL; + + CloseHandle (hProcess); + return 0; + } + + if (CLOCKID_IS_THREAD (clk_id)) + { + long thr_id = CLOCKID_TO_THREADID (clk_id); + HANDLE hThread; + KERNEL_USER_TIMES kut; + ULONG sizeof_kut = sizeof (KERNEL_USER_TIMES); + long long x; + + if (thr_id == 0) + thr_id = pthread::self ()->getsequence_np (); + + hThread = OpenThread (THREAD_QUERY_INFORMATION, 0, thr_id); + if (!hThread) + { + set_errno (EINVAL); + return -1; + } + + NtQueryInformationThread (hThread, ThreadTimes, &kut, sizeof_kut, &sizeof_kut); + + x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart; + tp->tv_sec = x / (long long) NSPERSEC; + tp->tv_nsec = (x % (long long) NSPERSEC) * 100LL; + + CloseHandle (hThread); + return 0; + } + switch (clk_id) { case CLOCK_REALTIME: @@ -630,6 +689,16 @@ clock_settime (clockid_t clk_id, const struct timespec *tp) { struct timeval tv; + if (CLOCKID_IS_PROCESS (clk_id) || CLOCKID_IS_THREAD (clk_id)) + /* According to POSIX, the privileges to set a particular clock + * are implementation-defined. On Linux, CPU-time clocks are not + * settable; do the same here. + */ + { + set_errno (EPERM); + return -1; + } + if (clk_id != CLOCK_REALTIME) { set_errno (EINVAL); @@ -702,6 +771,16 @@ hires_ms::resolution () extern "C" int clock_getres (clockid_t clk_id, struct timespec *tp) { + if (CLOCKID_IS_PROCESS (clk_id) || CLOCKID_IS_THREAD (clk_id)) + { + ULONG coarsest, finest, actual; + + NtQueryTimerResolution (&coarsest, &finest, &actual); + tp->tv_sec = coarsest / NSPERSEC; + tp->tv_nsec = (coarsest % NSPERSEC) * 100; + return 0; + } + switch (clk_id) { case CLOCK_REALTIME: @@ -776,3 +855,12 @@ clock_setres (clockid_t clk_id, struct timespec *tp) period_set = true; return 0; } + +extern "C" int +clock_getcpuclockid (pid_t pid, clockid_t *clk_id) +{ + if (pid != 0 && !pinfo (pid)->exists ()) + return (ESRCH); + *clk_id = (clockid_t) PID_TO_CLOCKID (pid); + return 0; +}