Imported from 6.824 labs
[invirt/third/libt4.git] / gettime.cc
1 /*
2  * Copyright (c), MM Weiss
3  * All rights reserved.
4  * 
5  * Redistribution and use in source and binary forms, with or without modification, 
6  * are permitted provided that the following conditions are met:
7  * 
8  *     1. Redistributions of source code must retain the above copyright notice, 
9  *     this list of conditions and the following disclaimer.
10  *     
11  *     2. Redistributions in binary form must reproduce the above copyright notice, 
12  *     this list of conditions and the following disclaimer in the documentation 
13  *     and/or other materials provided with the distribution.
14  *     
15  *     3. Neither the name of the MM Weiss nor the names of its contributors 
16  *     may be used to endorse or promote products derived from this software without 
17  *     specific prior written permission.
18  * 
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
22  * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
24  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
26  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
27  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 /*
31  *  clock_gettime_stub.c
32  *  gcc -Wall -c clock_gettime_stub.c
33  *  posix realtime functions; MacOS user space glue
34  */
35  
36 /*  @comment
37  *  other possible implementation using intel builtin rdtsc
38  *  rdtsc-workaround: http://www.mcs.anl.gov/~kazutomo/rdtsc.html
39  *  
40  *  we could get the ticks by doing this
41  * 
42  *  __asm __volatile("mov %%ebx, %%esi\n\t"
43  *              "cpuid\n\t"
44  *              "xchg %%esi, %%ebx\n\t"
45  *              "rdtsc"
46  *              : "=a" (a),
47  *                "=d" (d)
48  *      );
49  
50  *  we could even replace our tricky sched_yield call by assembly code to get a better accurency,
51  *  anyway the following C stub will satisfy 99% of apps using posix clock_gettime call, 
52  *  moreover, the setter version (clock_settime) could be easly written using mach primitives:
53  *  http://www.opensource.apple.com/source/xnu/xnu-${VERSION}/osfmk/man/ (clock_[set|get]_time)
54  *  
55  *  hackers don't be crackers, don't you use a flush toilet?
56  * 
57  *
58  *  @see draft: ./posix-realtime-stub/posix-realtime-stub.c
59  *
60  */
61  
62
63 #ifdef __APPLE__
64
65 #pragma weak clock_gettime
66
67 #include <sys/time.h>
68 #include <sys/resource.h>
69 #include <mach/mach.h>
70 #include <mach/clock.h>
71 #include <mach/mach_time.h>
72 #include <errno.h>
73 #include <unistd.h>
74 #include <sched.h>
75
76 typedef enum {
77         CLOCK_REALTIME,
78         CLOCK_MONOTONIC,
79         CLOCK_PROCESS_CPUTIME_ID,
80         CLOCK_THREAD_CPUTIME_ID
81 } clockid_t;
82
83 static mach_timebase_info_data_t __clock_gettime_inf;
84
85 int clock_gettime(clockid_t clk_id, struct timespec *tp) {
86         kern_return_t   ret;
87         clock_serv_t    clk;
88         clock_id_t clk_serv_id;
89         mach_timespec_t tm;
90         
91         uint64_t start, end, delta, nano;
92         
93         int retval = -1;
94         switch (clk_id) {
95                 case CLOCK_REALTIME:
96                 case CLOCK_MONOTONIC:
97                         clk_serv_id = clk_id == CLOCK_REALTIME ? CALENDAR_CLOCK : SYSTEM_CLOCK;
98                         if (KERN_SUCCESS == (ret = host_get_clock_service(mach_host_self(), clk_serv_id, &clk))) {
99                                 if (KERN_SUCCESS == (ret = clock_get_time(clk, &tm))) {
100                                         tp->tv_sec  = tm.tv_sec;
101                                         tp->tv_nsec = tm.tv_nsec;
102                                         retval = 0;
103                                 }
104                         }
105                         if (KERN_SUCCESS != ret) {
106                                 errno = EINVAL;
107                                 retval = -1;
108                         }
109                 break;
110                 case CLOCK_PROCESS_CPUTIME_ID:
111                 case CLOCK_THREAD_CPUTIME_ID:
112                         start = mach_absolute_time();
113                         if (clk_id == CLOCK_PROCESS_CPUTIME_ID) {
114                                 getpid();
115                         } else {
116                                 sched_yield();
117                         }
118                         end = mach_absolute_time();
119                         delta = end - start;    
120                         if (0 == __clock_gettime_inf.denom) {
121                                 mach_timebase_info(&__clock_gettime_inf);
122                         }
123                         nano = delta * __clock_gettime_inf.numer / __clock_gettime_inf.denom;
124                         tp->tv_sec = nano * 1e-9;  
125                         tp->tv_nsec = nano - (tp->tv_sec * 1e9);
126                         retval = 0;
127                 break;
128                 default:
129                         errno = EINVAL;
130                         retval = -1;
131         }
132         return retval;
133 }
134
135 #endif // __APPLE__