VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/timer-posix.cpp@ 10634

Last change on this file since 10634 was 10614, checked in by vboxsync, 16 years ago

Enable posix timers by default by all users of the code (requirement of VBoxSVC now). Enabled VBOX_WITH_RESOURECE_USAGE_API everywhere as it turned out Darwin is using the generic timers and not the posix ones as initially thought.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 20.2 KB
Line 
1/* $Id: timer-posix.cpp 10614 2008-07-14 19:52:32Z vboxsync $ */
2/** @file
3 * IPRT - Timer, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*******************************************************************************
32* Defined Constants And Macros *
33*******************************************************************************/
34/** Enables the use of POSIX RT timers. */
35#define IPRT_WITH_POSIX_TIMERS
36
37
38/*******************************************************************************
39* Header Files *
40*******************************************************************************/
41#include <iprt/timer.h>
42#include <iprt/alloc.h>
43#include <iprt/assert.h>
44#include <iprt/thread.h>
45#include <iprt/log.h>
46#include <iprt/asm.h>
47#include <iprt/semaphore.h>
48#include <iprt/string.h>
49#include <iprt/err.h>
50#include "internal/magics.h"
51
52#include <unistd.h>
53#include <sys/fcntl.h>
54#include <sys/ioctl.h>
55#ifdef RT_OS_LINUX
56# include <linux/rtc.h>
57#endif
58#include <sys/time.h>
59#include <signal.h>
60#include <errno.h>
61#ifndef RT_OS_OS2
62# include <pthread.h>
63#endif
64
65
66/*******************************************************************************
67* Structures and Typedefs *
68*******************************************************************************/
69/**
70 * The internal representation of a timer handle.
71 */
72typedef struct RTTIMER
73{
74 /** Magic.
75 * This is RTTIMER_MAGIC, but changes to something else before the timer
76 * is destroyed to indicate clearly that thread should exit. */
77 uint32_t volatile u32Magic;
78 /** Flag indicating the the timer is suspended. */
79 uint8_t volatile fSuspended;
80 /** Flag indicating that the timer has been destroyed. */
81 uint8_t volatile fDestroyed;
82#ifndef IPRT_WITH_POSIX_TIMERS /** @todo We have to take the signals on a dedicated timer thread as
83 * we (might) have code assuming that signals doesn't screw around
84 * on existing threads. (It would be sufficient to have one thread
85 * per signal of course since the signal will be masked while it's
86 * running, however, it may just cause more compilcations than its
87 * worth - sigwait/sigwaitinfo work atomically anyway...)
88 * Also, must block the signal in the thread main procedure too. */
89 /** The timer thread. */
90 RTTHREAD Thread;
91 /** Event semaphore on which the thread is blocked. */
92 RTSEMEVENT Event;
93#endif
94 /** User argument. */
95 void *pvUser;
96 /** Callback. */
97 PFNRTTIMER pfnTimer;
98 /** The timer interval. 0 if one-shot. */
99 uint64_t u64NanoInterval;
100#ifndef IPRT_WITH_POSIX_TIMERS
101 /** The first shot interval. 0 if ASAP. */
102 uint64_t volatile u64NanoFirst;
103#endif /* !IPRT_WITH_POSIX_TIMERS */
104 /** The current timer tick. */
105 uint64_t volatile iTick;
106#ifndef IPRT_WITH_POSIX_TIMERS
107 /** The error/status of the timer.
108 * Initially -1, set to 0 when the timer have been successfully started, and
109 * to errno on failure in starting the timer. */
110 int volatile iError;
111#else /* !IPRT_WITH_POSIX_TIMERS */
112 timer_t timer;
113#endif /* !IPRT_WITH_POSIX_TIMERS */
114
115} RTTIMER;
116
117#ifndef IPRT_WITH_POSIX_TIMERS
118
119/**
120 * Signal handler which ignore everything it gets.
121 *
122 * @param iSignal The signal number.
123 */
124static void rttimerSignalIgnore(int iSignal)
125{
126 //AssertBreakpoint();
127}
128
129
130/**
131 * SIGALRM wait thread.
132 */
133static DECLCALLBACK(int) rttimerThread(RTTHREAD Thread, void *pvArg)
134{
135 PRTTIMER pTimer = (PRTTIMER)(void *)pvArg;
136 RTTIMER Timer = *pTimer;
137 Assert(pTimer->u32Magic == RTTIMER_MAGIC);
138
139 /*
140 * Install signal handler.
141 */
142 struct sigaction SigAct;
143 memset(&SigAct, 0, sizeof(SigAct));
144 SigAct.sa_flags = SA_RESTART;
145 sigemptyset(&SigAct.sa_mask);
146 SigAct.sa_handler = rttimerSignalIgnore;
147 if (sigaction(SIGALRM, &SigAct, NULL))
148 {
149 SigAct.sa_flags &= ~SA_RESTART;
150 if (sigaction(SIGALRM, &SigAct, NULL))
151 AssertMsgFailed(("sigaction failed, errno=%d\n", errno));
152 }
153
154 /*
155 * Mask most signals except those which might be used by the pthread implementation (linux).
156 */
157 sigset_t SigSet;
158 sigfillset(&SigSet);
159 sigdelset(&SigSet, SIGTERM);
160 sigdelset(&SigSet, SIGHUP);
161 sigdelset(&SigSet, SIGINT);
162 sigdelset(&SigSet, SIGABRT);
163 sigdelset(&SigSet, SIGKILL);
164#ifdef SIGRTMIN
165 for (int iSig = SIGRTMIN; iSig < SIGRTMAX; iSig++)
166 sigdelset(&SigSet, iSig);
167#endif
168 if (sigprocmask(SIG_SETMASK, &SigSet, NULL))
169 {
170 int rc = pTimer->iError = RTErrConvertFromErrno(errno);
171 AssertMsgFailed(("sigprocmask -> errno=%d\n", errno));
172 return rc;
173 }
174
175 /*
176 * The work loop.
177 */
178 RTThreadUserSignal(Thread);
179 while ( !pTimer->fDestroyed
180 && pTimer->u32Magic == RTTIMER_MAGIC)
181 {
182 /*
183 * Wait for a start or destroy event.
184 */
185 if (pTimer->fSuspended)
186 {
187 int rc = RTSemEventWait(pTimer->Event, RT_INDEFINITE_WAIT);
188 if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED)
189 {
190 AssertRC(rc);
191 RTThreadSleep(1000); /* Don't cause trouble! */
192 }
193 if ( pTimer->fSuspended
194 || pTimer->fDestroyed)
195 continue;
196 }
197
198 /*
199 * Start the timer.
200 *
201 * For some SunOS (/SysV?) threading compatibility Linux will only
202 * deliver the SIGALRM to the thread calling setitimer(). Therefore
203 * we have to call it here.
204 *
205 * It turns out this might not always be the case, see SIGALRM killing
206 * processes on RH 2.4.21.
207 */
208 struct itimerval TimerVal;
209 if (pTimer->u64NanoFirst)
210 {
211 uint64_t u64 = RT_MAX(1000, pTimer->u64NanoFirst);
212 TimerVal.it_value.tv_sec = u64 / 1000000000;
213 TimerVal.it_value.tv_usec = (u64 % 1000000000) / 1000;
214 }
215 else
216 {
217 TimerVal.it_value.tv_sec = 0;
218 TimerVal.it_value.tv_usec = 10;
219 }
220 if (pTimer->u64NanoInterval)
221 {
222 uint64_t u64 = RT_MAX(1000, pTimer->u64NanoInterval);
223 TimerVal.it_interval.tv_sec = u64 / 1000000000;
224 TimerVal.it_interval.tv_usec = (u64 % 1000000000) / 1000;
225 }
226 else
227 {
228 TimerVal.it_interval.tv_sec = 0;
229 TimerVal.it_interval.tv_usec = 0;
230 }
231
232 if (setitimer(ITIMER_REAL, &TimerVal, NULL))
233 {
234 ASMAtomicXchgU8(&pTimer->fSuspended, true);
235 pTimer->iError = RTErrConvertFromErrno(errno);
236 RTThreadUserSignal(Thread);
237 continue; /* back to suspended mode. */
238 }
239 pTimer->iError = 0;
240 RTThreadUserSignal(Thread);
241
242 /*
243 * Timer Service Loop.
244 */
245 sigemptyset(&SigSet);
246 sigaddset(&SigSet, SIGALRM);
247 do
248 {
249 siginfo_t SigInfo = {0};
250#ifdef RT_OS_DARWIN
251 if (RT_LIKELY(sigwait(&SigSet, &SigInfo.si_signo) >= 0))
252 {
253#else
254 if (RT_LIKELY(sigwaitinfo(&SigSet, &SigInfo) >= 0))
255 {
256 if (RT_LIKELY(SigInfo.si_signo == SIGALRM))
257#endif
258 {
259 if (RT_UNLIKELY( pTimer->fSuspended
260 || pTimer->fDestroyed
261 || pTimer->u32Magic != RTTIMER_MAGIC))
262 break;
263
264 pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pTimer->iTick);
265
266 /* auto suspend one-shot timers. */
267 if (RT_UNLIKELY(!pTimer->u64NanoInterval))
268 {
269 ASMAtomicXchgU8(&pTimer->fSuspended, true);
270 break;
271 }
272 }
273 }
274 else if (errno != EINTR)
275 AssertMsgFailed(("sigwaitinfo -> errno=%d\n", errno));
276 } while (RT_LIKELY( !pTimer->fSuspended
277 && !pTimer->fDestroyed
278 && pTimer->u32Magic == RTTIMER_MAGIC));
279
280 /*
281 * Disable the timer.
282 */
283 struct itimerval TimerVal2 = {{0,0}, {0,0}};
284 if (setitimer(ITIMER_REAL, &TimerVal2, NULL))
285 AssertMsgFailed(("setitimer(ITIMER_REAL,&{0}, NULL) failed, errno=%d\n", errno));
286
287 /*
288 * ACK any pending suspend request.
289 */
290 if (!pTimer->fDestroyed)
291 {
292 pTimer->iError = 0;
293 RTThreadUserSignal(Thread);
294 }
295 }
296
297 /*
298 * Exit.
299 */
300 pTimer->iError = 0;
301 RTThreadUserSignal(Thread);
302
303 return VINF_SUCCESS;
304}
305#else /* !IPRT_WITH_POSIX_TIMERS */
306void rttimerCallback(union sigval SigVal)
307{
308 PRTTIMER pTimer = (PRTTIMER)SigVal.sival_ptr;
309 /* Is the timer being destoyed/suspended at this very moment? */
310 if (RT_LIKELY(pTimer->u32Magic == RTTIMER_MAGIC
311 && !pTimer->fSuspended
312 && !pTimer->fDestroyed))
313 {
314 pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pTimer->iTick);
315 }
316}
317#endif /* !IPRT_WITH_POSIX_TIMERS */
318
319
320RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
321{
322 /*
323 * We don't support the fancy MP features.
324 */
325 if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
326 return VERR_NOT_SUPPORTED;
327
328#ifndef IPRT_WITH_POSIX_TIMERS /** @todo the signal blocking applies to the new code too, see comment in the struct. */
329 /*
330 * Check if timer is busy.
331 */
332 struct itimerval TimerVal;
333 if (getitimer(ITIMER_REAL, &TimerVal))
334 {
335 AssertMsgFailed(("getitimer() -> errno=%d\n", errno));
336 return VERR_NOT_IMPLEMENTED;
337 }
338 if ( TimerVal.it_value.tv_usec || TimerVal.it_value.tv_sec
339 || TimerVal.it_interval.tv_usec || TimerVal.it_interval.tv_sec
340 )
341 {
342 AssertMsgFailed(("A timer is running. System limit is one timer per process!\n"));
343 return VERR_TIMER_BUSY;
344 }
345
346 /*
347 * Block SIGALRM from calling thread.
348 */
349 sigset_t SigSet;
350 sigemptyset(&SigSet);
351 sigaddset(&SigSet, SIGALRM);
352 sigprocmask(SIG_BLOCK, &SigSet, NULL);
353
354 /** @todo Move this RTC hack else where... */
355 static bool fDoneRTC;
356 if (!fDoneRTC)
357 {
358 fDoneRTC = true;
359 /* check resolution. */
360 TimerVal.it_interval.tv_sec = 0;
361 TimerVal.it_interval.tv_usec = 1000;
362 TimerVal.it_value = TimerVal.it_interval;
363 if ( setitimer(ITIMER_REAL, &TimerVal, NULL)
364 || getitimer(ITIMER_REAL, &TimerVal)
365 || TimerVal.it_interval.tv_usec > 1000)
366 {
367 /*
368 * Try open /dev/rtc to set the irq rate to 1024 and
369 * turn periodic
370 */
371 Log(("RTTimerCreate: interval={%ld,%ld} trying to adjust /dev/rtc!\n", TimerVal.it_interval.tv_sec, TimerVal.it_interval.tv_usec));
372#ifdef RT_OS_LINUX
373 int fh = open("/dev/rtc", O_RDONLY);
374 if (fh >= 0)
375 {
376 if ( ioctl(fh, RTC_IRQP_SET, 1024) < 0
377 || ioctl(fh, RTC_PIE_ON, 0) < 0)
378 Log(("RTTimerCreate: couldn't configure rtc! errno=%d\n", errno));
379 ioctl(fh, F_SETFL, O_ASYNC);
380 ioctl(fh, F_SETOWN, getpid());
381 /* not so sure if closing it is a good idea... */
382 //close(fh);
383 }
384 else
385 Log(("RTTimerCreate: couldn't configure rtc! open failed with errno=%d\n", errno));
386#endif
387 }
388 /* disable it */
389 TimerVal.it_interval.tv_sec = 0;
390 TimerVal.it_interval.tv_usec = 0;
391 TimerVal.it_value = TimerVal.it_interval;
392 setitimer(ITIMER_REAL, &TimerVal, NULL);
393 }
394
395 /*
396 * Create a new timer.
397 */
398 int rc;
399 PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));
400 if (pTimer)
401 {
402 pTimer->u32Magic = RTTIMER_MAGIC;
403 pTimer->fSuspended = true;
404 pTimer->fDestroyed = false;
405 pTimer->Thread = NIL_RTTHREAD;
406 pTimer->Event = NIL_RTSEMEVENT;
407 pTimer->pfnTimer = pfnTimer;
408 pTimer->pvUser = pvUser;
409 pTimer->u64NanoInterval = u64NanoInterval;
410 pTimer->u64NanoFirst = 0;
411 pTimer->iTick = 0;
412 pTimer->iError = 0;
413 rc = RTSemEventCreate(&pTimer->Event);
414 AssertRC(rc);
415 if (RT_SUCCESS(rc))
416 {
417 rc = RTThreadCreate(&pTimer->Thread, rttimerThread, pTimer, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "Timer");
418 AssertRC(rc);
419 if (RT_SUCCESS(rc))
420 {
421 /*
422 * Wait for the timer thread to initialize it self.
423 * This might take a little while...
424 */
425 rc = RTThreadUserWait(pTimer->Thread, 45*1000);
426 AssertRC(rc);
427 if (RT_SUCCESS(rc))
428 {
429 rc = RTThreadUserReset(pTimer->Thread); AssertRC(rc);
430 rc = pTimer->iError;
431 AssertRC(rc);
432 if (RT_SUCCESS(rc))
433 {
434 RTThreadYield(); /* <-- Horrible hack to make tstTimer work. (linux 2.6.12) */
435 *ppTimer = pTimer;
436 return VINF_SUCCESS;
437 }
438 }
439
440 /* bail out */
441 ASMAtomicXchgU8(&pTimer->fDestroyed, true);
442 ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1);
443 RTThreadWait(pTimer->Thread, 45*1000, NULL);
444 }
445 RTSemEventDestroy(pTimer->Event);
446 pTimer->Event = NIL_RTSEMEVENT;
447 }
448 RTMemFree(pTimer);
449 }
450 else
451 rc = VERR_NO_MEMORY;
452#else /* !IPRT_WITH_POSIX_TIMERS */
453 /*
454 * Create a new timer.
455 */
456 int rc;
457 PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));
458 if (pTimer)
459 {
460 struct sigevent evt;
461
462 /* Initialize timer structure. */
463 pTimer->u32Magic = RTTIMER_MAGIC;
464 pTimer->fSuspended = true;
465 pTimer->fDestroyed = false;
466 pTimer->pfnTimer = pfnTimer;
467 pTimer->pvUser = pvUser;
468 pTimer->u64NanoInterval = u64NanoInterval;
469 pTimer->iTick = 0;
470
471 /* Ask to call rttimerCallback in a separate thread context upon timer expiration. */
472 memset(&evt, 0, sizeof(evt));
473 evt.sigev_notify = SIGEV_THREAD;
474 evt.sigev_value.sival_ptr = pTimer;
475 evt.sigev_notify_function = rttimerCallback;
476
477 rc = RTErrConvertFromErrno(timer_create(CLOCK_REALTIME, &evt, &pTimer->timer));
478 if (RT_SUCCESS(rc))
479 {
480 *ppTimer = pTimer;
481 return VINF_SUCCESS;
482 }
483 RTMemFree(pTimer);
484 }
485 else
486 rc = VERR_NO_MEMORY;
487
488#endif /* !IPRT_WITH_POSIX_TIMERS */
489 return rc;
490}
491
492
493RTR3DECL(int) RTTimerDestroy(PRTTIMER pTimer)
494{
495 LogFlow(("RTTimerDestroy: pTimer=%p\n", pTimer));
496
497 /*
498 * Validate input.
499 */
500 /* NULL is ok. */
501 if (!pTimer)
502 return VINF_SUCCESS;
503 int rc = VINF_SUCCESS;
504 AssertPtrReturn(pTimer, VERR_INVALID_POINTER);
505 AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_MAGIC);
506#ifndef IPRT_WITH_POSIX_TIMERS
507 AssertReturn(pTimer->Thread != RTThreadSelf(), VERR_INTERNAL_ERROR);
508
509 /*
510 * Tell the thread to terminate and wait for it do complete.
511 */
512 ASMAtomicXchgU8(&pTimer->fDestroyed, true);
513 ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1);
514 rc = RTSemEventSignal(pTimer->Event);
515 AssertRC(rc);
516 if (!pTimer->fSuspended)
517 {
518#ifndef RT_OS_OS2
519 pthread_kill((pthread_t)RTThreadGetNative(pTimer->Thread), SIGALRM);
520#endif
521 }
522 rc = RTThreadWait(pTimer->Thread, 30 * 1000, NULL);
523 AssertRC(rc);
524
525 RTSemEventDestroy(pTimer->Event);
526 pTimer->Event = NIL_RTSEMEVENT;
527#else /* !IPRT_WITH_POSIX_TIMERS */
528 if (ASMAtomicXchgU8(&pTimer->fDestroyed, true))
529 {
530 /* It is already being destroyed by another thread. */
531 return VINF_SUCCESS;
532 }
533 rc = RTErrConvertFromErrno(timer_delete(pTimer->timer));
534#endif /* !IPRT_WITH_POSIX_TIMERS */
535 if (RT_SUCCESS(rc))
536 RTMemFree(pTimer);
537 return rc;
538}
539
540
541RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
542{
543 /*
544 * Validate input.
545 */
546 AssertPtrReturn(pTimer, VERR_INVALID_POINTER);
547 AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_MAGIC);
548#ifndef IPRT_WITH_POSIX_TIMERS
549 AssertReturn(pTimer->Thread != RTThreadSelf(), VERR_INTERNAL_ERROR);
550
551 /*
552 * Already running?
553 */
554 if (!pTimer->fSuspended)
555 return VERR_TIMER_ACTIVE;
556
557 /*
558 * Tell the thread to start servicing the timer.
559 */
560 RTThreadUserReset(pTimer->Thread);
561 ASMAtomicUoWriteU64(&pTimer->u64NanoFirst, u64First);
562 ASMAtomicUoWriteU64(&pTimer->iTick, 0);
563 ASMAtomicWriteU8(&pTimer->fSuspended, false);
564 int rc = RTSemEventSignal(pTimer->Event);
565 if (RT_SUCCESS(rc))
566 {
567 rc = RTThreadUserWait(pTimer->Thread, 45*1000);
568 AssertRC(rc);
569 RTThreadUserReset(pTimer->Thread);
570 }
571 else
572 AssertRC(rc);
573 if (RT_FAILURE(rc))
574 ASMAtomicXchgU8(&pTimer->fSuspended, false);
575#else /* !IPRT_WITH_POSIX_TIMERS */
576 struct itimerspec ts;
577
578 if (!ASMAtomicXchgU8(&pTimer->fSuspended, false))
579 return VERR_TIMER_ACTIVE;
580
581 ts.it_value.tv_sec = u64First / 1000000000; /* nanosec => sec */
582 ts.it_value.tv_nsec = u64First ? u64First % 1000000000 : 1; /* 0 means disable, replace it with 1. */
583 ts.it_interval.tv_sec = pTimer->u64NanoInterval / 1000000000;
584 ts.it_interval.tv_nsec = pTimer->u64NanoInterval % 1000000000;
585 int rc = RTErrConvertFromErrno(timer_settime(pTimer->timer, 0, &ts, NULL));
586#endif /* !IPRT_WITH_POSIX_TIMERS */
587
588 return rc;
589}
590
591
592RTDECL(int) RTTimerStop(PRTTIMER pTimer)
593{
594 /*
595 * Validate input.
596 */
597 AssertPtrReturn(pTimer, VERR_INVALID_POINTER);
598 AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_MAGIC);
599
600#ifndef IPRT_WITH_POSIX_TIMERS
601 /*
602 * Already running?
603 */
604 if (pTimer->fSuspended)
605 return VERR_TIMER_SUSPENDED;
606
607 /*
608 * Tell the thread to stop servicing the timer.
609 */
610 RTThreadUserReset(pTimer->Thread);
611 ASMAtomicXchgU8(&pTimer->fSuspended, true);
612 int rc = VINF_SUCCESS;
613 if (RTThreadSelf() != pTimer->Thread)
614 {
615#ifndef RT_OS_OS2
616 pthread_kill((pthread_t)RTThreadGetNative(pTimer->Thread), SIGALRM);
617#endif
618 rc = RTThreadUserWait(pTimer->Thread, 45*1000);
619 AssertRC(rc);
620 RTThreadUserReset(pTimer->Thread);
621 }
622#else /* !IPRT_WITH_POSIX_TIMERS */
623 struct itimerspec ts;
624
625 if (ASMAtomicXchgU8(&pTimer->fSuspended, true))
626 return VERR_TIMER_SUSPENDED;
627
628 ts.it_value.tv_sec = 0;
629 ts.it_value.tv_nsec = 0;
630 int rc = RTErrConvertFromErrno(timer_settime(pTimer->timer, 0, &ts, NULL));
631#endif /* !IPRT_WITH_POSIX_TIMERS */
632
633 return rc;
634}
635
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette