1  /* Copyright (C) 1991-2023 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
      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_THREAD_TIMES_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  #if __TIMESIZE != 64
     115  int
     116  __clock_gettime64 (clockid_t clock_id, struct __timespec64 *ts64)
     117  {
     118    struct timespec ts;
     119    int ret;
     120  
     121    ret = __clock_gettime (clock_id, &ts);
     122    if (ret == 0)
     123      *ts64 = valid_timespec_to_timespec64 (ts);
     124  
     125    return ret;
     126  }
     127  libc_hidden_def (__clock_gettime64)
     128  #endif