BOROSOFTWAREAll work →
scantool/diag_os_unix.c 713 lines
1/*
2 * freediag - Vehicle Diagnostic Utility
3 *
4 *
5 * Copyright (C) 2001 Richard Almeida & Ibex Ltd ([email protected])
6 * 2014-2015 fenugrec
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 *************************************************************************
23 *
24 *
25 * OS abstraction & wrappers for unix, linux & OSX as much as possible.
26 *
27 *
28 * (1) Using the diag_l0_dumb driver requires very accurate timing,
29 * which may require running the process in real time mode in certain
30 * cases.
31 * (2) Another process needs to be capable of establishing (1)
32 *
33 * Some notes on syscall interruption :
34 * (3) The os specific and IO driver code allows "interruptible syscalls"
35 * BSD and Linux defaults is that signals don't interrupt syscalls
36 * (i.e restartable system calls)
37 * SYSV does, so you see lots of code that copes with EINTR
38 * (4) EINTR handling code belongs inside diag_os* and diag_tty* functions only,
39 * to provide a clean OS-independant API to upper levels.
40 *
41 * Goals : if _POSIX_TIMERS is defined, we attempt to use:
42 * 1- POSIX timer_create() mechanisms for the periodic callbacks
43 * 2- POSIX clock_gettime(), using best available clockid, for _getms() and _gethrt()
44 * 3- clock_nanosleep(), using best available clockid, for _millisleep()
45 *
46 * Fallbacks for above:
47 * 1- SIGALRM signal handler
48 * 2- gettimeofday(), yuck. TODO : OSX specific mach_absolute_time()
49 * 3a- (linux): /dev/rtc trick
50 * 3b- (other): nanosleep()
51 *
52 * more info on different OS high-resolution timers:
53 * http://nadeausoftware.com/articles/2012/04/c_c_tip_how_measure_elapsed_real_time_benchmarking
54 */
55
56
57#include <stdbool.h>
58#include <stdio.h>
59#include <string.h>
60#include <assert.h>
61
62#include "diag_os.h"
63#include "diag_os_unix.h"
64#include "diag.h"
65
66#include "diag_l2.h"
67#include "diag_l3.h"
68#include "diag_err.h"
69
70#include <unistd.h>
71
72#include <errno.h>
73#include <fcntl.h>
74#include <signal.h>
75#include <time.h>
76#include <pthread.h>
77
78/***
79 * In the following #ifdefs, enable/include everything supported.
80 * Other #ifdefs in the code will 'choose' the correct implementations
81 * when applicable. In other words, the following blocks should not
82 * interfere with each other (ex. if both _POSIX_TIMERS && __linux__ )
83 */
84#ifdef _POSIX_TIMERS
85/* This should be defined on a lot of linux/unix systems.
86 Implications : timer_create(), clock_gettime(), clock_nanosleep() are available.
87 */
88//Best clockids auto-selected by diag_os_discover() :
89static clockid_t clkid_pt = CLOCK_MONOTONIC; //clockid for periodic timer,
90static clockid_t clkid_gt = CLOCK_MONOTONIC; // for clock_gettime(),
91static clockid_t clkid_ns = CLOCK_MONOTONIC; // for clock_nanosleep()
92
93static timer_t ptimer_id; //periodic timer ID
94#endif // _POSIX_TIMERS
95
96#ifdef __linux__
97 #include <sys/ioctl.h> //need these for
98 #include <linux/rtc.h> //diag_os_millisleep fallback
99#ifndef _POSIX_TIMERS
100 #warning ****** WARNING ! Linux without _POSIX_TIMERS ?? Please report this !
101#endif
102#endif // __linux__
103
104#ifdef HAVE_GETTIMEOFDAY
105 #include <sys/time.h> //only for gettimeofday(), timeval etc?
106#endif
107/***/
108
109
110static int diag_os_init_done=0;
111static int discover_done = 0; //protect diag_os_millisleep() and _gethrt()
112
113static void diag_os_discover(void);
114
115static pthread_mutex_t periodic_lock = PTHREAD_MUTEX_INITIALIZER;
116
117static void
118#if defined(_POSIX_TIMERS) && (SEL_PERIODIC==S_POSIX || SEL_PERIODIC==S_AUTO)
119diag_os_periodic(UNUSED(union sigval sv)) {
120#else
121diag_os_periodic(UNUSED(int unused)) {
122#endif
123 /* Warning: these indirectly use non-async-signal-safe functions
124 * Their behavior is undefined if they happen
125 * to occur during any other non-async-signal-safe function.
126 * See doc/sourcetree_notes.txt
127 */
128
129 if (periodic_done() || pthread_mutex_trylock(&periodic_lock)) {
130 return;
131 }
132
133 diag_l3_timer(); /* Call L3 Timers */
134 diag_l2_timer(); /* Call L2 timers */
135 pthread_mutex_unlock(&periodic_lock);
136}
137
138//diag_os_init sets up a periodic callback (diag_os_periodic())
139//for keepalive messages, and selects + calibrates timer functions.
140//return 0 if ok
141int diag_os_init(void) {
142 const long tmo = ALARM_TIMEOUT;
143
144 if (diag_os_init_done) {
145 return 0;
146 }
147
148 diag_os_discover(); //auto-select clockids or other capabilities
149 diag_os_calibrate(); //calibrate before starting periodic timer
150
151#if defined(_POSIX_TIMERS) && (SEL_PERIODIC==S_POSIX || SEL_PERIODIC==S_AUTO)
152 struct itimerspec pti;
153 struct sigevent pt_sigev;
154
155 pt_sigev.sigev_notify = SIGEV_THREAD; //"Upon timer expiration, invoke sigev_notify_function "
156 pt_sigev.sigev_notify_function = diag_os_periodic;
157 pt_sigev.sigev_notify_attributes = NULL; //not sure what we need here, if anything.
158// pt_sigev.sigev_value.sival_int = 0; //not used
159// pt_sigev.siev_signo = 0; //not used
160
161 if (timer_create(clkid_pt, &pt_sigev, &ptimer_id) != 0) {
162 fprintf(stderr, FLFMT "Could not create periodic timer... report this\n", FL);
163 diag_os_geterr(0);
164 return diag_iseterr(DIAG_ERR_GENERAL);
165 }
166 //timer was created in disarmed state
167 pti.it_interval.tv_sec = (tmo / 1000);
168 pti.it_interval.tv_nsec = (tmo % 1000) * 1000*1000;
169 pti.it_value.tv_sec = pti.it_interval.tv_sec;
170 pti.it_value.tv_nsec = pti.it_interval.tv_nsec;
171
172 if (timer_settime(ptimer_id, 0, &pti, NULL) != 0) {
173 fprintf(stderr, FLFMT "Could not set periodic timer... report this\n", FL);
174 diag_os_geterr(0);
175 timer_delete(ptimer_id);
176 return diag_iseterr(DIAG_ERR_GENERAL);
177 }
178#else //so, no _POSIX_TIMERS ... sucks
179 struct sigaction stNew;
180 struct itimerval tv;
181
182 /*
183 * Install alarm handler
184 */
185 memset(&stNew, 0, sizeof(stNew));
186 stNew.sa_handler = diag_os_periodic;
187 stNew.sa_flags = 0;
188 //stNew.sa_flags = SA_RESTART;
189
190/* Notes on SA_RESTART: (man 7 signal)
191 The following interfaces are never restarted after being interrupted by
192 a signal handler, regardless of the use of SA_RESTART; they always fail
193 with the error EINTR when interrupted by a signal handler:
194 select, clock_nanosleep, [some others].
195
196 *** From POSIX docs:
197 SA_RESTART
198 This flag affects the behavior of interruptible functions; that is,
199 those specified to fail with errno set to [EINTR]. If set, and a
200 function specified as interruptible is interrupted by this signal,
201 the function shall restart and shall not fail with [EINTR] unless
202 otherwise specified. If an interruptible function which uses a
203 timeout is restarted, the duration of the timeout following the
204 restart is set to an unspecified value that does not exceed the
205 original timeout value. If the flag is not set, interruptible
206 functions interrupted by this signal shall fail with errno set to
207 [EINTR].
208
209 *** Interesting synthesis on
210 http://unix.stackexchange.com/questions/16455/interruption-of-system-calls-when-a-signal-is-caught
211
212 *** Conclusion : since we need to handle EINTR for read(), write(), select()
213 and some *sleep() syscalls anyway, we don't specify SA_RESTART.
214
215 */
216
217 sigaction(SIGALRM, &stNew, NULL); //install handler for SIGALRM
218 /*
219 * Start repeating timer
220 */
221 tv.it_interval.tv_sec = tmo / 1000; /* Seconds */
222 tv.it_interval.tv_usec = (tmo % 1000) * 1000; /* ms */
223
224 tv.it_value = tv.it_interval;
225
226 setitimer(ITIMER_REAL, &tv, 0); /* Set timer : it will SIGALRM upon expiration */
227#endif // _POSIX_TIMERS
228
229 if (getuid() == 0) {
230 printf("\t******** WARNING ********\n"
231 "\tRunning as superuser (uid 0) !!\n"
232 "\tThis is dangerous, not required, and not recommended !\n");
233 }
234
235 diag_os_init_done = 1;
236 return 0;
237} //diag_os_init
238
239//diag_os_close: delete alarm handlers / periodic timers
240//return 0 if ok (in this case, always)
241int diag_os_close() {
242#if defined(_POSIX_TIMERS) && (SEL_PERIODIC==S_POSIX || SEL_PERIODIC==S_AUTO)
243 //disarm + delete periodic timer
244 timer_delete(ptimer_id);
245#else
246 //stop the interval timer:
247 struct itimerval tv = {{0,0},{0, 0}};
248 setitimer(ITIMER_REAL, &tv, 0);
249
250 //and set the SIGALRM handler to default, whatever that is
251 struct sigaction disable_tmr;
252 memset(&disable_tmr, 0, sizeof(disable_tmr));
253 disable_tmr.sa_handler=SIG_DFL;
254 sigaction(SIGALRM, &disable_tmr, NULL);
255#endif // _POSIX_TIMERS
256
257 diag_os_init_done = 0;
258 return 0;
259
260} //diag_os_close
261
262
263//return after (ms) milliseconds.
264void diag_os_millisleep(unsigned int ms) {
265 unsigned long long t1,t2; //for verification
266 long int offsetus;
267
268 t1=diag_os_gethrt();
269
270 if (ms == 0 || !discover_done) {
271 return;
272 }
273
274//3 different compile-time implementations
275//TODO : select implem at runtime if possible? + internal feedback loop
276#if defined(_POSIX_TIMERS) && (SEL_SLEEP==S_POSIX || SEL_SLEEP==S_AUTO)
277 struct timespec rqst, resp;
278 int rv;
279
280 rqst.tv_sec = ms / 1000;
281 rqst.tv_nsec = (ms % 1000) * 1000*1000;
282
283 errno = 0;
284 //clock_nanosleep is interruptible, hence this loop
285 while ((rv=clock_nanosleep(clkid_ns, 0, &rqst, &resp)) != 0) {
286 if (rv == EINTR) {
287 rqst = resp;
288 errno = 0;
289 } else {
290 //unlikely
291 fprintf(stderr, "diag_os_millisleep : error %d\n",rv);
292 break;
293 }
294 }
295#elif defined(__linux__) && (SEL_SLEEP==S_LINUX || SEL_SLEEP==S_AUTO)
296/** ugly /dev/rtc implementation; requires uid=0 or appropriate permissions. **/
297 int fd, retval;
298 unsigned int i;
299 unsigned long tmp,data;
300
301 /* adjust time for 2048 rate */
302
303 ms = (unsigned int)((unsigned long) ms* 2048/1000); //avoid overflow
304
305 if (ms > 2) { //Bias delay -1ms to avoid overshoot ?
306 ms-=2;
307 }
308
309 fd = open ("/dev/rtc", O_RDONLY);
310
311 if (fd == -1) {
312 perror("/dev/rtc");
313 exit(errno);
314 }
315
316 /* Read periodic IRQ rate */
317 retval = ioctl(fd, RTC_IRQP_READ, &tmp);
318 if (retval == -1) {
319 perror("ioctl");
320 exit(errno);
321 }
322
323 if (retval != 2048) {
324
325 retval = ioctl(fd, RTC_IRQP_SET, 2048);
326 if (retval == -1) {
327 perror("ioctl");
328 exit(errno);
329 }
330 }
331
332 /* Enable periodic interrupts */
333 retval = ioctl(fd, RTC_PIE_ON, 0);
334 if (retval == -1) {
335 perror("ioctl");
336 exit(errno);
337 }
338
339 i = 0;
340 while (1) {
341 /* This blocks */
342 retval = read(fd, &data, sizeof(unsigned long));
343 if (retval == -1) {
344 perror("read");
345 exit(errno);
346 }
347 data >>= 8;
348 i += (unsigned int) data;
349 if (i>=(ms*2)) {
350 break;
351 }
352 }
353
354 /* Disable periodic interrupts */
355 retval = ioctl(fd, RTC_PIE_OFF, 0);
356 if (retval == -1) {
357 perror("ioctl");
358 exit(errno);
359 }
360
361 close(fd);
362#else
363#warning ****** WARNING ! Your system needs help. Using nanosleep() third-string backup plan.
364#warning ****** Please report this!
365 struct timespec rqst, resp;
366 int rv;
367
368 rqst.tv_sec = ms / 1000;
369 rqst.tv_nsec = (ms % 1000) * 1000*1000;
370
371 errno = 0;
372 //clock_nanosleep is interruptible, hence this loop
373 while ((rv=nanosleep(&rqst, &resp)) != 0) {
374 if (rv == EINTR) {
375 rqst = resp;
376 errno = 0;
377 } else {
378 break; //unlikely
379 }
380 }
381#endif // SEL_SLEEP
382
383 t2 = diag_os_gethrt();
384 offsetus = ((long int) diag_os_hrtus(t2-t1)) - ms*1000;
385 if ((offsetus > 1500) || (offsetus < -1500)) {
386 printf("_millisleep off by %ld\n", offsetus);
387 }
388
389 return;
390
391} //diag_os_millisleep
392
393/*
394 * diag_os_ipending: Is input available on stdin. ret 1 if yes.
395 *
396 *
397 */
398int diag_os_ipending(void) {
399 fd_set set;
400 int rv;
401 struct timeval tv;
402
403 FD_ZERO(&set); // empty set of FDs;
404 FD_SET(fileno(stdin), &set); //adds an FD to the set
405 tv.tv_sec = 0;
406 tv.tv_usec = 0; //select() with 0 timeout (return immediately)
407
408 /*
409 * poll for input using select():
410 */
411 errno = 0;
412 //int select(nfds, readset, writeset, exceptset, timeout) ; return number of ready FDs found
413 rv = select(fileno(stdin) + 1, &set, NULL, NULL, &tv);
414 //this will return immediately since timeout=0. NOTE : not the same thing as passing NULL instead of &tv :
415 // in that case, it would NOT return until something is ready, in this case readset.
416
417 return rv == 1;
418
419}
420
421//diag_os_cursor_up : move the console cursor up the specified number of
422//lines and to column 1
423void diag_os_cursor_up(unsigned int lines) {
424 printf("\033[%uF", lines);
425 fflush(stdout);
426}
427
428//diag_os_clrtoeol : clear the console text from the cursor to the end of
429//the current line
430void diag_os_clrtoeol(void) {
431 fputs("\033[K", stdout);
432 fflush(stdout);
433}
434
435//diag_os_geterr : get OS-specific error string.
436//Either gets the last error if os_errno==0, or print the
437//message associated with the specified os_errno
438// XXX this is not async-safe / re-entrant !
439const char *diag_os_geterr(OS_ERRTYPE os_errno) {
440 //we'll suppose strerr is satisfactory.
441 return (const char *) strerror(os_errno? os_errno : errno);
442// static char errbuf[30];
443
444// snprintf(errbuf, sizeof(errbuf), "OS Error %d", os_errno);
445// return (const char *) errbuf;
446
447}
448
449#ifdef _POSIX_TIMERS
450//internal use. ret 0 if ok
451static int diag_os_testgt(clockid_t ckid, char *ckname) {
452 struct timespec tmtest;
453 if (clock_gettime(ckid, &tmtest) == 0) {
454 printf("clock_gettime(): using %s\n", ckname);
455 clkid_gt = ckid;
456 return 0;
457 }
458 return -1;
459}
460//internal use. ret 0 if ok
461static int diag_os_testns(clockid_t ckid, char *ckname) {
462 struct timespec rqtp;
463 rqtp.tv_sec = 0;
464 rqtp.tv_nsec = 0; //bogus interval for nanosleep test
465 if (clock_nanosleep(ckid, 0, &rqtp, NULL) != ENOTSUP) {
466 printf("clock_nanosleep(): using %s\n", ckname);
467 clkid_ns = ckid;
468 return 0;
469 }
470 return -1;
471}
472#endif // _POSIX_TIMERS
473
474//use best clock truly available:
475//TODO : add weird clockids for other systems
476static void diag_os_discover(void) {
477#ifdef _POSIX_TIMERS //this guarantees clock_gettime and CLOCK_REALTIME are available
478 int gtdone=0, nsdone=0;
479
480// ***** 1) set clockid for periodic timers
481#ifdef _POSIX_MONOTONIC_CLOCK
482 //for some reason we can't use CLOCK_MONOTONIC_RAW, but
483 //CLOCK_MONOTONIC will do just fine
484 clkid_pt= CLOCK_MONOTONIC;
485#else
486 //CLOCK_REALTIME is mandatory (_MONOTONIC was optional)
487 clkid_pt = CLOCK_REALTIME;
488#endif // _POSIX_MONOTONIC_CLOCK
489
490// ***** 2) test clockids for clock_gettime and clock_nanosleep
491#define TESTCK(X) if (!gtdone) if (diag_os_testgt(X, #X)==0) { gtdone=1;} \
492 if (!nsdone) if (diag_os_testns(X, #X)==0) { nsdone=1;}
493
494#ifdef CLOCK_MONOTONIC_RAW
495 TESTCK(CLOCK_MONOTONIC_RAW)
496#endif // CLOCK_MONOTONIC_RAW
497#ifdef CLOCK_MONOTONIC
498 TESTCK(CLOCK_MONOTONIC)
499#endif // CLOCK_MONOTONIC
500#ifdef CLOCK_BOOTTIME
501 TESTCK(CLOCK_BOOTTIME)
502 if (clkid_gt == CLOCK_BOOTTIME) {
503 printf("CLOCK_BOOTTIME is unusual...\n");
504 }
505#endif // CLOCK_BOOTTIME
506#ifdef CLOCK_REALTIME
507 TESTCK(CLOCK_REALTIME)
508 if (clkid_gt == CLOCK_REALTIME) {
509 printf("CLOCK_REALTIME is suboptimal !\n");
510 }
511#endif
512// ***** 3) report possible problems
513 if (!gtdone) {
514 clkid_gt = CLOCK_REALTIME; //won't work anyway...
515 printf("WARNING: no clockid for clock_gettime()!!\n");
516 }
517 if (!nsdone) {
518 clkid_ns = CLOCK_REALTIME;
519 printf("WARNING: no clockid for clock_nanosleep()!!\n");
520 }
521 if (!gtdone || !nsdone) {
522 printf("WARNING: your system lied about its clocks;\nWARNING: you WILL have problems !\n");
523 }
524#else
525 //nothing to do (yet) for non-posix
526#endif // _POSIX_TIMERS
527 discover_done = 1;
528 return;
529}
530
531
532//diag_os_calibrate : run some timing tests to make sure we have
533//adequate performances.
534//call after diag_os_discover !
535void diag_os_calibrate(void) {
536 #define RESOL_ITERS 5
537 static int calibrate_done=0;
538 unsigned long t1, t2;
539 unsigned long long tl1, tl2, resol, maxres; //for _gethrt()
540
541 if (calibrate_done) {
542 return;
543 }
544 if (!discover_done) {
545 diag_os_discover();
546 }
547
548 //test _gethrt(). clock_getres() would tell us the resolution, but measuring
549 //like this gives a better measure of "usable" res.
550 resol=0;
551 maxres=0;
552 for (int i=0; i < RESOL_ITERS; i++) {
553 unsigned long long tr;
554 tl1=diag_os_gethrt();
555 while ((tl2=diag_os_gethrt()) == tl1) {}
556 tr = (tl2-tl1);
557 if (tr > maxres) {
558 maxres = tr;
559 }
560 resol += tr;
561 }
562 printf("diag_os_gethrt() resolution <= %lluus, avg ~%lluus\n",
563 diag_os_hrtus(maxres), diag_os_hrtus(resol / RESOL_ITERS));
564 if (diag_os_hrtus(maxres) >= 1200) {
565 printf("WARNING : your system offers no clock >= 1kHz; this "
566 "WILL be a problem!\n");
567 }
568
569 //test _getms()
570 resol=0;
571 maxres=0;
572 for (int i=0; i < RESOL_ITERS; i++) {
573 unsigned long tr;
574 t1=diag_os_getms();
575 while ((t2=diag_os_getms()) == t1) {}
576 tr = (t2-t1);
577 if (tr > maxres) {
578 maxres = tr;
579 }
580 resol += tr;
581 }
582 printf("diag_os_getms() resolution <= ~%llums, avg ~%llums\n", maxres, resol / RESOL_ITERS);
583 if (t2 > ((unsigned long)(-1) - 1000*30*60)) {
584 //unlikely, since 32-bit milliseconds will wrap in 49.7 days
585 printf("warning : diag_os_getms() will wrap in <30 minutes ! Consider rebooting...\n");
586 }
587
588 //test _millisleep() VS _gethrt()
589 printf("testing diag_os_millisleep(), this will take a moment...\n");
590 for (int testval=50; testval > 0; testval -= 2) {
591 //Start with the highest timeout
592 int i;
593 const int iters = 5;
594 long long avgerr, max, min, tsum; //in us
595
596 tsum=0;
597 max=0;
598 min=testval*1000;
599
600 for (i=0; i< iters; i++) {
601 long long timediff;
602 tl1=diag_os_gethrt();
603 diag_os_millisleep(testval);
604 tl2=diag_os_gethrt();
605 timediff= (long long) diag_os_hrtus(tl2 - tl1);
606 tsum += timediff;
607 //update extreme records if required:
608 if (timediff < min) {
609 min = timediff;
610 }
611 if (timediff > max) {
612 max = timediff;
613 }
614 }
615 avgerr= (tsum/iters) - (testval*1000); //average error in us
616 //a high spread (max-min) indicates initbus with dumb interfaces will be
617 //fragile. We just print it out; there's not much we can do to fix this.
618 if ((min < (testval*1000)) || (avgerr > 900)) {
619 printf("diag_os_millisleep(%d) off by %lld%% (+%lldus)"
620 "; spread=%lld%%\n", testval, (avgerr*100/1000)/testval, avgerr, ((max-min)*100)/(testval*1000));
621 }
622
623 if (testval >= 25) {
624 testval -= 7;
625 }
626 } //for testvals
627
628 calibrate_done=1;
629 return;
630} //diag_os_calibrate
631
632
633unsigned long diag_os_getms(void) {
634 //just use diag_os_gethrt() backend
635 return diag_os_hrtus(diag_os_gethrt()) / 1000;
636}
637
638//return high res timestamp, monotonic.
639unsigned long long diag_os_gethrt(void) {
640 assert(discover_done);
641#if defined(_POSIX_TIMERS) && (SEL_HRT==S_POSIX || SEL_HRT==S_AUTO)
642 //units : ns
643 struct timespec curtime = {0};
644
645 clock_gettime(clkid_gt, &curtime);
646
647 return curtime.tv_nsec + (curtime.tv_sec * 1000*1000*1000ULL);
648
649#else
650 #warning Using gettimeofday() ! This is evil !
651
652#ifndef HAVE_GETTIMEOFDAY
653 #error No implementation of gettimeofday() for your system!
654#endif // HAVE_GETTIMEOFDAY
655
656 //Use gettimeofday anyway as a stopgap. This is evil
657 //because gettimeofday isn't guaranteed to be monotonic (always increasing)
658 //units : us
659 struct timeval tv;
660 unsigned long long rv;
661 gettimeofday(&tv, NULL);
662 rv= tv.tv_usec + (tv.tv_sec * 1000000ULL);
663 return rv;
664#endif
665}
666
667//convert a delta of diag_os_gethrt() timestamps to microseconds
668//must match diag_os_gethrt() implementation!
669unsigned long long diag_os_hrtus(unsigned long long hrdelta) {
670#if defined(_POSIX_TIMERS) && (SEL_HRT==S_POSIX || SEL_HRT==S_AUTO)
671 return hrdelta / 1000;
672#else
673 return hrdelta;
674#endif // _POSIX_TIMERS
675}
676
677void diag_os_initmtx(diag_mtx *mtx) {
678 pthread_mutex_init((pthread_mutex_t *)mtx, NULL);
679 return;
680}
681
682void diag_os_initstaticmtx(diag_mtx *mtx) {
683 // This could have been statically initialized (in the Pthreads case, specifically)
684 // see notes in diag_os.h
685 pthread_mutex_init((pthread_mutex_t *)mtx, NULL);
686 return;
687}
688
689void diag_os_delmtx(diag_mtx *mtx) {
690 pthread_mutex_destroy((pthread_mutex_t *)mtx);
691 return;
692}
693
694void diag_os_lock(diag_mtx *mtx) {
695 if (pthread_mutex_lock((pthread_mutex_t *)mtx) == EDEADLK) {
696 // do we even check for error values...
697 fprintf(stderr, "DEADLOCK !\n");
698 }
699 return;
700}
701
702bool diag_os_trylock(diag_mtx *mtx) {
703 if (pthread_mutex_trylock((pthread_mutex_t *)mtx)) {
704 return 0;
705 }
706 return 1;
707}
708
709void diag_os_unlock(diag_mtx *mtx) {
710 pthread_mutex_unlock((pthread_mutex_t *)mtx);
711 return;
712}
713