e10ce184e4
Previously, there was a tiny chance that tickdelay(3) would return early or that it would fail to reinstate a previous alarm. - sys_setalarm(2) now returns TMR_NEVER instead of 0 for the time left if no previous alarm was set; - sys_setalarm(2) now also returns the current time, to allow the caller to determine whether it got an alarm notification for the alarm it set or for a previous alarm that has just gone off; - tickdelay(3) now makes use of these facilities. Change-Id: Id4f8fe19a61ca8574f43131964e6f0317f613f49
49 lines
1.6 KiB
C
49 lines
1.6 KiB
C
#include "sysutil.h"
|
|
#include <minix/timers.h>
|
|
|
|
/*===========================================================================*
|
|
* tickdelay *
|
|
*===========================================================================*/
|
|
int tickdelay(clock_t ticks)
|
|
{
|
|
/* This function uses the synchronous alarm to delay for a while. This works
|
|
* even if a previous synchronous alarm was scheduled, because the remaining
|
|
* ticks of the previous alarm are returned so that it can be rescheduled.
|
|
* Note however that a long tick delay (longer than the remaining time of the
|
|
* previous) alarm will also delay the previous alarm.
|
|
*/
|
|
clock_t time_left, uptime;
|
|
message m;
|
|
int r, status;
|
|
|
|
if (ticks <= 0) return OK; /* check for robustness */
|
|
|
|
/* Set the new alarm while getting the time left on the previous alarm. */
|
|
if ((r = sys_setalarm2(ticks, FALSE, &time_left, &uptime)) != OK)
|
|
return r;
|
|
|
|
/* Await synchronous alarm. Since an alarm notification may already have
|
|
* been dispatched by the time that we set the new alarm, we keep going
|
|
* until we actually receive an alarm with a timestamp no earlier than the
|
|
* alarm time we expect.
|
|
*/
|
|
while ((r = ipc_receive(CLOCK, &m, &status)) == OK) {
|
|
if (m.m_type == NOTIFY_MESSAGE &&
|
|
m.m_notify.timestamp >= uptime + ticks)
|
|
break;
|
|
}
|
|
|
|
/* Check if we must reschedule the previous alarm. */
|
|
if (time_left != TMR_NEVER) {
|
|
if (time_left > ticks)
|
|
time_left -= ticks;
|
|
else
|
|
time_left = 1; /* force an alarm */
|
|
|
|
/* There's no point in returning an error from here.. */
|
|
(void)sys_setalarm(time_left, FALSE);
|
|
}
|
|
|
|
return r;
|
|
}
|