public inbox for cygwin-patches@cygwin.com
 help / color / mirror / Atom feed
* [PATCH] CPU-time clocks
@ 2011-05-15 18:37 Yaakov (Cygwin/X)
  2011-05-15 19:12 ` Corinna Vinschen
  0 siblings, 1 reply; 8+ messages in thread
From: Yaakov (Cygwin/X) @ 2011-05-15 18:37 UTC (permalink / raw)
  To: cygwin-patches

[-- Attachment #1: Type: text/plain, Size: 2162 bytes --]

The attached patches implement POSIX CPU-time clock support:

http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getcpuclockid.html
http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getcpuclockid.html
http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_gettime.html
http://www.kernel.org/doc/man-pages/online/pages/man3/clock_getcpuclockid.3.html
http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_getcpuclockid.3.html
http://www.kernel.org/doc/man-pages/online/pages/man3/clock_gettime.3.html

There are several things I need to note:

1) Unfortunately newlib's variable naming doesn't currently comply with
POSIX.  Fixing this will affect RTEMS, so this will need to be worked
out on the newlib list.

2) On Linux, clockid_t is a signed int, and glibc uses negative clock
IDs for processes and threads (e.g. clock_getcpuclockid returns -6 -
pid*8 for the given pid).  However, newlib's clockid_t is a unsigned
long, so I've chosen a slightly-different numbering scheme which makes
the code a bit cleaner.  While the scheme is arbitrary and could be
changed at any time, that should only be necessary if several more fixed
clock IDs are required in the future (a (clockid_t)10 would be mistaken
for a CPU-time clock for PID 1); right now POSIX defines only four fixed
clock IDs.

3) timer_create(2) needs to be reworked to support clocks other than
CLOCK_REALTIME.  For now, I'm falling back to the ENOTSUP case allowed
by POSIX, but this should be reexamined after reworking timer_create.

4) As noted in the comments, POSIX says that the permissions required to
set any particular clock are implementation-defined.  On Linux, CPU-time
clocks are not settable (IOW no process has such permissions); I have
done the same here.

5) The clock_getres(3) code is based on my findings on my system (156001
100ns on W7 x64); I'd appreciate some confirmation for other systems.

6) On Linux, clock_getres(3) does not appear to verify if a (potential)
CPU-time clock actually exists.

Patches for newlib, winsup/cygwin, and winsup/doc, along with test
programs for the new and affected functions, attached.


Yaakov


[-- Attachment #2: newlib-cpuclockid.patch --]
[-- Type: text/x-patch, Size: 2118 bytes --]

2011-05-12  Yaakov Selkowitz  <yselkowitz@...>

	* libc/include/time.h (CLOCK_PROCESS_CPUTIME_ID): Rename from
	CLOCK_PROCESS_CPUTIME.
	(CLOCK_THREAD_CPUTIME_ID): Rename from CLOCK_THREAD_CPUTIME.
	* libc/include/sys/features.h [__CYGWIN__] (_POSIX_CPUTIME): Define.
	(_POSIX_THREAD_CPUTIME): Define.

Index: libc/include/time.h
===================================================================
RCS file: /cvs/src/src/newlib/libc/include/time.h,v
retrieving revision 1.19
diff -u -r1.19 time.h
--- libc/include/time.h	16 Oct 2008 21:53:58 -0000	1.19
+++ libc/include/time.h	8 May 2011 23:56:27 -0000
@@ -212,7 +212,7 @@
    the identifier of the CPU_time clock associated with the PROCESS
    making the function call.  */
 
-#define CLOCK_PROCESS_CPUTIME (clockid_t)2
+#define CLOCK_PROCESS_CPUTIME_ID (clockid_t)2
 
 #endif
 
@@ -222,7 +222,7 @@
     the identifier of the CPU_time clock associated with the THREAD
     making the function call.  */
 
-#define CLOCK_THREAD_CPUTIME (clockid_t)3
+#define CLOCK_THREAD_CPUTIME_ID (clockid_t)3
 
 #endif
 
Index: libc/include/sys/features.h
===================================================================
RCS file: /cvs/src/src/newlib/libc/include/sys/features.h,v
retrieving revision 1.24
diff -u -r1.24 features.h
--- libc/include/sys/features.h	2 May 2011 16:05:06 -0000	1.24
+++ libc/include/sys/features.h	8 May 2011 23:56:27 -0000
@@ -103,7 +103,7 @@
 /* #define _POSIX_BARRIERS			    -1 */
 #define _POSIX_CHOWN_RESTRICTED			     1
 /* #define _POSIX_CLOCK_SELECTION		    -1 */
-/* #define _POSIX_CPUTIME			    -1 */
+#define _POSIX_CPUTIME			    	200112L
 #define _POSIX_FSYNC				200112L
 #define _POSIX_IPV6				200112L
 #define _POSIX_JOB_CONTROL			     1
@@ -130,7 +130,7 @@
 #define _POSIX_SYNCHRONIZED_IO			200112L
 /* #define _POSIX_THREAD_ATTR_STACKADDR		    -1 */
 #define _POSIX_THREAD_ATTR_STACKSIZE		200112L
-/* #define _POSIX_THREAD_CPUTIME		    -1 */
+#define _POSIX_THREAD_CPUTIME			200112L
 /* #define _POSIX_THREAD_PRIO_INHERIT		    -1 */
 /* #define _POSIX_THREAD_PRIO_PROTECT		    -1 */
 #define _POSIX_THREAD_PRIORITY_SCHEDULING	200112L

[-- Attachment #3: cpuclockid.patch --]
[-- Type: text/x-patch, Size: 12385 bytes --]

2011-05-15  Yaakov Selkowitz  <yselkowitz@...>

	* cygwin.din (clock_getcpuclockid): Export.
	(pthread_getcpuclockid): Export.
	* 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.
	* winsup.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.
	* include/pthread.h (pthread_getcpuclockid): Declare.
	* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.

Index: cygwin.din
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/cygwin.din,v
retrieving revision 1.240
diff -u -r1.240 cygwin.din
--- cygwin.din	9 May 2011 08:57:46 -0000	1.240
+++ cygwin.din	13 May 2011 04:02:33 -0000
@@ -217,6 +217,7 @@
 _clearerr = clearerr SIGFE
 clock SIGFE
 _clock = clock SIGFE
+clock_getcpuclockid SIGFE
 clock_getres SIGFE
 clock_gettime SIGFE
 clock_setres SIGFE
@@ -1208,6 +1209,7 @@
 pthread_exit SIGFE
 pthread_getattr_np SIGFE
 pthread_getconcurrency SIGFE
+pthread_getcpuclockid SIGFE
 pthread_getschedparam SIGFE
 pthread_getsequence_np SIGFE
 pthread_getspecific SIGFE
Index: posix.sgml
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/posix.sgml,v
retrieving revision 1.62
diff -u -r1.62 posix.sgml
--- posix.sgml	9 May 2011 08:57:46 -0000	1.62
+++ posix.sgml	13 May 2011 04:02:33 -0000
@@ -90,8 +90,9 @@
     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
@@ -561,6 +562,7 @@
     pthread_equal
     pthread_exit
     pthread_getconcurrency
+    pthread_getcpuclockid
     pthread_getschedparam
     pthread_getspecific
     pthread_join
@@ -833,7 +835,7 @@
     tgamma
     tgammaf
     time
-    timer_create
+    timer_create		(see chapter "Implementation Notes")
     timer_delete
     timer_gettime
     timer_settime
@@ -1288,7 +1290,6 @@
     ceill
     cexpl
     cimagl
-    clock_getcpuclockid
     clogl
     conjl
     copysignl
@@ -1385,7 +1386,6 @@
     pthread_barrier[...]
     pthread_condattr_getclock
     pthread_condattr_setclock
-    pthread_getcpuclockid
     pthread_mutexattr_getrobust
     pthread_mutexattr_setrobust
     pthread_mutex_consistent
@@ -1440,9 +1440,8 @@
 related function calls.  A real chroot functionality is not supported by
 Windows however.</para>
 
-<para><function>clock_getres</function> and <function>clock_gettime</function>
-only support CLOCK_REALTIME and CLOCK_MONOTONIC for now.  <function>clock_setres</function>
-and <function>clock_settime</function> only support CLOCK_REALTIME.</para>
+<function>clock_setres</function>, <function>clock_settime</function>, and
+<function>timer_create</function> only support CLOCK_REALTIME.</para>
 
 <para>BSD file locks created via <function>flock</function> are not
 propagated to the parent process and sibling processes.  The locks are
Index: sysconf.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/sysconf.cc,v
retrieving revision 1.56
diff -u -r1.56 sysconf.cc
--- sysconf.cc	6 May 2011 18:53:21 -0000	1.56
+++ sysconf.cc	13 May 2011 04:02:33 -0000
@@ -160,7 +160,7 @@
   {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 @@
   {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 */
Index: thread.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/thread.cc,v
retrieving revision 1.238
diff -u -r1.238 thread.cc
--- thread.cc	4 May 2011 06:16:59 -0000	1.238
+++ thread.cc	13 May 2011 04:02:34 -0000
@@ -2461,6 +2461,15 @@
   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,
Index: timer.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/timer.cc,v
retrieving revision 1.26
diff -u -r1.26 timer.cc
--- timer.cc	1 Sep 2010 18:24:11 -0000	1.26
+++ timer.cc	15 May 2011 16:35:46 -0000
@@ -300,6 +300,13 @@
   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);
Index: times.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/times.cc,v
retrieving revision 1.108
diff -u -r1.108 times.cc
--- times.cc	9 May 2011 08:57:46 -0000	1.108
+++ times.cc	13 May 2011 04:02:34 -0000
@@ -15,6 +15,7 @@
 #include <sys/timeb.h>
 #include <utime.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include "cygerrno.h"
 #include "security.h"
 #include "path.h"
@@ -22,6 +23,7 @@
 #include "dtable.h"
 #include "cygheap.h"
 #include "pinfo.h"
+#include "thread.h"
 #include "cygtls.h"
 #include "ntdll.h"
 
@@ -594,6 +596,62 @@
 extern "C" int
 clock_gettime (clockid_t clk_id, struct timespec *tp)
 {
+  if (CLOCKID_IS_PROCESS (clk_id))
+    {
+      FILETIME creation_time, exit_time, kernel_time, user_time;
+      pid_t pid = CLOCKID_TO_PID (clk_id);
+      HANDLE hProcess;
+      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);
+      GetProcessTimes (hProcess, &creation_time, &exit_time, &kernel_time, &user_time);
+
+      x = ((long long) kernel_time.dwHighDateTime << 32) + ((unsigned) kernel_time.dwLowDateTime)
+          + ((long long) user_time.dwHighDateTime << 32) + ((unsigned) user_time.dwLowDateTime);
+      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))
+    {
+      FILETIME creation_time, exit_time, kernel_time, user_time;
+      long thr_id = CLOCKID_TO_THREADID (clk_id);
+      HANDLE hThread;
+      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;
+        }
+
+      GetThreadTimes (hThread, &creation_time, &exit_time, &kernel_time, &user_time);
+      x = ((long long) kernel_time.dwHighDateTime << 32) + ((unsigned) kernel_time.dwLowDateTime)
+          + ((long long) user_time.dwHighDateTime << 32) + ((unsigned) user_time.dwLowDateTime);
+      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 +688,16 @@
 {
   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 +770,16 @@
 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 +854,12 @@
   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;
+}
Index: winsup.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/winsup.h,v
retrieving revision 1.235
diff -u -r1.235 winsup.h
--- winsup.h	19 Apr 2011 10:02:06 -0000	1.235
+++ winsup.h	13 May 2011 04:02:34 -0000
@@ -220,6 +220,13 @@
 void *hook_or_detect_cygwin (const char *, const void *, WORD&) __attribute__ ((regparm (3)));
 
 /* Time related */
+#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)
+
 void __stdcall totimeval (struct timeval *, FILETIME *, int, int);
 long __stdcall to_time_t (FILETIME *);
 void __stdcall to_timestruc_t (FILETIME *, timestruc_t *);
Index: include/pthread.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/pthread.h,v
retrieving revision 1.31
diff -u -r1.31 pthread.h
--- include/pthread.h	3 May 2011 01:13:37 -0000	1.31
+++ include/pthread.h	15 May 2011 09:51:38 -0000
@@ -139,6 +139,7 @@
 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 **);
Index: include/cygwin/version.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/cygwin/version.h,v
retrieving revision 1.345
diff -u -r1.345 version.h
--- include/cygwin/version.h	9 May 2011 08:57:46 -0000	1.345
+++ include/cygwin/version.h	13 May 2011 04:02:34 -0000
@@ -410,12 +410,14 @@
       242: Export psiginfo, psignal, sys_siglist.
       243: Export sysinfo.
       244: Export clock_settime.
+      245: 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 244
+#define CYGWIN_VERSION_API_MINOR 245
 
      /* There is also a compatibity version number associated with the
 	shared memory regions.  It is incremented when incompatible

[-- Attachment #4: cpuclockid-test2.c --]
[-- Type: text/x-csrc, Size: 1137 bytes --]

#pragma CCOD:script no
#pragma CCOD:options -lrt

#define _XOPEN_SOURCE 600
#ifdef __CYGWIN__
#define _POSIX_CPUTIME
#endif
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <dlfcn.h>

int
main (int argc, char *argv[])
{
  clockid_t clockid;
  struct timespec tp;
  int i;

#ifdef __CYGWIN__
  int (*clock_getcpuclockid) (pid_t pid, clockid_t *clk_id);
  clock_getcpuclockid = dlsym (dlopen ("cygwin1.dll", 0), "clock_getcpuclockid");
#endif

  for (i = 1; i < argc; i++) {
    if (clock_getcpuclockid (atoi (argv[i]), &clockid) != 0) {
      perror ("clock_getcpuclockid");
      exit (EXIT_FAILURE);
    }

    if (clock_gettime (clockid, &tp) == -1) {
      perror ("clock_gettime");
      exit (EXIT_FAILURE);
    }

    printf ("CPU-time clock for PID %s is %ld.%09ld seconds\n",
            argv[i], (long) tp.tv_sec, (long) tp.tv_nsec);
  }

  if (clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &tp) == -1) {
    perror ("clock_gettime");
    exit (EXIT_FAILURE);
  }

  printf ("CPU-time clock for this process is %ld.%09ld seconds\n",
          (long) tp.tv_sec, (long) tp.tv_nsec);

  return 0;
}

[-- Attachment #5: getres-test.c --]
[-- Type: text/x-csrc, Size: 1188 bytes --]

#pragma CCOD:script no
#pragma CCOD:options -lrt

#define _XOPEN_SOURCE 600
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#ifdef __CYGWIN__
#include <dlfcn.h>
#define CLOCK_PROCESS_CPUTIME_ID	(clockid_t)2
int (*clock_getcpuclockid) (pid_t, clockid_t *);
#endif

int
main (int argc, char **argv)
{
  clockid_t clk_id;
  struct timespec tp;
  pid_t pid;

#ifdef __CYGWIN__
  clock_getcpuclockid = dlopen (dlsym ("cygwin1.dll", 0), "clock_getcpuclockid");
#endif

  clock_getres (CLOCK_REALTIME, &tp);
  printf ("Realtime clock resolution is %ld.%09ld seconds\n",
          (long) tp.tv_sec, (long) tp.tv_nsec);

  clock_getres (CLOCK_MONOTONIC, &tp);
  printf ("Monotonic clock resolution is %ld.%09ld seconds\n",
          (long) tp.tv_sec, (long) tp.tv_nsec);

  clock_getres (CLOCK_PROCESS_CPUTIME_ID, &tp);
  printf ("CPU clock resolution for this process is %ld.%09ld seconds\n",
          (long) tp.tv_sec, (long) tp.tv_nsec);

  pid = argv[1] ? atoi (argv[1]) : -1;

  clock_getcpuclockid (pid, &clk_id);
  clock_getres (clk_id, &tp);
  printf ("CPU clock resolution for PID %d is %ld.%09ld seconds\n",
          pid, (long) tp.tv_sec, (long) tp.tv_nsec);

  return 0;
}

[-- Attachment #6: doc-cpuclockid.patch --]
[-- Type: text/x-patch, Size: 857 bytes --]

2011-05-15  Yaakov Selkowitz  <yselkowitz@...>

	* new-features.sgml (ov-new1.7.10): Document CPU-time clock support.

Index: new-features.sgml
===================================================================
RCS file: /cvs/src/src/winsup/doc/new-features.sgml,v
retrieving revision 1.80
diff -u -r1.80 new-features.sgml
--- new-features.sgml	9 May 2011 08:58:59 -0000	1.80
+++ new-features.sgml	15 May 2011 17:54:55 -0000
@@ -19,6 +19,12 @@
 </para></listitem>
 
 <listitem><para>
+clock_gettime(3) and clock_getres(3) accept per-process and per-thread CPU-time
+clocks, including CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID.
+New APIs: clock_getcpuclockid, pthread_getcpuclockid.
+</para></listitem>
+
+<listitem><para>
 /proc/loadavg now shows the number of currently running processes and the
 total number of processes.
 </para></listitem>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] CPU-time clocks
  2011-05-15 18:37 [PATCH] CPU-time clocks Yaakov (Cygwin/X)
@ 2011-05-15 19:12 ` Corinna Vinschen
  2011-05-15 19:31   ` Yaakov (Cygwin/X)
  0 siblings, 1 reply; 8+ messages in thread
From: Corinna Vinschen @ 2011-05-15 19:12 UTC (permalink / raw)
  To: cygwin-patches

Hi Yaakov,

On May 15 13:37, Yaakov (Cygwin/X) wrote:
> The attached patches implement POSIX CPU-time clock support:

I just applied a patch to implement pthread_attr_setstack etc.
This affects your patch in that it won't apply cleanly anymore.
Would you mind to regenerate your patches relative to CVS HEAD?


Thanks,
Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] CPU-time clocks
  2011-05-15 19:12 ` Corinna Vinschen
@ 2011-05-15 19:31   ` Yaakov (Cygwin/X)
  2011-05-16 10:43     ` Corinna Vinschen
  0 siblings, 1 reply; 8+ messages in thread
From: Yaakov (Cygwin/X) @ 2011-05-15 19:31 UTC (permalink / raw)
  To: cygwin-patches

[-- Attachment #1: Type: text/plain, Size: 312 bytes --]

On Sun, 2011-05-15 at 21:11 +0200, Corinna Vinschen wrote:
> I just applied a patch to implement pthread_attr_setstack etc.

Yes, I just saw that, thank you.

> This affects your patch in that it won't apply cleanly anymore.
> Would you mind to regenerate your patches relative to CVS HEAD?

Attached.


Yaakov


[-- Attachment #2: cpuclockid.patch --]
[-- Type: text/x-patch, Size: 12440 bytes --]

2011-05-15  Yaakov Selkowitz  <yselkowitz@...>

	* cygwin.din (clock_getcpuclockid): Export.
	(pthread_getcpuclockid): Export.
	* 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.
	* winsup.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.
	* include/pthread.h (pthread_getcpuclockid): Declare.
	* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.

Index: cygwin.din
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/cygwin.din,v
retrieving revision 1.241
diff -u -r1.241 cygwin.din
--- cygwin.din	15 May 2011 18:49:39 -0000	1.241
+++ cygwin.din	15 May 2011 19:24:11 -0000
@@ -217,6 +217,7 @@
 _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_exit SIGFE
 pthread_getattr_np SIGFE
 pthread_getconcurrency SIGFE
+pthread_getcpuclockid SIGFE
 pthread_getschedparam SIGFE
 pthread_getsequence_np SIGFE
 pthread_getspecific SIGFE
Index: posix.sgml
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/posix.sgml,v
retrieving revision 1.63
diff -u -r1.63 posix.sgml
--- posix.sgml	15 May 2011 18:49:39 -0000	1.63
+++ posix.sgml	15 May 2011 19:24:11 -0000
@@ -90,8 +90,9 @@
     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 @@
     pthread_equal
     pthread_exit
     pthread_getconcurrency
+    pthread_getcpuclockid
     pthread_getschedparam
     pthread_getspecific
     pthread_join
@@ -836,7 +838,7 @@
     tgamma
     tgammaf
     time
-    timer_create
+    timer_create		(see chapter "Implementation Notes")
     timer_delete
     timer_gettime
     timer_settime
@@ -1292,7 +1294,6 @@
     ceill
     cexpl
     cimagl
-    clock_getcpuclockid
     clogl
     conjl
     copysignl
@@ -1386,7 +1387,6 @@
     pthread_barrier[...]
     pthread_condattr_getclock
     pthread_condattr_setclock
-    pthread_getcpuclockid
     pthread_mutexattr_getrobust
     pthread_mutexattr_setrobust
     pthread_mutex_consistent
@@ -1441,9 +1441,8 @@
 related function calls.  A real chroot functionality is not supported by
 Windows however.</para>
 
-<para><function>clock_getres</function> and <function>clock_gettime</function>
-only support CLOCK_REALTIME and CLOCK_MONOTONIC for now.  <function>clock_setres</function>
-and <function>clock_settime</function> only support CLOCK_REALTIME.</para>
+<function>clock_setres</function>, <function>clock_settime</function>, and
+<function>timer_create</function> only support CLOCK_REALTIME.</para>
 
 <para>BSD file locks created via <function>flock</function> are not
 propagated to the parent process and sibling processes.  The locks are
Index: sysconf.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/sysconf.cc,v
retrieving revision 1.57
diff -u -r1.57 sysconf.cc
--- sysconf.cc	15 May 2011 18:49:39 -0000	1.57
+++ sysconf.cc	15 May 2011 19:24:12 -0000
@@ -160,7 +160,7 @@
   {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 @@
   {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 */
Index: thread.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/thread.cc,v
retrieving revision 1.239
diff -u -r1.239 thread.cc
--- thread.cc	15 May 2011 18:49:40 -0000	1.239
+++ thread.cc	15 May 2011 19:24:12 -0000
@@ -2510,6 +2510,15 @@
   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,
Index: timer.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/timer.cc,v
retrieving revision 1.26
diff -u -r1.26 timer.cc
--- timer.cc	1 Sep 2010 18:24:11 -0000	1.26
+++ timer.cc	15 May 2011 19:24:12 -0000
@@ -300,6 +300,13 @@
   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);
Index: times.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/times.cc,v
retrieving revision 1.108
diff -u -r1.108 times.cc
--- times.cc	9 May 2011 08:57:46 -0000	1.108
+++ times.cc	15 May 2011 19:24:12 -0000
@@ -15,6 +15,7 @@
 #include <sys/timeb.h>
 #include <utime.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include "cygerrno.h"
 #include "security.h"
 #include "path.h"
@@ -22,6 +23,7 @@
 #include "dtable.h"
 #include "cygheap.h"
 #include "pinfo.h"
+#include "thread.h"
 #include "cygtls.h"
 #include "ntdll.h"
 
@@ -594,6 +596,62 @@
 extern "C" int
 clock_gettime (clockid_t clk_id, struct timespec *tp)
 {
+  if (CLOCKID_IS_PROCESS (clk_id))
+    {
+      FILETIME creation_time, exit_time, kernel_time, user_time;
+      pid_t pid = CLOCKID_TO_PID (clk_id);
+      HANDLE hProcess;
+      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);
+      GetProcessTimes (hProcess, &creation_time, &exit_time, &kernel_time, &user_time);
+
+      x = ((long long) kernel_time.dwHighDateTime << 32) + ((unsigned) kernel_time.dwLowDateTime)
+          + ((long long) user_time.dwHighDateTime << 32) + ((unsigned) user_time.dwLowDateTime);
+      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))
+    {
+      FILETIME creation_time, exit_time, kernel_time, user_time;
+      long thr_id = CLOCKID_TO_THREADID (clk_id);
+      HANDLE hThread;
+      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;
+        }
+
+      GetThreadTimes (hThread, &creation_time, &exit_time, &kernel_time, &user_time);
+      x = ((long long) kernel_time.dwHighDateTime << 32) + ((unsigned) kernel_time.dwLowDateTime)
+          + ((long long) user_time.dwHighDateTime << 32) + ((unsigned) user_time.dwLowDateTime);
+      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 +688,16 @@
 {
   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 +770,16 @@
 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 +854,12 @@
   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;
+}
Index: winsup.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/winsup.h,v
retrieving revision 1.235
diff -u -r1.235 winsup.h
--- winsup.h	19 Apr 2011 10:02:06 -0000	1.235
+++ winsup.h	15 May 2011 19:24:12 -0000
@@ -220,6 +220,13 @@
 void *hook_or_detect_cygwin (const char *, const void *, WORD&) __attribute__ ((regparm (3)));
 
 /* Time related */
+#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)
+
 void __stdcall totimeval (struct timeval *, FILETIME *, int, int);
 long __stdcall to_time_t (FILETIME *);
 void __stdcall to_timestruc_t (FILETIME *, timestruc_t *);
Index: include/pthread.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/pthread.h,v
retrieving revision 1.32
diff -u -r1.32 pthread.h
--- include/pthread.h	15 May 2011 18:49:40 -0000	1.32
+++ include/pthread.h	15 May 2011 19:24:12 -0000
@@ -141,6 +141,7 @@
 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 **);
Index: include/cygwin/version.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/cygwin/version.h,v
retrieving revision 1.346
diff -u -r1.346 version.h
--- include/cygwin/version.h	15 May 2011 18:49:40 -0000	1.346
+++ include/cygwin/version.h	15 May 2011 19:24:12 -0000
@@ -412,12 +412,14 @@
       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

[-- Attachment #3: doc-cpuclockid.patch --]
[-- Type: text/x-patch, Size: 1565 bytes --]

2011-05-15  Yaakov Selkowitz  <yselkowitz@...>

	* new-features.sgml (ov-new1.7.10): Document CPU-time clock support.
	Move pthread stack management APIs to separate listitem.

Index: new-features.sgml
===================================================================
RCS file: /cvs/src/src/winsup/doc/new-features.sgml,v
retrieving revision 1.81
diff -u -r1.81 new-features.sgml
--- new-features.sgml	15 May 2011 18:51:49 -0000	1.81
+++ new-features.sgml	15 May 2011 19:26:48 -0000
@@ -19,6 +19,18 @@
 </para></listitem>
 
 <listitem><para>
+Pthread stack address management.  New APIs: pthread_attr_getstack,
+pthread_attr_getstackaddr, pthread_attr_getguardsize, pthread_attr_setstack,
+pthread_attr_setstackaddr, pthread_attr_setguardsize, pthread_getattr_np.
+</para></listitem>
+
+<listitem><para>
+clock_gettime(3) and clock_getres(3) accept per-process and per-thread CPU-time
+clocks, including CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID.
+New APIs: clock_getcpuclockid, pthread_getcpuclockid.
+</para></listitem>
+
+<listitem><para>
 /proc/loadavg now shows the number of currently running processes and the
 total number of processes.
 </para></listitem>
@@ -40,9 +52,7 @@
 
 <listitem><para>
 Other new API: clock_settime, ppoll, psiginfo, psignal, sys_siglist,
-pthread_attr_getstack, pthread_attr_getstackaddr, pthread_attr_getguardsize,
-pthread_attr_setstack, pthread_attr_setstackaddr, pthread_attr_setguardsize,
-pthread_getattr_np, pthread_setschedprio, sysinfo.
+pthread_setschedprio, sysinfo.
 </para></listitem>
 
 </itemizedlist>

[-- Attachment #4: newlib-cpuclockid.patch --]
[-- Type: text/x-patch, Size: 2116 bytes --]

2011-05-15  Yaakov Selkowitz  <yselkowitz@...>

	* libc/include/time.h (CLOCK_PROCESS_CPUTIME_ID): Rename from
	CLOCK_PROCESS_CPUTIME.
	(CLOCK_THREAD_CPUTIME_ID): Rename from CLOCK_THREAD_CPUTIME.
	* libc/include/sys/features.h [__CYGWIN__] (_POSIX_CPUTIME): Define.
	(_POSIX_THREAD_CPUTIME): Define.

Index: libc/include/time.h
===================================================================
RCS file: /cvs/src/src/newlib/libc/include/time.h,v
retrieving revision 1.19
diff -u -r1.19 time.h
--- libc/include/time.h	16 Oct 2008 21:53:58 -0000	1.19
+++ libc/include/time.h	15 May 2011 19:28:27 -0000
@@ -212,7 +212,7 @@
    the identifier of the CPU_time clock associated with the PROCESS
    making the function call.  */
 
-#define CLOCK_PROCESS_CPUTIME (clockid_t)2
+#define CLOCK_PROCESS_CPUTIME_ID (clockid_t)2
 
 #endif
 
@@ -222,7 +222,7 @@
     the identifier of the CPU_time clock associated with the THREAD
     making the function call.  */
 
-#define CLOCK_THREAD_CPUTIME (clockid_t)3
+#define CLOCK_THREAD_CPUTIME_ID (clockid_t)3
 
 #endif
 
Index: libc/include/sys/features.h
===================================================================
RCS file: /cvs/src/src/newlib/libc/include/sys/features.h,v
retrieving revision 1.25
diff -u -r1.25 features.h
--- libc/include/sys/features.h	15 May 2011 18:50:52 -0000	1.25
+++ libc/include/sys/features.h	15 May 2011 19:28:27 -0000
@@ -103,7 +103,7 @@
 /* #define _POSIX_BARRIERS			    -1 */
 #define _POSIX_CHOWN_RESTRICTED			     1
 /* #define _POSIX_CLOCK_SELECTION		    -1 */
-/* #define _POSIX_CPUTIME			    -1 */
+#define _POSIX_CPUTIME			    	200112L
 #define _POSIX_FSYNC				200112L
 #define _POSIX_IPV6				200112L
 #define _POSIX_JOB_CONTROL			     1
@@ -130,7 +130,7 @@
 #define _POSIX_SYNCHRONIZED_IO			200112L
 #define _POSIX_THREAD_ATTR_STACKADDR		200112L
 #define _POSIX_THREAD_ATTR_STACKSIZE		200112L
-/* #define _POSIX_THREAD_CPUTIME		    -1 */
+#define _POSIX_THREAD_CPUTIME			200112L
 /* #define _POSIX_THREAD_PRIO_INHERIT		    -1 */
 /* #define _POSIX_THREAD_PRIO_PROTECT		    -1 */
 #define _POSIX_THREAD_PRIORITY_SCHEDULING	200112L

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] CPU-time clocks
  2011-05-15 19:31   ` Yaakov (Cygwin/X)
@ 2011-05-16 10:43     ` Corinna Vinschen
  2011-05-16 23:11       ` Yaakov (Cygwin/X)
  0 siblings, 1 reply; 8+ messages in thread
From: Corinna Vinschen @ 2011-05-16 10:43 UTC (permalink / raw)
  To: cygwin-patches

Hi Yaakov,

On May 15 14:31, Yaakov (Cygwin/X) wrote:
> On Sun, 2011-05-15 at 21:11 +0200, Corinna Vinschen wrote:
> > I just applied a patch to implement pthread_attr_setstack etc.
> 
> Yes, I just saw that, thank you.
> 
> > This affects your patch in that it won't apply cleanly anymore.
> > Would you mind to regenerate your patches relative to CVS HEAD?
> 
> Attached.

Thanks for this patch.  It looks good to me with two exceptions:

>  extern "C" int
>  clock_gettime (clockid_t clk_id, struct timespec *tp)
>  {
> [...]
> +      hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, 0, p->dwProcessId);
> +      GetProcessTimes (hProcess, &creation_time, &exit_time, &kernel_time, &user_time);
> +
> +      x = ((long long) kernel_time.dwHighDateTime << 32) + ((unsigned) kernel_time.dwLowDateTime)
> +          + ((long long) user_time.dwHighDateTime << 32) + ((unsigned) user_time.dwLowDateTime);

Can you please collapse these lines into 80 columns?

> [...]
> +      GetThreadTimes (hThread, &creation_time, &exit_time, &kernel_time, &user_time);
> +      x = ((long long) kernel_time.dwHighDateTime << 32) + ((unsigned) kernel_time.dwLowDateTime)
> +          + ((long long) user_time.dwHighDateTime << 32) + ((unsigned) user_time.dwLowDateTime);

Ditto.

> Index: winsup.h
> ===================================================================
> RCS file: /cvs/src/src/winsup/cygwin/winsup.h,v
> retrieving revision 1.235
> diff -u -r1.235 winsup.h
> --- winsup.h	19 Apr 2011 10:02:06 -0000	1.235
> +++ winsup.h	15 May 2011 19:24:12 -0000
> @@ -220,6 +220,13 @@
>  void *hook_or_detect_cygwin (const char *, const void *, WORD&) __attribute__ ((regparm (3)));
>  
>  /* Time related */
> +#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)
> +

I think these definitions should go into hires.h.  That's the nearest
thing to a time-specific header file we have.

As for the newlib thingy, I follow up on the newlib list.


Thanks,
Corinna

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] CPU-time clocks
  2011-05-16 10:43     ` Corinna Vinschen
@ 2011-05-16 23:11       ` Yaakov (Cygwin/X)
  2011-05-17  5:59         ` Corinna Vinschen
  0 siblings, 1 reply; 8+ messages in thread
From: Yaakov (Cygwin/X) @ 2011-05-16 23:11 UTC (permalink / raw)
  To: cygwin-patches

[-- Attachment #1: Type: text/plain, Size: 1949 bytes --]

On Mon, 2011-05-16 at 12:43 +0200, Corinna Vinschen wrote:
> Thanks for this patch.  It looks good to me with two exceptions:
> 
> >  extern "C" int
> >  clock_gettime (clockid_t clk_id, struct timespec *tp)
> >  {
> > [...]
> > +      hProcess = OpenProcess (PROCESS_QUERY_INFORMATION, 0, p->dwProcessId);
> > +      GetProcessTimes (hProcess, &creation_time, &exit_time, &kernel_time, &user_time);
> > +
> > +      x = ((long long) kernel_time.dwHighDateTime << 32) + ((unsigned) kernel_time.dwLowDateTime)
> > +          + ((long long) user_time.dwHighDateTime << 32) + ((unsigned) user_time.dwLowDateTime);
> 
> Can you please collapse these lines into 80 columns?
> 
> > [...]
> > +      GetThreadTimes (hThread, &creation_time, &exit_time, &kernel_time, &user_time);
> > +      x = ((long long) kernel_time.dwHighDateTime << 32) + ((unsigned) kernel_time.dwLowDateTime)
> > +          + ((long long) user_time.dwHighDateTime << 32) + ((unsigned) user_time.dwLowDateTime);
> 
> Ditto.
> 
> > --- winsup.h	19 Apr 2011 10:02:06 -0000	1.235
> > +++ winsup.h	15 May 2011 19:24:12 -0000
> > @@ -220,6 +220,13 @@
> >  void *hook_or_detect_cygwin (const char *, const void *, WORD&) __attribute__ ((regparm (3)));
> >  
> >  /* Time related */
> > +#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)
> 
> I think these definitions should go into hires.h.  That's the nearest
> thing to a time-specific header file we have.

Revised patch attached.

> As for the newlib thingy, I follow up on the newlib list.

Already committed per your approval there.


Yaakov


[-- Attachment #2: cpuclockid.patch --]
[-- Type: text/x-patch, Size: 12491 bytes --]

2011-05-16  Yaakov Selkowitz  <yselkowitz@...>

	* 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.
	* 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.

Index: cygwin.din
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/cygwin.din,v
retrieving revision 1.241
diff -u -r1.241 cygwin.din
--- cygwin.din	15 May 2011 18:49:39 -0000	1.241
+++ cygwin.din	16 May 2011 22:31:30 -0000
@@ -217,6 +217,7 @@
 _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_exit SIGFE
 pthread_getattr_np SIGFE
 pthread_getconcurrency SIGFE
+pthread_getcpuclockid SIGFE
 pthread_getschedparam SIGFE
 pthread_getsequence_np SIGFE
 pthread_getspecific SIGFE
Index: hires.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/hires.h,v
retrieving revision 1.18
diff -u -r1.18 hires.h
--- hires.h	30 Mar 2011 21:54:09 -0000	1.18
+++ hires.h	16 May 2011 22:31:30 -0000
@@ -13,6 +13,14 @@
 
 #include <mmsystem.h>
 
+/* 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
Index: posix.sgml
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/posix.sgml,v
retrieving revision 1.63
diff -u -r1.63 posix.sgml
--- posix.sgml	15 May 2011 18:49:39 -0000	1.63
+++ posix.sgml	16 May 2011 22:31:30 -0000
@@ -90,8 +90,9 @@
     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 @@
     pthread_equal
     pthread_exit
     pthread_getconcurrency
+    pthread_getcpuclockid
     pthread_getschedparam
     pthread_getspecific
     pthread_join
@@ -836,7 +838,7 @@
     tgamma
     tgammaf
     time
-    timer_create
+    timer_create		(see chapter "Implementation Notes")
     timer_delete
     timer_gettime
     timer_settime
@@ -1292,7 +1294,6 @@
     ceill
     cexpl
     cimagl
-    clock_getcpuclockid
     clogl
     conjl
     copysignl
@@ -1386,7 +1387,6 @@
     pthread_barrier[...]
     pthread_condattr_getclock
     pthread_condattr_setclock
-    pthread_getcpuclockid
     pthread_mutexattr_getrobust
     pthread_mutexattr_setrobust
     pthread_mutex_consistent
@@ -1441,9 +1441,8 @@
 related function calls.  A real chroot functionality is not supported by
 Windows however.</para>
 
-<para><function>clock_getres</function> and <function>clock_gettime</function>
-only support CLOCK_REALTIME and CLOCK_MONOTONIC for now.  <function>clock_setres</function>
-and <function>clock_settime</function> only support CLOCK_REALTIME.</para>
+<function>clock_setres</function>, <function>clock_settime</function>, and
+<function>timer_create</function> only support CLOCK_REALTIME.</para>
 
 <para>BSD file locks created via <function>flock</function> are not
 propagated to the parent process and sibling processes.  The locks are
Index: sysconf.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/sysconf.cc,v
retrieving revision 1.57
diff -u -r1.57 sysconf.cc
--- sysconf.cc	15 May 2011 18:49:39 -0000	1.57
+++ sysconf.cc	16 May 2011 22:31:30 -0000
@@ -160,7 +160,7 @@
   {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 @@
   {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 */
Index: thread.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/thread.cc,v
retrieving revision 1.239
diff -u -r1.239 thread.cc
--- thread.cc	15 May 2011 18:49:40 -0000	1.239
+++ thread.cc	16 May 2011 22:31:30 -0000
@@ -2510,6 +2510,15 @@
   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,
Index: timer.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/timer.cc,v
retrieving revision 1.26
diff -u -r1.26 timer.cc
--- timer.cc	1 Sep 2010 18:24:11 -0000	1.26
+++ timer.cc	16 May 2011 22:31:30 -0000
@@ -300,6 +300,13 @@
   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);
Index: times.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/times.cc,v
retrieving revision 1.108
diff -u -r1.108 times.cc
--- times.cc	9 May 2011 08:57:46 -0000	1.108
+++ times.cc	16 May 2011 22:31:30 -0000
@@ -15,6 +15,7 @@
 #include <sys/timeb.h>
 #include <utime.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include "cygerrno.h"
 #include "security.h"
 #include "path.h"
@@ -22,6 +23,7 @@
 #include "dtable.h"
 #include "cygheap.h"
 #include "pinfo.h"
+#include "thread.h"
 #include "cygtls.h"
 #include "ntdll.h"
 
@@ -594,6 +596,68 @@
 extern "C" int
 clock_gettime (clockid_t clk_id, struct timespec *tp)
 {
+  if (CLOCKID_IS_PROCESS (clk_id))
+    {
+      FILETIME creation_time, exit_time, kernel_time, user_time;
+      pid_t pid = CLOCKID_TO_PID (clk_id);
+      HANDLE hProcess;
+      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);
+      GetProcessTimes (hProcess, &creation_time, &exit_time, &kernel_time,
+                       &user_time);
+
+      x = ((long long) kernel_time.dwHighDateTime << 32)
+          + ((unsigned) kernel_time.dwLowDateTime)
+          + ((long long) user_time.dwHighDateTime << 32)
+          + ((unsigned) user_time.dwLowDateTime);
+      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))
+    {
+      FILETIME creation_time, exit_time, kernel_time, user_time;
+      long thr_id = CLOCKID_TO_THREADID (clk_id);
+      HANDLE hThread;
+      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;
+        }
+
+      GetThreadTimes (hThread, &creation_time, &exit_time, &kernel_time,
+                      &user_time);
+      x = ((long long) kernel_time.dwHighDateTime << 32)
+          + ((unsigned) kernel_time.dwLowDateTime)
+          + ((long long) user_time.dwHighDateTime << 32)
+          + ((unsigned) user_time.dwLowDateTime);
+      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 +694,16 @@
 {
   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 +776,16 @@
 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 +860,12 @@
   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;
+}
Index: include/pthread.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/pthread.h,v
retrieving revision 1.32
diff -u -r1.32 pthread.h
--- include/pthread.h	15 May 2011 18:49:40 -0000	1.32
+++ include/pthread.h	16 May 2011 22:31:31 -0000
@@ -141,6 +141,7 @@
 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 **);
Index: include/cygwin/version.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/cygwin/version.h,v
retrieving revision 1.346
diff -u -r1.346 version.h
--- include/cygwin/version.h	15 May 2011 18:49:40 -0000	1.346
+++ include/cygwin/version.h	16 May 2011 22:31:31 -0000
@@ -412,12 +412,14 @@
       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

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] CPU-time clocks
  2011-05-16 23:11       ` Yaakov (Cygwin/X)
@ 2011-05-17  5:59         ` Corinna Vinschen
  2011-05-17  9:11           ` Yaakov (Cygwin/X)
  0 siblings, 1 reply; 8+ messages in thread
From: Corinna Vinschen @ 2011-05-17  5:59 UTC (permalink / raw)
  To: cygwin-patches

On May 16 18:10, Yaakov (Cygwin/X) wrote:
> On Mon, 2011-05-16 at 12:43 +0200, Corinna Vinschen wrote:
> > Thanks for this patch.  It looks good to me with two exceptions:
> > [...]
> Revised patch attached.

Thank you.  You can apply it, but while I was looking into it,
this occured to me:

> +      FILETIME creation_time, exit_time, kernel_time, user_time;
> +      long long x;
> +      [...]
> +      GetProcessTimes (hProcess, &creation_time, &exit_time, &kernel_time,
> +                       &user_time);
> +
> +      x = ((long long) kernel_time.dwHighDateTime << 32)
> +          + ((unsigned) kernel_time.dwLowDateTime)
> +          + ((long long) user_time.dwHighDateTime << 32)
> +          + ((unsigned) user_time.dwLowDateTime);
> +      tp->tv_sec = x / (long long) NSPERSEC;
> +      tp->tv_nsec = (x % (long long) NSPERSEC) * 100LL;

This conversion arithmetic from FILETIME to long long happens a lot
in times.cc, even though it's absolutely not necessary.

The FILETIME struct is actually a LARGE_INTEGER in which just the
QuadPart member is missing, unfortunately.  What we can do is to
replace the bit shifting stuff with a simple cast:

  x = ((PLARGE_INTEGER) &kernel_time)->QuadPart
      + ((PLARGE_INTEGER) &user_time)->QuadPart;

Alternatively we can define kernel_time etc as LARGE_INTEGER and cast in
the call to GetProcessTimes or just call NtQueryInformationProcess.

What do you think?  If you don't care, just apply your patch as is.


Thanks,
Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] CPU-time clocks
  2011-05-17  5:59         ` Corinna Vinschen
@ 2011-05-17  9:11           ` Yaakov (Cygwin/X)
  2011-05-17 10:19             ` Corinna Vinschen
  0 siblings, 1 reply; 8+ messages in thread
From: Yaakov (Cygwin/X) @ 2011-05-17  9:11 UTC (permalink / raw)
  To: cygwin-patches

[-- Attachment #1: Type: text/plain, Size: 1118 bytes --]

On Tue, 2011-05-17 at 07:58 +0200, Corinna Vinschen wrote:
> Thank you.  You can apply it, but while I was looking into it,
> this occured to me:
> 
> This conversion arithmetic from FILETIME to long long happens a lot
> in times.cc, even though it's absolutely not necessary.
> 
> The FILETIME struct is actually a LARGE_INTEGER in which just the
> QuadPart member is missing, unfortunately.  What we can do is to
> replace the bit shifting stuff with a simple cast:
> 
>   x = ((PLARGE_INTEGER) &kernel_time)->QuadPart
>       + ((PLARGE_INTEGER) &user_time)->QuadPart;

The MSDN docs on FILETIME[1] state:

> Do not cast a pointer to a FILETIME structure to either a ULARGE_INTEGER*
> or __int64* value because it can cause alignment faults on 64-bit Windows.

As I am by no means an expert on Win32 programming, I take that at face
value.

> Alternatively we can define kernel_time etc as LARGE_INTEGER and cast in
> the call to GetProcessTimes or just call NtQueryInformationProcess.

I have chosen the latter.  Revised patch attached.


Yaakov


[1] http://msdn.microsoft.com/en-us/library/ms724284(VS.85).aspx


[-- Attachment #2: cpuclockid.patch --]
[-- Type: text/x-patch, Size: 12696 bytes --]

2011-05-17  Yaakov Selkowitz  <yselkowitz@...>

	* 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.

Index: cygwin.din
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/cygwin.din,v
retrieving revision 1.241
diff -u -r1.241 cygwin.din
--- cygwin.din	15 May 2011 18:49:39 -0000	1.241
+++ cygwin.din	17 May 2011 08:57:52 -0000
@@ -217,6 +217,7 @@
 _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_exit SIGFE
 pthread_getattr_np SIGFE
 pthread_getconcurrency SIGFE
+pthread_getcpuclockid SIGFE
 pthread_getschedparam SIGFE
 pthread_getsequence_np SIGFE
 pthread_getspecific SIGFE
Index: hires.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/hires.h,v
retrieving revision 1.18
diff -u -r1.18 hires.h
--- hires.h	30 Mar 2011 21:54:09 -0000	1.18
+++ hires.h	17 May 2011 08:57:52 -0000
@@ -13,6 +13,14 @@
 
 #include <mmsystem.h>
 
+/* 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
Index: ntdll.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/ntdll.h,v
retrieving revision 1.119
diff -u -r1.119 ntdll.h
--- ntdll.h	15 May 2011 18:49:39 -0000	1.119
+++ ntdll.h	17 May 2011 08:57:52 -0000
@@ -938,6 +938,7 @@
 typedef enum _THREAD_INFORMATION_CLASS
 {
   ThreadBasicInformation = 0,
+  ThreadTimes = 1,
   ThreadImpersonationToken = 5
 } THREAD_INFORMATION_CLASS, *PTHREAD_INFORMATION_CLASS;
 
Index: posix.sgml
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/posix.sgml,v
retrieving revision 1.63
diff -u -r1.63 posix.sgml
--- posix.sgml	15 May 2011 18:49:39 -0000	1.63
+++ posix.sgml	17 May 2011 08:57:52 -0000
@@ -90,8 +90,9 @@
     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 @@
     pthread_equal
     pthread_exit
     pthread_getconcurrency
+    pthread_getcpuclockid
     pthread_getschedparam
     pthread_getspecific
     pthread_join
@@ -836,7 +838,7 @@
     tgamma
     tgammaf
     time
-    timer_create
+    timer_create		(see chapter "Implementation Notes")
     timer_delete
     timer_gettime
     timer_settime
@@ -1292,7 +1294,6 @@
     ceill
     cexpl
     cimagl
-    clock_getcpuclockid
     clogl
     conjl
     copysignl
@@ -1386,7 +1387,6 @@
     pthread_barrier[...]
     pthread_condattr_getclock
     pthread_condattr_setclock
-    pthread_getcpuclockid
     pthread_mutexattr_getrobust
     pthread_mutexattr_setrobust
     pthread_mutex_consistent
@@ -1441,9 +1441,8 @@
 related function calls.  A real chroot functionality is not supported by
 Windows however.</para>
 
-<para><function>clock_getres</function> and <function>clock_gettime</function>
-only support CLOCK_REALTIME and CLOCK_MONOTONIC for now.  <function>clock_setres</function>
-and <function>clock_settime</function> only support CLOCK_REALTIME.</para>
+<function>clock_setres</function>, <function>clock_settime</function>, and
+<function>timer_create</function> only support CLOCK_REALTIME.</para>
 
 <para>BSD file locks created via <function>flock</function> are not
 propagated to the parent process and sibling processes.  The locks are
Index: sysconf.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/sysconf.cc,v
retrieving revision 1.57
diff -u -r1.57 sysconf.cc
--- sysconf.cc	15 May 2011 18:49:39 -0000	1.57
+++ sysconf.cc	17 May 2011 08:57:52 -0000
@@ -160,7 +160,7 @@
   {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 @@
   {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 */
Index: thread.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/thread.cc,v
retrieving revision 1.239
diff -u -r1.239 thread.cc
--- thread.cc	15 May 2011 18:49:40 -0000	1.239
+++ thread.cc	17 May 2011 08:57:53 -0000
@@ -2510,6 +2510,15 @@
   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,
Index: timer.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/timer.cc,v
retrieving revision 1.26
diff -u -r1.26 timer.cc
--- timer.cc	1 Sep 2010 18:24:11 -0000	1.26
+++ timer.cc	17 May 2011 08:57:53 -0000
@@ -300,6 +300,13 @@
   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);
Index: times.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/times.cc,v
retrieving revision 1.108
diff -u -r1.108 times.cc
--- times.cc	9 May 2011 08:57:46 -0000	1.108
+++ times.cc	17 May 2011 08:57:53 -0000
@@ -15,6 +15,7 @@
 #include <sys/timeb.h>
 #include <utime.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include "cygerrno.h"
 #include "security.h"
 #include "path.h"
@@ -22,6 +23,7 @@
 #include "dtable.h"
 #include "cygheap.h"
 #include "pinfo.h"
+#include "thread.h"
 #include "cygtls.h"
 #include "ntdll.h"
 
@@ -594,6 +596,63 @@
 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 @@
 {
   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 @@
 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 @@
   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;
+}
Index: include/pthread.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/pthread.h,v
retrieving revision 1.32
diff -u -r1.32 pthread.h
--- include/pthread.h	15 May 2011 18:49:40 -0000	1.32
+++ include/pthread.h	17 May 2011 08:57:53 -0000
@@ -141,6 +141,7 @@
 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 **);
Index: include/cygwin/version.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/cygwin/version.h,v
retrieving revision 1.346
diff -u -r1.346 version.h
--- include/cygwin/version.h	15 May 2011 18:49:40 -0000	1.346
+++ include/cygwin/version.h	17 May 2011 08:57:53 -0000
@@ -412,12 +412,14 @@
       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

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] CPU-time clocks
  2011-05-17  9:11           ` Yaakov (Cygwin/X)
@ 2011-05-17 10:19             ` Corinna Vinschen
  0 siblings, 0 replies; 8+ messages in thread
From: Corinna Vinschen @ 2011-05-17 10:19 UTC (permalink / raw)
  To: cygwin-patches

On May 17 04:10, Yaakov (Cygwin/X) wrote:
> On Tue, 2011-05-17 at 07:58 +0200, Corinna Vinschen wrote:
> > Thank you.  You can apply it, but while I was looking into it,
> > this occured to me:
> > 
> > This conversion arithmetic from FILETIME to long long happens a lot
> > in times.cc, even though it's absolutely not necessary.
> > 
> > The FILETIME struct is actually a LARGE_INTEGER in which just the
> > QuadPart member is missing, unfortunately.  What we can do is to
> > replace the bit shifting stuff with a simple cast:
> > 
> >   x = ((PLARGE_INTEGER) &kernel_time)->QuadPart
> >       + ((PLARGE_INTEGER) &user_time)->QuadPart;
> 
> The MSDN docs on FILETIME[1] state:
> 
> > Do not cast a pointer to a FILETIME structure to either a ULARGE_INTEGER*
> > or __int64* value because it can cause alignment faults on 64-bit Windows.
> 
> As I am by no means an expert on Win32 programming, I take that at face
> value.

I don't think that has anything to do with Win32, it's a potential CPU
problem.  Why this should be the case beats me, though.  Maybe 8 byte
values are supposed to be 8 byte aligned on x86_64.  However, in 32 bit
mode it's definitely no problem.  I tested it:

  FILETIME x;
  printf ("&x = %p\n", &x);
  ((LARGE_INTEGER *) &x)->QuadPart = 0x123456789abcdefLL;
  printf ("x = %llx\n", ((LARGE_INTEGER *) &x)->QuadPart);

  ==>

  &x = 0x28ccb4
  x = 123456789abcdef

If that would have been a problem, we should see a core dump.

> > Alternatively we can define kernel_time etc as LARGE_INTEGER and cast in
> > the call to GetProcessTimes or just call NtQueryInformationProcess.
> 
> I have chosen the latter.  Revised patch attached.

Thanks, please apply.


Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2011-05-17 10:19 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-15 18:37 [PATCH] CPU-time clocks Yaakov (Cygwin/X)
2011-05-15 19:12 ` Corinna Vinschen
2011-05-15 19:31   ` Yaakov (Cygwin/X)
2011-05-16 10:43     ` Corinna Vinschen
2011-05-16 23:11       ` Yaakov (Cygwin/X)
2011-05-17  5:59         ` Corinna Vinschen
2011-05-17  9:11           ` Yaakov (Cygwin/X)
2011-05-17 10:19             ` Corinna Vinschen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).