770 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			770 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
/* times.cc
 | 
						|
 | 
						|
This file is part of Cygwin.
 | 
						|
 | 
						|
This software is a copyrighted work licensed under the terms of the
 | 
						|
Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 | 
						|
details. */
 | 
						|
 | 
						|
#define __timezonefunc__
 | 
						|
#include "winsup.h"
 | 
						|
#include <sys/times.h>
 | 
						|
#include <sys/timeb.h>
 | 
						|
#include <utime.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include "cygerrno.h"
 | 
						|
#include "security.h"
 | 
						|
#include "path.h"
 | 
						|
#include "fhandler.h"
 | 
						|
#include "dtable.h"
 | 
						|
#include "cygheap.h"
 | 
						|
#include "pinfo.h"
 | 
						|
#include "thread.h"
 | 
						|
#include "cygtls.h"
 | 
						|
#include "ntdll.h"
 | 
						|
 | 
						|
hires_ms NO_COPY gtod;
 | 
						|
 | 
						|
hires_ns NO_COPY ntod;
 | 
						|
 | 
						|
static inline void __attribute__ ((always_inline))
 | 
						|
get_system_time (PLARGE_INTEGER systime)
 | 
						|
{
 | 
						|
  wincap.has_precise_system_time ()
 | 
						|
  	? GetSystemTimePreciseAsFileTime ((LPFILETIME) systime)
 | 
						|
	: GetSystemTimeAsFileTime ((LPFILETIME) systime);
 | 
						|
}
 | 
						|
 | 
						|
/* There's no GetTickCount64 on pre-Vista.  This is the do-it-yourself kit,
 | 
						|
   as it was implemented as hires_ms::timeGetTime_ns once.  Resurrect the
 | 
						|
   functionality to allow reliable (albeit low res) timing values.  The
 | 
						|
   function returns the value in 100ns interval to avoid a division by 10000. */
 | 
						|
ULONGLONG
 | 
						|
GetTickCount_ns ()
 | 
						|
{
 | 
						|
  LARGE_INTEGER t;
 | 
						|
  do
 | 
						|
    {
 | 
						|
      t.HighPart = SharedUserData.InterruptTime.High1Time;
 | 
						|
      t.LowPart = SharedUserData.InterruptTime.LowPart;
 | 
						|
    }
 | 
						|
  while (t.HighPart != SharedUserData.InterruptTime.High2Time);
 | 
						|
  return (ULONGLONG) t.QuadPart;
 | 
						|
}
 | 
						|
 | 
						|
/* Cygwin internal */
 | 
						|
static uint64_t __stdcall
 | 
						|
__to_clock_t (PLARGE_INTEGER src, int flag)
 | 
						|
{
 | 
						|
  uint64_t total = src->QuadPart;
 | 
						|
  /* Convert into clock ticks - the total is in 10ths of a usec.  */
 | 
						|
  if (flag)
 | 
						|
    total -= FACTOR;
 | 
						|
 | 
						|
  total /= NSPERSEC / CLOCKS_PER_SEC;
 | 
						|
  return total;
 | 
						|
}
 | 
						|
 | 
						|
/* times: POSIX 4.5.2.1 */
 | 
						|
extern "C" clock_t
 | 
						|
times (struct tms *buf)
 | 
						|
{
 | 
						|
  static SYSTEM_TIMEOFDAY_INFORMATION stodi;
 | 
						|
  KERNEL_USER_TIMES kut;
 | 
						|
  LARGE_INTEGER ticks;
 | 
						|
  clock_t tc = (clock_t) -1;
 | 
						|
 | 
						|
  __try
 | 
						|
    {
 | 
						|
      /* Fetch boot time if we haven't already. */
 | 
						|
      if (!stodi.BootTime.QuadPart)
 | 
						|
	NtQuerySystemInformation (SystemTimeOfDayInformation,
 | 
						|
				  &stodi, sizeof stodi, NULL);
 | 
						|
 | 
						|
      NtQueryInformationProcess (NtCurrentProcess (), ProcessTimes,
 | 
						|
				 &kut, sizeof kut, NULL);
 | 
						|
      get_system_time (&ticks);
 | 
						|
 | 
						|
      /* uptime */
 | 
						|
      ticks.QuadPart -= stodi.BootTime.QuadPart;
 | 
						|
      /* ticks is in in 100ns, convert to clock ticks. */
 | 
						|
      tc = (clock_t) (ticks.QuadPart * CLOCKS_PER_SEC / NSPERSEC);
 | 
						|
 | 
						|
      buf->tms_stime = __to_clock_t (&kut.KernelTime, 0);
 | 
						|
      buf->tms_utime = __to_clock_t (&kut.UserTime, 0);
 | 
						|
      timeval_to_filetime (&myself->rusage_children.ru_stime, &kut.KernelTime);
 | 
						|
      buf->tms_cstime = __to_clock_t (&kut.KernelTime, 1);
 | 
						|
      timeval_to_filetime (&myself->rusage_children.ru_utime, &kut.UserTime);
 | 
						|
      buf->tms_cutime = __to_clock_t (&kut.UserTime, 1);
 | 
						|
    }
 | 
						|
  __except (EFAULT)
 | 
						|
    {
 | 
						|
      tc = (clock_t) -1;
 | 
						|
    }
 | 
						|
  __endtry
 | 
						|
  syscall_printf ("%D = times(%p)", tc, buf);
 | 
						|
  return tc;
 | 
						|
}
 | 
						|
 | 
						|
EXPORT_ALIAS (times, _times)
 | 
						|
 | 
						|
/* settimeofday: BSD */
 | 
						|
extern "C" int
 | 
						|
settimeofday (const struct timeval *tv, const struct timezone *tz)
 | 
						|
{
 | 
						|
  SYSTEMTIME st;
 | 
						|
  struct tm *ptm;
 | 
						|
  int res = -1;
 | 
						|
 | 
						|
  __try
 | 
						|
    {
 | 
						|
      if (tv->tv_usec < 0 || tv->tv_usec >= 1000000)
 | 
						|
	{
 | 
						|
	  set_errno (EINVAL);
 | 
						|
	  return -1;
 | 
						|
	}
 | 
						|
 | 
						|
      ptm = gmtime (&tv->tv_sec);
 | 
						|
      st.wYear	   = ptm->tm_year + 1900;
 | 
						|
      st.wMonth	   = ptm->tm_mon + 1;
 | 
						|
      st.wDayOfWeek    = ptm->tm_wday;
 | 
						|
      st.wDay	   = ptm->tm_mday;
 | 
						|
      st.wHour	   = ptm->tm_hour;
 | 
						|
      st.wMinute       = ptm->tm_min;
 | 
						|
      st.wSecond       = ptm->tm_sec;
 | 
						|
      st.wMilliseconds = tv->tv_usec / 1000;
 | 
						|
 | 
						|
      res = -!SetSystemTime (&st);
 | 
						|
      gtod.reset ();
 | 
						|
 | 
						|
      if (res)
 | 
						|
	set_errno (EPERM);
 | 
						|
    }
 | 
						|
  __except (EFAULT)
 | 
						|
    {
 | 
						|
      res = -1;
 | 
						|
    }
 | 
						|
  __endtry
 | 
						|
  syscall_printf ("%R = settimeofday(%p, %p)", res, tv, tz);
 | 
						|
  return res;
 | 
						|
}
 | 
						|
 | 
						|
/* stime: SVr4 */
 | 
						|
extern "C" int
 | 
						|
stime (const time_t *t)
 | 
						|
{
 | 
						|
  struct timeval tv = { *t, 0 };
 | 
						|
  return settimeofday(&tv, NULL);
 | 
						|
}
 | 
						|
 | 
						|
/* timezone: standards? */
 | 
						|
extern "C" char *
 | 
						|
timezone (void)
 | 
						|
{
 | 
						|
  char *b = _my_tls.locals.timezone_buf;
 | 
						|
 | 
						|
  tzset ();
 | 
						|
  __small_sprintf (b,"GMT%+d:%02d", (int) (-_timezone / 3600), (int) (abs (_timezone / 60) % 60));
 | 
						|
  return b;
 | 
						|
}
 | 
						|
 | 
						|
/* Cygwin internal */
 | 
						|
void __stdcall
 | 
						|
totimeval (struct timeval *dst, PLARGE_INTEGER src, int sub, int flag)
 | 
						|
{
 | 
						|
  int64_t x = __to_clock_t (src, flag);
 | 
						|
 | 
						|
  x *= (int64_t) 1000000 / CLOCKS_PER_SEC; /* Turn x into usecs */
 | 
						|
  x -= (int64_t) sub * 1000000;
 | 
						|
 | 
						|
  dst->tv_usec = x % 1000000; /* And split */
 | 
						|
  dst->tv_sec = x / 1000000;
 | 
						|
}
 | 
						|
 | 
						|
/* FIXME: Make thread safe */
 | 
						|
extern "C" int
 | 
						|
gettimeofday (struct timeval *__restrict tv, void *__restrict tzvp)
 | 
						|
{
 | 
						|
  struct timezone *tz = (struct timezone *) tzvp;
 | 
						|
  static bool tzflag;
 | 
						|
  LONGLONG now = gtod.usecs ();
 | 
						|
 | 
						|
  if (now == (LONGLONG) -1)
 | 
						|
    return -1;
 | 
						|
 | 
						|
  tv->tv_sec = now / 1000000;
 | 
						|
  tv->tv_usec = now % 1000000;
 | 
						|
 | 
						|
  if (tz != NULL)
 | 
						|
    {
 | 
						|
      if (!tzflag)
 | 
						|
	{
 | 
						|
	  tzset ();
 | 
						|
	  tzflag = true;
 | 
						|
	}
 | 
						|
      tz->tz_minuteswest = _timezone / 60;
 | 
						|
      tz->tz_dsttime = _daylight;
 | 
						|
    }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
EXPORT_ALIAS (gettimeofday, _gettimeofday)
 | 
						|
 | 
						|
/* Cygwin internal */
 | 
						|
void __stdcall
 | 
						|
timespec_to_filetime (const struct timespec *time_in, PLARGE_INTEGER out)
 | 
						|
{
 | 
						|
  if (time_in->tv_nsec == UTIME_OMIT)
 | 
						|
    out->QuadPart = 0;
 | 
						|
  else
 | 
						|
    out->QuadPart = time_in->tv_sec * NSPERSEC
 | 
						|
		    + time_in->tv_nsec / (1000000000/NSPERSEC) + FACTOR;
 | 
						|
}
 | 
						|
 | 
						|
/* Cygwin internal */
 | 
						|
void __stdcall
 | 
						|
timeval_to_filetime (const struct timeval *time_in, PLARGE_INTEGER out)
 | 
						|
{
 | 
						|
  out->QuadPart = time_in->tv_sec * NSPERSEC
 | 
						|
		  + time_in->tv_usec * (NSPERSEC/1000000) + FACTOR;
 | 
						|
}
 | 
						|
 | 
						|
/* Cygwin internal */
 | 
						|
static timeval __stdcall
 | 
						|
time_t_to_timeval (time_t in)
 | 
						|
{
 | 
						|
  timeval res;
 | 
						|
  res.tv_sec = in;
 | 
						|
  res.tv_usec = 0;
 | 
						|
  return res;
 | 
						|
}
 | 
						|
 | 
						|
/* Cygwin internal */
 | 
						|
static const struct timespec *
 | 
						|
timeval_to_timespec (const struct timeval *tvp, struct timespec *tmp)
 | 
						|
{
 | 
						|
  if (!tvp)
 | 
						|
    return NULL;
 | 
						|
 | 
						|
  tmp[0].tv_sec = tvp[0].tv_sec;
 | 
						|
  tmp[0].tv_nsec = tvp[0].tv_usec * 1000;
 | 
						|
  if (tmp[0].tv_nsec < 0)
 | 
						|
    tmp[0].tv_nsec = 0;
 | 
						|
  else if (tmp[0].tv_nsec > 999999999)
 | 
						|
    tmp[0].tv_nsec = 999999999;
 | 
						|
 | 
						|
  tmp[1].tv_sec = tvp[1].tv_sec;
 | 
						|
  tmp[1].tv_nsec = tvp[1].tv_usec * 1000;
 | 
						|
  if (tmp[1].tv_nsec < 0)
 | 
						|
    tmp[1].tv_nsec = 0;
 | 
						|
  else if (tmp[1].tv_nsec > 999999999)
 | 
						|
    tmp[1].tv_nsec = 999999999;
 | 
						|
 | 
						|
  return tmp;
 | 
						|
}
 | 
						|
 | 
						|
/* Cygwin internal */
 | 
						|
/* Convert a Win32 time to "UNIX" format. */
 | 
						|
time_t __stdcall
 | 
						|
to_time_t (PLARGE_INTEGER ptr)
 | 
						|
{
 | 
						|
  /* A file time is the number of 100ns since jan 1 1601
 | 
						|
     stuffed into two long words.
 | 
						|
     A time_t is the number of seconds since jan 1 1970.  */
 | 
						|
 | 
						|
  int64_t x = ptr->QuadPart;
 | 
						|
 | 
						|
  /* pass "no time" as epoch */
 | 
						|
  if (x == 0)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  x -= FACTOR;			/* number of 100ns between 1601 and 1970 */
 | 
						|
  x /= NSPERSEC;		/* number of 100ns in a second */
 | 
						|
  return x;
 | 
						|
}
 | 
						|
 | 
						|
/* Cygwin internal */
 | 
						|
/* Convert a Win32 time to "UNIX" timestruc_t format. */
 | 
						|
void __stdcall
 | 
						|
to_timestruc_t (PLARGE_INTEGER ptr, timestruc_t *out)
 | 
						|
{
 | 
						|
  /* A file time is the number of 100ns since jan 1 1601
 | 
						|
     stuffed into two long words.
 | 
						|
     A timestruc_t is the number of seconds and microseconds since jan 1 1970
 | 
						|
     stuffed into a time_t and a long.  */
 | 
						|
 | 
						|
  int64_t rem;
 | 
						|
  int64_t x = ptr->QuadPart;
 | 
						|
 | 
						|
  /* pass "no time" as epoch */
 | 
						|
  if (x == 0)
 | 
						|
    {
 | 
						|
      out->tv_sec = 0;
 | 
						|
      out->tv_nsec = 0;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  x -= FACTOR;			/* number of 100ns between 1601 and 1970 */
 | 
						|
  rem = x % NSPERSEC;
 | 
						|
  x /= NSPERSEC;		/* number of 100ns in a second */
 | 
						|
  out->tv_nsec = rem * 100;	/* as tv_nsec is in nanoseconds */
 | 
						|
  out->tv_sec = x;
 | 
						|
}
 | 
						|
 | 
						|
/* Cygwin internal */
 | 
						|
/* Get the current time as a "UNIX" timestruc_t format. */
 | 
						|
void __stdcall
 | 
						|
time_as_timestruc_t (timestruc_t * out)
 | 
						|
{
 | 
						|
  LARGE_INTEGER systime;
 | 
						|
 | 
						|
  get_system_time (&systime);
 | 
						|
  to_timestruc_t (&systime, out);
 | 
						|
}
 | 
						|
 | 
						|
/* time: POSIX 4.5.1.1, C 4.12.2.4 */
 | 
						|
/* Return number of seconds since 00:00 UTC on jan 1, 1970 */
 | 
						|
extern "C" time_t
 | 
						|
time (time_t * ptr)
 | 
						|
{
 | 
						|
  time_t res;
 | 
						|
  LARGE_INTEGER systime;
 | 
						|
 | 
						|
  get_system_time (&systime);
 | 
						|
  res = to_time_t (&systime);
 | 
						|
  if (ptr)
 | 
						|
    *ptr = res;
 | 
						|
 | 
						|
  syscall_printf ("%d = time(%p)", res, ptr);
 | 
						|
 | 
						|
  return res;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
utimens_worker (path_conv &win32, const struct timespec *tvp)
 | 
						|
{
 | 
						|
  int res = -1;
 | 
						|
 | 
						|
  if (win32.error)
 | 
						|
    set_errno (win32.error);
 | 
						|
  else
 | 
						|
    {
 | 
						|
      fhandler_base *fh = NULL;
 | 
						|
      bool fromfd = false;
 | 
						|
 | 
						|
      cygheap_fdenum cfd (true);
 | 
						|
      while (cfd.next () >= 0)
 | 
						|
	if (cfd->get_access () & (FILE_WRITE_ATTRIBUTES | GENERIC_WRITE)
 | 
						|
	    && RtlEqualUnicodeString (cfd->pc.get_nt_native_path (),
 | 
						|
				      win32.get_nt_native_path (),
 | 
						|
				      cfd->pc.objcaseinsensitive ()))
 | 
						|
	  {
 | 
						|
	    fh = cfd;
 | 
						|
	    fromfd = true;
 | 
						|
	    break;
 | 
						|
	  }
 | 
						|
 | 
						|
      if (!fh)
 | 
						|
	{
 | 
						|
	  if (!(fh = build_fh_pc (win32)))
 | 
						|
	    goto error;
 | 
						|
 | 
						|
	  if (fh->error ())
 | 
						|
	    {
 | 
						|
	      debug_printf ("got %d error from build_fh_pc", fh->error ());
 | 
						|
	      set_errno (fh->error ());
 | 
						|
	    }
 | 
						|
	}
 | 
						|
 | 
						|
      res = fh->utimens (tvp);
 | 
						|
 | 
						|
      if (!fromfd)
 | 
						|
	delete fh;
 | 
						|
    }
 | 
						|
 | 
						|
error:
 | 
						|
  syscall_printf ("%R = utimes(%S, %p)", res, win32.get_nt_native_path (), tvp);
 | 
						|
  return res;
 | 
						|
}
 | 
						|
 | 
						|
/* utimes: POSIX/SUSv3 */
 | 
						|
extern "C" int
 | 
						|
utimes (const char *path, const struct timeval *tvp)
 | 
						|
{
 | 
						|
  path_conv win32 (path, PC_POSIX | PC_SYM_FOLLOW, stat_suffixes);
 | 
						|
  struct timespec tmp[2];
 | 
						|
  return utimens_worker (win32, timeval_to_timespec (tvp, tmp));
 | 
						|
}
 | 
						|
 | 
						|
/* BSD */
 | 
						|
extern "C" int
 | 
						|
lutimes (const char *path, const struct timeval *tvp)
 | 
						|
{
 | 
						|
  path_conv win32 (path, PC_POSIX | PC_SYM_NOFOLLOW, stat_suffixes);
 | 
						|
  struct timespec tmp[2];
 | 
						|
  return utimens_worker (win32, timeval_to_timespec (tvp, tmp));
 | 
						|
}
 | 
						|
 | 
						|
/* futimens: POSIX/SUSv4 */
 | 
						|
extern "C" int
 | 
						|
futimens (int fd, const struct timespec *tvp)
 | 
						|
{
 | 
						|
  int res;
 | 
						|
 | 
						|
  cygheap_fdget cfd (fd);
 | 
						|
  if (cfd < 0)
 | 
						|
    res = -1;
 | 
						|
  else if (cfd->get_access () & (FILE_WRITE_ATTRIBUTES | GENERIC_WRITE))
 | 
						|
    res = cfd->utimens (tvp);
 | 
						|
  else
 | 
						|
    res = utimens_worker (cfd->pc, tvp);
 | 
						|
  syscall_printf ("%d = futimens(%d, %p)", res, fd, tvp);
 | 
						|
  return res;
 | 
						|
}
 | 
						|
 | 
						|
/* BSD */
 | 
						|
extern "C" int
 | 
						|
futimes (int fd, const struct timeval *tvp)
 | 
						|
{
 | 
						|
  struct timespec tmp[2];
 | 
						|
  return futimens (fd,  timeval_to_timespec (tvp, tmp));
 | 
						|
}
 | 
						|
 | 
						|
/* utime: POSIX 5.6.6.1 */
 | 
						|
extern "C" int
 | 
						|
utime (const char *path, const struct utimbuf *buf)
 | 
						|
{
 | 
						|
  struct timeval tmp[2];
 | 
						|
 | 
						|
  if (buf == 0)
 | 
						|
    return utimes (path, 0);
 | 
						|
 | 
						|
  debug_printf ("incoming utime act %lx", buf->actime);
 | 
						|
  tmp[0] = time_t_to_timeval (buf->actime);
 | 
						|
  tmp[1] = time_t_to_timeval (buf->modtime);
 | 
						|
 | 
						|
  return utimes (path, tmp);
 | 
						|
}
 | 
						|
 | 
						|
/* ftime: standards? */
 | 
						|
extern "C" int
 | 
						|
ftime (struct timeb *tp)
 | 
						|
{
 | 
						|
  struct timeval tv;
 | 
						|
  struct timezone tz;
 | 
						|
 | 
						|
  if (gettimeofday (&tv, &tz) < 0)
 | 
						|
    return -1;
 | 
						|
 | 
						|
  tp->time = tv.tv_sec;
 | 
						|
  tp->millitm = tv.tv_usec / 1000;
 | 
						|
  tp->timezone = tz.tz_minuteswest;
 | 
						|
  tp->dstflag = tz.tz_dsttime;
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
#define stupid_printf if (cygwin_finished_initializing) debug_printf
 | 
						|
void
 | 
						|
hires_ns::prime ()
 | 
						|
{
 | 
						|
  LARGE_INTEGER ifreq;
 | 
						|
  if (!QueryPerformanceFrequency (&ifreq))
 | 
						|
    {
 | 
						|
      inited = -1;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  int priority = GetThreadPriority (GetCurrentThread ());
 | 
						|
 | 
						|
  SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
 | 
						|
  if (!QueryPerformanceCounter (&primed_pc))
 | 
						|
    {
 | 
						|
      SetThreadPriority (GetCurrentThread (), priority);
 | 
						|
      inited = -1;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
  freq = (double) ((double) 1000000000. / (double) ifreq.QuadPart);
 | 
						|
  inited = true;
 | 
						|
  SetThreadPriority (GetCurrentThread (), priority);
 | 
						|
}
 | 
						|
 | 
						|
LONGLONG
 | 
						|
hires_ns::nsecs (bool monotonic)
 | 
						|
{
 | 
						|
  if (!inited)
 | 
						|
    prime ();
 | 
						|
  if (inited < 0)
 | 
						|
    {
 | 
						|
      set_errno (ENOSYS);
 | 
						|
      return (LONGLONG) -1;
 | 
						|
    }
 | 
						|
 | 
						|
  LARGE_INTEGER now;
 | 
						|
  if (!QueryPerformanceCounter (&now))
 | 
						|
    {
 | 
						|
      set_errno (ENOSYS);
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  // FIXME: Use round() here?
 | 
						|
  now.QuadPart = (LONGLONG) (freq * (double)
 | 
						|
		 (now.QuadPart - (monotonic ? 0LL : primed_pc.QuadPart)));
 | 
						|
  return now.QuadPart;
 | 
						|
}
 | 
						|
 | 
						|
LONGLONG
 | 
						|
hires_ms::nsecs ()
 | 
						|
{
 | 
						|
  LARGE_INTEGER systime;
 | 
						|
  get_system_time (&systime);
 | 
						|
  /* Add conversion factor for UNIX vs. Windows base time */
 | 
						|
  return systime.QuadPart - FACTOR;
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
      int64_t 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, NULL);
 | 
						|
 | 
						|
      x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart;
 | 
						|
      tp->tv_sec = x / NSPERSEC;
 | 
						|
      tp->tv_nsec = (x % 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;
 | 
						|
      int64_t 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, NULL);
 | 
						|
 | 
						|
      x = kut.KernelTime.QuadPart + kut.UserTime.QuadPart;
 | 
						|
      tp->tv_sec = x / NSPERSEC;
 | 
						|
      tp->tv_nsec = (x % NSPERSEC) * 100LL;
 | 
						|
 | 
						|
      CloseHandle (hThread);
 | 
						|
      return 0;
 | 
						|
    }
 | 
						|
 | 
						|
  switch (clk_id)
 | 
						|
    {
 | 
						|
      case CLOCK_REALTIME:
 | 
						|
	{
 | 
						|
	  LONGLONG now = gtod.nsecs ();
 | 
						|
	  if (now == (LONGLONG) -1)
 | 
						|
	    return -1;
 | 
						|
	  tp->tv_sec = now / NSPERSEC;
 | 
						|
	  tp->tv_nsec = (now % NSPERSEC) * (1000000000 / NSPERSEC);
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
 | 
						|
      case CLOCK_MONOTONIC:
 | 
						|
	{
 | 
						|
	  LONGLONG now = ntod.nsecs (true);
 | 
						|
	  if (now == (LONGLONG) -1)
 | 
						|
	    return -1;
 | 
						|
 | 
						|
	  tp->tv_sec = now / 1000000000;
 | 
						|
	  tp->tv_nsec = (now % 1000000000);
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
 | 
						|
      default:
 | 
						|
	set_errno (EINVAL);
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
extern "C" int
 | 
						|
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);
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  tv.tv_sec = tp->tv_sec;
 | 
						|
  tv.tv_usec = tp->tv_nsec / 1000;
 | 
						|
 | 
						|
  return settimeofday (&tv, NULL);
 | 
						|
}
 | 
						|
 | 
						|
static ULONG minperiod;	// FIXME: Maintain period after a fork.
 | 
						|
 | 
						|
LONGLONG
 | 
						|
hires_ns::resolution ()
 | 
						|
{
 | 
						|
  if (!inited)
 | 
						|
    prime ();
 | 
						|
  if (inited < 0)
 | 
						|
    {
 | 
						|
      set_errno (ENOSYS);
 | 
						|
      return (LONGLONG) -1;
 | 
						|
    }
 | 
						|
 | 
						|
  return (freq <= 1.0) ? 1LL : (LONGLONG) freq;
 | 
						|
}
 | 
						|
 | 
						|
UINT
 | 
						|
hires_ms::resolution ()
 | 
						|
{
 | 
						|
  if (!minperiod)
 | 
						|
    {
 | 
						|
      ULONG coarsest, finest, actual;
 | 
						|
 | 
						|
      NtQueryTimerResolution (&coarsest, &finest, &actual);
 | 
						|
      /* The actual resolution of the OS timer is a system-wide setting which
 | 
						|
	 can be changed any time, by any process.  The only fixed value we
 | 
						|
	 can rely on is the coarsest value. */
 | 
						|
      minperiod = coarsest;
 | 
						|
    }
 | 
						|
  return minperiod;
 | 
						|
}
 | 
						|
 | 
						|
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:
 | 
						|
	{
 | 
						|
	  DWORD period = gtod.resolution ();
 | 
						|
	  tp->tv_sec = period / NSPERSEC;
 | 
						|
	  tp->tv_nsec = (period % NSPERSEC) * 100;
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
 | 
						|
      case CLOCK_MONOTONIC:
 | 
						|
	{
 | 
						|
	  LONGLONG period = ntod.resolution ();
 | 
						|
	  tp->tv_sec = period / 1000000000;
 | 
						|
	  tp->tv_nsec = period % 1000000000;
 | 
						|
	  break;
 | 
						|
	}
 | 
						|
 | 
						|
      default:
 | 
						|
	set_errno (EINVAL);
 | 
						|
	return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
extern "C" int
 | 
						|
clock_setres (clockid_t clk_id, struct timespec *tp)
 | 
						|
{
 | 
						|
  static NO_COPY bool period_set;
 | 
						|
  int status;
 | 
						|
 | 
						|
  if (clk_id != CLOCK_REALTIME)
 | 
						|
    {
 | 
						|
      set_errno (EINVAL);
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Convert to 100ns to match OS resolution.  The OS uses ULONG values
 | 
						|
     to express resolution in 100ns units, so the coarsest timer resolution
 | 
						|
     is < 430 secs.  Actually the coarsest timer resolution is only slightly
 | 
						|
     beyond 15ms, but this might change in future OS versions, so we play nice
 | 
						|
     here. */
 | 
						|
  ULONGLONG period = (tp->tv_sec * 10000000ULL) + ((tp->tv_nsec) / 100ULL);
 | 
						|
 | 
						|
  /* clock_setres is non-POSIX/non-Linux.  On QNX, the function always
 | 
						|
     rounds the incoming value to the nearest supported value. */
 | 
						|
  ULONG coarsest, finest, actual;
 | 
						|
  if (NT_SUCCESS (NtQueryTimerResolution (&coarsest, &finest, &actual)))
 | 
						|
    {
 | 
						|
      if (period > coarsest)
 | 
						|
	period = coarsest;
 | 
						|
      else if (finest > period)
 | 
						|
	period = finest;
 | 
						|
    }
 | 
						|
 | 
						|
  if (period_set
 | 
						|
      && NT_SUCCESS (NtSetTimerResolution (minperiod, FALSE, &actual)))
 | 
						|
    period_set = false;
 | 
						|
 | 
						|
  status = NtSetTimerResolution (period, TRUE, &actual);
 | 
						|
  if (!NT_SUCCESS (status))
 | 
						|
    {
 | 
						|
      __seterrno_from_nt_status (status);
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
  minperiod = period;
 | 
						|
  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;
 | 
						|
}
 |