1 /* public domain, no copyright claimed */
2 
3 #include <stdlib.h>
4 #include <errno.h>
5 #include <assert.h>
6 #include <time.h>
7 #include <math.h>
8 #include <unistd.h>
9 
10 #include <stdint.h>
11 #include <stdbool.h>
12 
13 #ifdef __OpenBSD__
14 #include <sys/types.h>
15 #include <sys/sysctl.h>
16 #endif
17 
18 #include "../platform_types.h"
19 
arcan_timemillis()20 long long int arcan_timemillis()
21 {
22 	struct timespec tp;
23 	clock_gettime(CLOCK_MONOTONIC, &tp);
24 	return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000);
25 }
26 
arcan_timemicros()27 long long int arcan_timemicros()
28 {
29 	struct timespec tp;
30 	clock_gettime(CLOCK_MONOTONIC, &tp);
31 	return (tp.tv_sec * 1000000) + (tp.tv_nsec / 1000);
32 }
33 
platform_hardware_clockcfg()34 struct platform_timing platform_hardware_clockcfg()
35 {
36 #ifdef __OpenBSD__
37 	int mib[2] = {CTL_KERN, KERN_CLOCKRATE};
38 	struct clockinfo cinf;
39 	size_t len = sizeof(struct clockinfo);
40 	if (sysctl(mib, 2, &cinf, &len, NULL, 0) != -1){
41 		return (struct platform_timing){
42 			.cost_us = cinf.tick,
43 			.tickless = false
44 		};
45 	}
46 	else {
47 		return (struct platform_timing){
48 			.cost_us = 10 * 1000,
49 			.tickless = false
50 		};
51 	}
52 #else
53 	return (struct platform_timing){
54 		.cost_us = 0,
55 		.tickless = true
56 	};
57 #endif
58 }
59 
arcan_timesleep(unsigned long val)60 void arcan_timesleep(unsigned long val)
61 {
62 	struct timespec req, rem;
63 	req.tv_sec = floor(val / 1000);
64 	val -= req.tv_sec * 1000;
65 	req.tv_nsec = val * 1000000;
66 
67 	while( nanosleep(&req, &rem) == -1 ){
68 		assert(errno != EINVAL);
69 		if (errno == EFAULT)
70 			break;
71 
72 /* sweeping EINTR introduces an error rate that can grow large,
73  * check if the remaining time is less than a threshold */
74 		if (errno == EINTR) {
75 			req = rem;
76 			if (rem.tv_sec * 1000 + (1 + req.tv_nsec) / 1000000 < 4)
77 				break;
78 		}
79 	}
80 }
81