1 /* Copyright (C) 1991-2021 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <errno.h>
19 #include <time.h>
20 #include <mach.h>
21 #include <assert.h>
22 #include <shlib-compat.h>
23 
24 /* Get the current time of day, putting it into *TS.
25    Returns 0 on success, -1 on errors.  */
26 int
__clock_gettime(clockid_t clock_id,struct timespec * ts)27 __clock_gettime (clockid_t clock_id, struct timespec *ts)
28 {
29   mach_msg_type_number_t count;
30   error_t err;
31 
32   switch (clock_id) {
33 
34     case CLOCK_REALTIME:
35       {
36 	/* __host_get_time can only fail if passed an invalid host_t.
37 	   __mach_host_self could theoretically fail (producing an
38 	   invalid host_t) due to resource exhaustion, but we assume
39 	   this will never happen.  */
40 	time_value_t tv;
41 	__host_get_time (__mach_host_self (), &tv);
42 	TIME_VALUE_TO_TIMESPEC (&tv, ts);
43 	return 0;
44       }
45 
46     case CLOCK_PROCESS_CPUTIME_ID:
47       {
48 	struct time_value t = { .seconds = 0, .microseconds = 0 };
49 	struct task_basic_info bi;
50 	struct task_thread_times_info tti;
51 
52 	/* Dead threads CPU time.  */
53 	count = TASK_BASIC_INFO_COUNT;
54 	err = __task_info (__mach_task_self (), TASK_BASIC_INFO,
55 			   (task_info_t) &bi, &count);
56 	if (err)
57 	  {
58 	    __set_errno(err);
59 	    return -1;
60 	  }
61 	time_value_add (&t, &bi.user_time);
62 	time_value_add (&t, &bi.system_time);
63 
64 	/* Live threads CPU time.  */
65 	count = TASK_EVENTS_INFO_COUNT;
66 	err = __task_info (__mach_task_self (), TASK_THREAD_TIMES_INFO,
67 			   (task_info_t) &tti, &count);
68 	if (err)
69 	  {
70 	    __set_errno(err);
71 	    return -1;
72 	  }
73 	time_value_add (&t, &tti.user_time);
74 	time_value_add (&t, &tti.system_time);
75 
76 	TIME_VALUE_TO_TIMESPEC(&t, ts);
77 	return 0;
78       }
79 
80     case CLOCK_THREAD_CPUTIME_ID:
81       {
82 	struct thread_basic_info bi;
83 	mach_port_t self = __mach_thread_self ();
84 
85 	count = THREAD_BASIC_INFO_COUNT;
86 	err = __thread_info (self, THREAD_BASIC_INFO,
87 			     (thread_info_t) &bi, &count);
88 	__mach_port_deallocate (__mach_task_self (), self);
89 	if (err)
90 	  {
91 	    __set_errno(err);
92 	    return -1;
93 	  }
94 	time_value_add (&bi.user_time, &bi.system_time);
95 
96 	TIME_VALUE_TO_TIMESPEC(&bi.user_time, ts);
97 	return 0;
98       }
99   }
100 
101   errno = EINVAL;
102   return -1;
103 }
104 libc_hidden_def (__clock_gettime)
105 
106 versioned_symbol (libc, __clock_gettime, clock_gettime, GLIBC_2_17);
107 /* clock_gettime moved to libc in version 2.17;
108    old binaries may expect the symbol version it had in librt.  */
109 #if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_17)
110 strong_alias (__clock_gettime, __clock_gettime_2);
111 compat_symbol (libc, __clock_gettime_2, clock_gettime, GLIBC_2_2);
112 #endif
113 
114 int
__clock_gettime64(clockid_t clock_id,struct __timespec64 * ts64)115 __clock_gettime64 (clockid_t clock_id, struct __timespec64 *ts64)
116 {
117   struct timespec ts;
118   int ret;
119 
120   ret = __clock_gettime (clock_id, &ts);
121   if (ret == 0)
122     *ts64 = valid_timespec_to_timespec64 (ts);
123 
124   return ret;
125 }
126 libc_hidden_def (__clock_gettime64)
127