P99
p99_clib.h
Go to the documentation of this file.
1 /* This may look like nonsense, but it really is -*- mode: C; coding: utf-8 -*- */
2 /* */
3 /* Except for parts copied from previous work and as explicitly stated below, */
4 /* the authors and copyright holders for this work are as follows: */
5 /* (C) copyright 2012, 2014 Jens Gustedt, INRIA, France */
6 /* (C) copyright 2012 William Morris */
7 /* */
8 /* This file is free software; it is part of the P99 project. */
9 /* */
10 /* Licensed under the Apache License, Version 2.0 (the "License"); */
11 /* you may not use this file except in compliance with the License. */
12 /* You may obtain a copy of the License at */
13 /* */
14 /* http://www.apache.org/licenses/LICENSE-2.0 */
15 /* */
16 /* Unless required by applicable law or agreed to in writing, software */
17 /* distributed under the License is distributed on an "AS IS" BASIS, */
18 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
19 /* See the License for the specific language governing permissions and */
20 /* limitations under the License. */
21 /* */
22 #ifndef P99_CLIB_H
23 #define P99_CLIB_H 1
24 
25 #include "p99_compiler.h"
26 #include "p99_new.h"
27 #include "p99_callback.h"
28 #include "p99_tss.h"
29 #include <time.h>
30 
37 #if __STDC_VERSION__ >= 201112L
38 # define p00_has_feature_aligned_alloc 1
39 # define p00_has_extension_aligned_alloc 1
40 #elif (_XOPEN_SOURCE >= 600) || defined(P00_DOXYGEN)
41 
42 # if !p99_has_feature(aligned_alloc)
43 
44 # define p00_has_feature_aligned_alloc 1
45 # define p00_has_extension_aligned_alloc 1
46 
53 void *aligned_alloc(size_t p00_alignment, size_t p00_size) {
54  void * p00_ret = 0;
55  int err = posix_memalign(&p00_ret, p00_alignment, p00_size);
56  /* If there was an error and a fake pointer has been returned, free
57  this pointer and set it to 0. This is the only way to return an
58  error for this C11 interface. */
59  if (err && p00_ret) {
60  free(p00_ret);
61  p00_ret = 0;
62  }
63  return p00_ret;
64 }
65 
66 # endif
67 
68 # endif /* XOPEN */
69 
70 
71 # define p00_has_feature_quick_exit 1
72 # define p00_has_extension_quick_exit 1
73 
74 #if __STDC_VERSION__ < 201112L
75 
76 /* In both cases this is guaranteed to do the correct
77  initialization. */
78 P99_WEAK(p00_cb)
79 p99_callback_stack p00_at_quick_exit = P99_LIFO_INITIALIZER(0);
80 
81 # ifdef __USE_GNU
82 # if __GLIBC_PREREQ(2,13)
83 /* they seem to have implemented quick_exit */
84 # else
85 
90 int at_quick_exit(void (*p00_void_func)(void)) {
91  return !P99_CALLBACK_PUSH(&p00_at_quick_exit, p00_void_func);
92 }
93 
103 _Noreturn void quick_exit(int status) {
104  p99_callback(&p00_at_quick_exit);
105  _Exit(status);
106 }
107 
108 # endif
109 # endif /* USE_GNU */
110 
111 #endif /* C < C11 */
112 
113 P99_SETJMP_INLINE(p00_run_at_thrd_exit)
114 void p00_run_at_thrd_exit(void * li) {
115  p99_callback(li);
116 }
117 
118 P99_TSS_DECLARE_LOCAL(p99_callback_stack, p00_at_thrd_exit, p00_run_at_thrd_exit);
119 # define P00_AT_THRD_EXIT P99_TSS_LOCAL(p00_at_thrd_exit)
120 
129 int at_thrd_exit(void (*p00_void_func)(void)) {
130  return !P99_CALLBACK_PUSH(&P00_AT_THRD_EXIT, p00_void_func);
131 }
132 
133 /* Add rudimentary support for the timespec data structure */
134 
135 /* All this fuss is needed because TIME_UTC isn't allowed to be 0.
136  And this is because timespec_get returns failure as 0, and success
137  by returning the time base, oh well. */
138 
139 /* A fallback version if all else fails */
140 
142 int p00_timespec_get(struct timespec *p00_ts, int p00_base) {
143  struct timeval t;
144  if (gettimeofday(&t, P99_0(struct timezone*))) {
145  errno = 0;
146  return 0;
147  } else {
148  p00_ts->tv_sec = t.tv_sec;
149  /* ensure that the usec value is first converted to a nsec
150  value of the correct width ... */
151  p00_ts->tv_nsec = t.tv_usec;
152  /* ... and do the multiplication within that width. */
153  p00_ts->tv_nsec *= 1000;
154  return p00_base;
155  }
156 }
157 
158 #ifndef TIME_UTC
159 
177 int timespec_get(struct timespec *p00_ts, int p00_base);
178 
179 enum {
180  p00_time_base,
181  p00_time_utc,
182  p00_time_monotonic,
183 # ifdef CLOCK_PROCESS_CPUTIME_ID
184  p00_time_process_cputime_id,
185 # endif
186 # ifdef CLOCK_THREAD_CPUTIME_ID
187  p00_time_thread_cputime_id,
188 # endif
189  p00_time_base_max
190 };
191 
200 # define TIME_UTC p00_time_utc
201 
202 # if defined(CLOCK_REALTIME) || defined(P00_DOXYGEN)
203 
204 # if defined(CLOCK_MONOTONIC) || defined(P00_DOXYGEN)
205 
218 # define TIME_MONOTONIC p00_time_monotonic
219 
220 # endif
221 # ifdef CLOCK_PROCESS_CPUTIME_ID
222 # define TIME_PROCESS_CPUTIME_ID p00_time_process_cputime_id
223 # endif
224 # ifdef CLOCK_THREAD_CPUTIME_ID
225 # define TIME_THREAD_CPUTIME_ID p00_time_thread_cputime_id,
226 # endif
227 
230 clockid_t p00_getclockid(int base) {
231  return (base >= p00_time_base_max)
232  ? CLOCK_REALTIME
233  : (clockid_t const[]) {
234  [p00_time_base] = CLOCK_REALTIME,
235  [p00_time_utc] = CLOCK_REALTIME,
236 # ifdef CLOCK_MONOTONIC
237  [p00_time_monotonic] = CLOCK_MONOTONIC,
238 # endif
239 # ifdef CLOCK_PROCESS_CPUTIME_ID
240  [p00_time_process_cputime_id] = CLOCK_PROCESS_CPUTIME_ID,
241 # endif
242 # ifdef CLOCK_THREAD_CPUTIME_ID
243  [p00_time_thread_cputime_id] = CLOCK_THREAD_CPUTIME_ID,
244 # endif
245  }[base];
246 }
247 
263 int timespec_get(struct timespec *p00_ts, int p00_base) {
264  clockid_t p00_clkid = p00_getclockid(p00_base);
265  if (clock_gettime(p00_clkid, p00_ts)) {
266  errno = 0;
267  return 0;
268  } else
269  return p00_base;
270 }
271 
272 # elif defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__)
273 # include <mach/mach_time.h>
274 
275 # define TIME_MONOTONIC p00_time_monotonic
276 
277 P99_WEAK(p00_timebase)
278 double p00_timebase;
279 
280 P99_WEAK(p00_timeoff_)
281 struct timespec p00_timeoff_;
282 
283 P99_WEAK(p00_timeoff)
284 struct timespec const*const p00_timeoff = &p00_timeoff_;
285 
286 P99_WEAK(p00_timeonce)
287 once_flag p00_timeonce = ONCE_FLAG_INIT;
288 
290 void p00_timeonce_init(void) {
291  /* Calibrate the monotonic time */
292  mach_timebase_info_data_t p00_tb = P99_INIT;
293  mach_timebase_info(&p00_tb);
294  p00_timebase = p00_tb.numer;
295  p00_timebase /= p00_tb.denom;
296  /* Compute the offset of the monotonic time compared to UTC */
297  /* Nanosec since system start, or something similar. */
298  uint64_t p00_nsec = mach_absolute_time() * p00_timebase;
299  p00_timespec_get(&p00_timeoff_, TIME_UTC);
300  uint64_t const p00_giga = UINT64_C(1000000000);
301  uint64_t p00_epoch = p00_timeoff_.tv_sec * p00_giga + p00_timeoff_.tv_nsec;
302  p00_epoch -= p00_nsec;
303  p00_timeoff_.tv_sec = p00_epoch / p00_giga;
304  p00_timeoff_.tv_nsec = p00_epoch % p00_giga;
305 }
306 
308 int timespec_get(struct timespec *p00_ts, int p00_base) {
309  call_once(&p00_timeonce, p00_timeonce_init);
310  uint64_t p00_nsec = mach_absolute_time() * p00_timebase;
311  register uint64_t const p00_giga = UINT64_C(1000000000);
312  p00_ts->tv_sec = p00_nsec / p00_giga;
313  p00_ts->tv_nsec = p00_nsec % p00_giga;
314  if (p00_base != TIME_MONOTONIC) {
315  p00_ts->tv_sec += p00_timeoff->tv_sec;
316  p00_ts->tv_nsec += p00_timeoff->tv_nsec;
317  while (p00_ts->tv_nsec >= p00_giga) {
318  p00_ts->tv_nsec -= p00_giga;
319  ++p00_ts->tv_sec;
320  }
321  }
322  return p00_base;
323 }
324 # else
325 # warning only low resolution gettimeofday found
326 # define timespec_get p00_timespec_get
327 # endif
328 #endif
329 
334 #endif
P99_SETJMP_INLINE
P99_SETJMP_INLINE(p00_run_at_thrd_exit) void p00_run_at_thrd_exit(void *li)
Definition: p99_clib.h:110
TIME_UTC
#define TIME_UTC
expands to an integer constant greater than 0 that designates the UTC time base since an implementati...
Definition: p99_clib.h:197
P99_TSS_DECLARE_LOCAL
#define P99_TSS_DECLARE_LOCAL(T, NAME, DTOR)
p99_new.h
Macros for initialization and allocation.
p99_once_flag
complete object type that holds a flag for use by p99_call_once
Definition: p99_threads.h:62
aligned_alloc
void * aligned_alloc(size_t p00_alignment, size_t p00_size)
allocation with a chosen alignment
Definition: p99_clib.h:51
p99_tss.h
TIME_MONOTONIC
#define TIME_MONOTONIC
expands to an integer constant greater than 0 that designates a real time clock who's base is usually...
Definition: p99_clib.h:215
p99_compiler.h
Group compiler dependencies together in one file.
P99_0
#define P99_0(T)
Cast the int value 0 to type T.
Definition: p99_int.h:349
_Noreturn
#define _Noreturn
Declare a function that doesn't return to the caller.
Definition: p99_compiler.h:835
p99_inline
#define p99_inline
Try to force a function always to be inlined.
Definition: p99_compiler.h:496
P99_WEAK
#define P99_WEAK(...)
Declare a symbol to be weak such that it can be provided several times without error.
Definition: p99_compiler.h:561
P99_INIT
#define P99_INIT
A catch all 0-initializer.
Definition: p99_int.h:1065
timespec_get
int timespec_get(struct timespec *p00_ts, int p00_base)
The timespec_get function sets the interval pointed to by p00_ts to hold the current calendar time ba...
Definition: p99_clib.h:260
p99_callback_stack::p99_callback
void p99_callback(p99_callback_stack *p00_stck)
Call all functions that have been registered with p00_stck in reverse order of their registration and...
Definition: p99_callback.h:171
P99_CONST_FUNCTION
#define P99_CONST_FUNCTION
On architectures that support this, assert that a function is "const", i.e only depends on parameters...
Definition: p99_compiler.h:622
P99_LIFO_INITIALIZER
#define P99_LIFO_INITIALIZER(VAL)
Definition: p99_lifo.h:46
p99_callback_stack
A data structure to register callbacks.
Definition: p99_callback.h:43
at_thrd_exit
int at_thrd_exit(void(*p00_void_func)(void))
Add p00_void_func to the functions that are called on exit of the current thread.
Definition: p99_clib.h:126
ONCE_FLAG_INIT
#define ONCE_FLAG_INIT
Definition: p99_threads.h:37
p99_callback.h
call_once
#define call_once
Definition: p99_threads.h:38
errno
errno
Definition: p99_constraint.h:199
p99_callback_stack::P99_CALLBACK_PUSH
#define P99_CALLBACK_PUSH(STCK,...)
Register a function as a callback on STCK.
Definition: p99_callback.h:149