Cygwin: sched_setscheduler: allow changes of the priority
[newlib-cygwin.git] / winsup / cygwin / times.cc
blobf6e2692b598cdb9bd0a977db38f279987a825ca2
1 /* times.cc
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 #define __timezonefunc__
10 #include "winsup.h"
11 #include <sys/times.h>
12 #include <sys/timeb.h>
13 #include <sys/param.h>
14 #include <utime.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include "cygerrno.h"
18 #include "security.h"
19 #include "path.h"
20 #include "fhandler.h"
21 #include "dtable.h"
22 #include "cygheap.h"
23 #include "pinfo.h"
24 #include "thread.h"
25 #include "cygtls.h"
26 #include "ntdll.h"
27 #include "spinlock.h"
29 static inline void __attribute__ ((always_inline))
30 get_system_time (PLARGE_INTEGER systime)
32 GetSystemTimePreciseAsFileTime ((LPFILETIME) systime);
35 /* Cygwin internal */
36 static uint64_t
37 __to_clock_t (PLARGE_INTEGER src, int flag)
39 uint64_t total = src->QuadPart;
40 /* Convert into clock ticks - the total is in 10ths of a usec. */
41 if (flag)
42 total -= FACTOR;
44 total /= NS100PERSEC / CLOCKS_PER_SEC;
45 return total;
48 /* times: POSIX 4.5.2.1 */
49 extern "C" clock_t
50 times (struct tms *buf)
52 static SYSTEM_TIMEOFDAY_INFORMATION stodi;
53 KERNEL_USER_TIMES kut;
54 LARGE_INTEGER ticks;
55 clock_t tc = (clock_t) -1;
57 __try
59 /* Fetch boot time if we haven't already. */
60 if (!stodi.BootTime.QuadPart)
61 NtQuerySystemInformation (SystemTimeOfDayInformation,
62 &stodi, sizeof stodi, NULL);
64 NtQueryInformationProcess (NtCurrentProcess (), ProcessTimes,
65 &kut, sizeof kut, NULL);
66 get_system_time (&ticks);
68 /* uptime */
69 ticks.QuadPart -= stodi.BootTime.QuadPart;
70 /* ticks is in in 100ns, convert to clock ticks. */
71 tc = (clock_t) (ticks.QuadPart * CLOCKS_PER_SEC / NS100PERSEC);
73 /* Linux allows a NULL buf and just returns tc in that case, so
74 mimic that */
75 if (buf)
77 buf->tms_stime = __to_clock_t (&kut.KernelTime, 0);
78 buf->tms_utime = __to_clock_t (&kut.UserTime, 0);
79 timeval_to_filetime (&myself->rusage_children.ru_stime, &kut.KernelTime);
80 buf->tms_cstime = __to_clock_t (&kut.KernelTime, 1);
81 timeval_to_filetime (&myself->rusage_children.ru_utime, &kut.UserTime);
82 buf->tms_cutime = __to_clock_t (&kut.UserTime, 1);
85 __except (EFAULT)
87 tc = (clock_t) -1;
89 __endtry
90 syscall_printf ("%D = times(%p)", tc, buf);
91 return tc;
94 /* settimeofday: BSD */
95 extern "C" int
96 settimeofday (const struct timeval *tv, const struct timezone *tz)
98 SYSTEMTIME st;
99 struct tm *ptm;
100 int res = -1;
102 __try
104 if (tv->tv_usec < 0 || tv->tv_usec >= USPERSEC)
106 set_errno (EINVAL);
107 return -1;
110 ptm = gmtime (&tv->tv_sec);
111 st.wYear = ptm->tm_year + 1900;
112 st.wMonth = ptm->tm_mon + 1;
113 st.wDayOfWeek = ptm->tm_wday;
114 st.wDay = ptm->tm_mday;
115 st.wHour = ptm->tm_hour;
116 st.wMinute = ptm->tm_min;
117 st.wSecond = ptm->tm_sec;
118 st.wMilliseconds = tv->tv_usec / (USPERSEC / MSPERSEC);
120 res = -!SetSystemTime (&st);
121 if (res)
122 set_errno (EPERM);
124 __except (EFAULT)
126 res = -1;
128 __endtry
129 syscall_printf ("%R = settimeofday(%p, %p)", res, tv, tz);
130 return res;
133 /* stime: SVr4 */
134 extern "C" int
135 stime (const time_t *t)
137 struct timeval tv = { *t, 0 };
138 return settimeofday(&tv, NULL);
141 /* timezone: standards? */
142 extern "C" char *
143 timezone (void)
145 char *b = _my_tls.locals.timezone_buf;
147 tzset ();
148 __small_sprintf (b,"GMT%+d:%02d", (int) (-_timezone / 3600), (int) (abs (_timezone / 60) % 60));
149 return b;
152 /* Cygwin internal */
153 void
154 totimeval (struct timeval *dst, PLARGE_INTEGER src, int sub, int flag)
156 int64_t x = __to_clock_t (src, flag);
158 x *= (int64_t) USPERSEC / CLOCKS_PER_SEC; /* Turn x into usecs */
159 x -= (int64_t) sub * USPERSEC;
161 dst->tv_usec = x % USPERSEC; /* And split */
162 dst->tv_sec = x / USPERSEC;
165 /* FIXME: Make thread safe */
166 extern "C" int
167 gettimeofday (struct timeval *__restrict tv, void *__restrict tzvp)
169 struct timezone *tz = (struct timezone *) tzvp;
170 static bool tzflag;
171 LONGLONG now = get_clock (CLOCK_REALTIME)->usecs ();
173 if (tv)
175 tv->tv_sec = now / USPERSEC;
176 tv->tv_usec = now % USPERSEC;
179 if (tz)
181 if (!tzflag)
183 tzset ();
184 tzflag = true;
186 tz->tz_minuteswest = _timezone / 60;
187 tz->tz_dsttime = _daylight;
190 return 0;
193 /* Cygwin internal */
194 void
195 timespec_to_filetime (const struct timespec *time_in, PLARGE_INTEGER out)
197 if (time_in->tv_nsec == UTIME_OMIT)
198 out->QuadPart = 0;
199 else
200 out->QuadPart = time_in->tv_sec * NS100PERSEC
201 + time_in->tv_nsec / (NSPERSEC/NS100PERSEC) + FACTOR;
204 /* Cygwin internal */
205 void
206 timeval_to_filetime (const struct timeval *time_in, PLARGE_INTEGER out)
208 out->QuadPart = time_in->tv_sec * NS100PERSEC
209 + time_in->tv_usec * (NS100PERSEC/USPERSEC) + FACTOR;
212 /* Cygwin internal */
213 bool
214 timeval_to_ms (const struct timeval *time_in, DWORD &ms)
216 if (time_in->tv_sec < 0 || time_in->tv_usec < 0
217 || time_in->tv_usec >= USPERSEC)
218 return false;
219 if ((time_in->tv_sec == 0 && time_in->tv_usec == 0)
220 || time_in->tv_sec >= (time_t) (INFINITE / MSPERSEC))
221 ms = INFINITE;
222 else
223 ms = time_in->tv_sec * MSPERSEC
224 + (time_in->tv_usec + (USPERSEC / MSPERSEC) - 1)
225 / (USPERSEC / MSPERSEC);
226 return true;
229 /* Cygwin internal */
230 static timeval
231 time_t_to_timeval (time_t in)
233 timeval res;
234 res.tv_sec = in;
235 res.tv_usec = 0;
236 return res;
239 /* Cygwin internal */
240 static const struct timespec *
241 timeval_to_timespec (const struct timeval *tvp, struct timespec *tmp)
243 if (!tvp)
244 return NULL;
246 tmp[0].tv_sec = tvp[0].tv_sec;
247 tmp[0].tv_nsec = tvp[0].tv_usec * (NSPERSEC/USPERSEC);
248 if (tmp[0].tv_nsec < 0)
249 tmp[0].tv_nsec = 0;
250 else if (tmp[0].tv_nsec >= NSPERSEC)
251 tmp[0].tv_nsec = NSPERSEC - 1;
253 tmp[1].tv_sec = tvp[1].tv_sec;
254 tmp[1].tv_nsec = tvp[1].tv_usec * (NSPERSEC/USPERSEC);
255 if (tmp[1].tv_nsec < 0)
256 tmp[1].tv_nsec = 0;
257 else if (tmp[1].tv_nsec >= NSPERSEC)
258 tmp[1].tv_nsec = NSPERSEC - 1;
260 return tmp;
263 /* Cygwin internal */
264 /* Convert a Win32 time to "UNIX" format. */
265 time_t
266 to_time_t (PLARGE_INTEGER ptr)
268 /* A file time is the number of 100ns since jan 1 1601
269 stuffed into two long words.
270 A time_t is the number of seconds since jan 1 1970. */
272 int64_t x = ptr->QuadPart;
274 /* pass "no time" as epoch */
275 if (x == 0)
276 return 0;
278 x -= FACTOR; /* number of 100ns between 1601 and 1970 */
279 x /= NS100PERSEC; /* number of 100ns in a second */
280 return x;
283 /* Cygwin internal */
284 /* Convert a Win32 time to "UNIX" timestruc_t format. */
285 void
286 to_timestruc_t (PLARGE_INTEGER ptr, timestruc_t *out)
288 /* A file time is the number of 100ns since jan 1 1601
289 stuffed into two long words.
290 A timestruc_t is the number of seconds and microseconds since jan 1 1970
291 stuffed into a time_t and a long. */
292 int64_t x = ptr->QuadPart;
294 /* pass "no time" as epoch */
295 if (x == 0)
297 out->tv_sec = 0;
298 out->tv_nsec = 0;
299 return;
302 x -= FACTOR; /* number of 100ns between 1601 and 1970 */
303 out->tv_sec = x / NS100PERSEC;
304 out->tv_nsec = (x % NS100PERSEC) * (NSPERSEC/NS100PERSEC);
307 /* Cygwin internal */
308 /* Get the current time as a "UNIX" timestruc_t format. */
309 void
310 time_as_timestruc_t (timestruc_t * out)
312 LARGE_INTEGER systime;
314 get_system_time (&systime);
315 to_timestruc_t (&systime, out);
318 /* time: POSIX 4.5.1.1, C 4.12.2.4 */
319 /* Return number of seconds since 00:00 UTC on jan 1, 1970 */
320 extern "C" time_t
321 time (time_t * ptr)
323 time_t res;
324 LARGE_INTEGER systime;
326 get_system_time (&systime);
327 res = to_time_t (&systime);
328 if (ptr)
329 *ptr = res;
331 syscall_printf ("%d = time(%p)", res, ptr);
333 return res;
337 utimens_worker (path_conv &win32, const struct timespec *tvp)
339 int res = -1;
341 if (win32.error)
342 set_errno (win32.error);
343 else
345 fhandler_base *fh = NULL;
346 bool fromfd = false;
348 cygheap_fdenum cfd (true);
349 while (cfd.next () >= 0)
350 if (cfd->get_access () & (FILE_WRITE_ATTRIBUTES | GENERIC_WRITE)
351 && RtlEqualUnicodeString (cfd->pc.get_nt_native_path (),
352 win32.get_nt_native_path (),
353 cfd->pc.objcaseinsensitive ()))
355 fh = cfd;
356 fromfd = true;
357 break;
360 if (!fh)
362 if (!(fh = build_fh_pc (win32)))
363 goto error;
365 if (fh->error ())
367 debug_printf ("got %d error from build_fh_pc", fh->error ());
368 set_errno (fh->error ());
372 res = fh->utimens (tvp);
374 if (!fromfd)
375 delete fh;
378 error:
379 syscall_printf ("%R = utimes(%S, %p)", res, win32.get_nt_native_path (), tvp);
380 return res;
383 /* utimes: POSIX/SUSv3 */
384 extern "C" int
385 utimes (const char *path, const struct timeval tvp[2])
387 path_conv win32 (path, PC_POSIX | PC_SYM_FOLLOW, stat_suffixes);
388 struct timespec tmp[2];
389 return utimens_worker (win32, timeval_to_timespec (tvp, tmp));
392 /* BSD */
393 extern "C" int
394 lutimes (const char *path, const struct timeval tvp[2])
396 path_conv win32 (path, PC_POSIX | PC_SYM_NOFOLLOW, stat_suffixes);
397 struct timespec tmp[2];
398 return utimens_worker (win32, timeval_to_timespec (tvp, tmp));
401 /* futimens: POSIX/SUSv4 */
402 extern "C" int
403 futimens (int fd, const struct timespec tvp[2])
405 int res;
407 cygheap_fdget cfd (fd);
408 if (cfd < 0)
409 res = -1;
410 else if (cfd->get_access () & (FILE_WRITE_ATTRIBUTES | GENERIC_WRITE))
411 res = cfd->utimens (tvp);
412 else
413 res = utimens_worker (cfd->pc, tvp);
414 syscall_printf ("%d = futimens(%d, %p)", res, fd, tvp);
415 return res;
418 /* BSD */
419 extern "C" int
420 futimes (int fd, const struct timeval tvp[2])
422 struct timespec tmp[2];
423 return futimens (fd, timeval_to_timespec (tvp, tmp));
426 /* utime: POSIX 5.6.6.1 */
427 extern "C" int
428 utime (const char *path, const struct utimbuf *buf)
430 struct timeval tmp[2];
432 if (buf == 0)
433 return utimes (path, 0);
435 debug_printf ("incoming utime act %lx", buf->actime);
436 tmp[0] = time_t_to_timeval (buf->actime);
437 tmp[1] = time_t_to_timeval (buf->modtime);
439 return utimes (path, tmp);
442 /* ftime: standards? */
443 extern "C" int
444 ftime (struct timeb *tp)
446 struct timeval tv;
447 struct timezone tz;
449 if (gettimeofday (&tv, &tz) < 0)
450 return -1;
452 tp->time = tv.tv_sec;
453 tp->millitm = tv.tv_usec / 1000;
454 tp->timezone = tz.tz_minuteswest;
455 tp->dstflag = tz.tz_dsttime;
457 return 0;
460 extern "C" int
461 clock_gettime (clockid_t clk_id, struct timespec *tp)
463 clk_t *clock = get_clock (clk_id);
465 if (!clock)
467 set_errno (EINVAL);
468 return -1;
470 __try
472 return clock->nsecs (clk_id, tp);
474 __except (EFAULT) {}
475 __endtry
476 return -1;
479 extern "C" int
480 clock_settime (clockid_t clk_id, const struct timespec *tp)
482 struct timeval tv;
484 if (CLOCKID_IS_PROCESS (clk_id) || CLOCKID_IS_THREAD (clk_id))
485 /* According to POSIX, the privileges to set a particular clock
486 * are implementation-defined. On Linux, CPU-time clocks are not
487 * settable; do the same here.
490 set_errno (EPERM);
491 return -1;
494 if (clk_id != CLOCK_REALTIME_COARSE && clk_id != CLOCK_REALTIME)
496 set_errno (EINVAL);
497 return -1;
500 __try
502 tv.tv_sec = tp->tv_sec;
503 tv.tv_usec = tp->tv_nsec / 1000;
505 __except (EFAULT)
507 return -1;
509 __endtry
511 return settimeofday (&tv, NULL);
514 extern "C" int
515 clock_getres (clockid_t clk_id, struct timespec *tp)
517 clk_t *clock = get_clock (clk_id);
519 if (!clock)
521 set_errno (EINVAL);
522 return -1;
524 __try
526 clock->resolution (tp);
528 __except (EFAULT)
530 return -1;
532 __endtry
533 return 0;
536 extern "C" int
537 clock_setres (clockid_t clk_id, struct timespec *tp)
539 /* Don't use this function. It only exists in QNX. Just return
540 success on CLOCK_REALTIME for backward compat. */
541 if (clk_id != CLOCK_REALTIME)
543 set_errno (EINVAL);
544 return -1;
546 return 0;
549 extern "C" int
550 clock_getcpuclockid (pid_t pid, clockid_t *clk_id)
552 if (pid != 0)
554 pinfo p (pid);
555 if (!p || !p->exists ())
556 return (ESRCH);
558 *clk_id = (clockid_t) PID_TO_CLOCKID (pid);
559 return 0;
562 extern "C" int
563 timespec_get (struct timespec *ts, int base)
565 if (base != TIME_UTC)
566 return 0;
567 clock_gettime (CLOCK_REALTIME, ts);
568 return base;
571 EXPORT_ALIAS (gettimeofday, _gettimeofday)
572 EXPORT_ALIAS (times, _times)