1 /* This file deals with the alarm clock related system calls, eventually
2 * passing off the work to the functions in timers.c and check_sig() in
3 * signal.c to pass an alarm signal to a process.
5 * The entry points into this file are:
6 * do_itimer: perform the ITIMER system call
7 * do_alarm: perform the ALARM system call
8 * set_alarm: tell the timer interface to start or stop a process timer
9 * check_vtimer: check if one of the virtual timers needs to be restarted
16 #include <minix/com.h>
20 #define US 1000000 /* shortcut for microseconds per second */
22 FORWARD
_PROTOTYPE( clock_t ticks_from_timeval
, (struct timeval
*tv
) );
23 FORWARD
_PROTOTYPE( void timeval_from_ticks
, (struct timeval
*tv
,
25 FORWARD
_PROTOTYPE( int is_sane_timeval
, (struct timeval
*tv
) );
26 FORWARD
_PROTOTYPE( void getset_vtimer
, (struct mproc
*mp
, int nwhich
,
27 struct itimerval
*value
, struct itimerval
*ovalue
) );
28 FORWARD
_PROTOTYPE( void get_realtimer
, (struct mproc
*mp
,
29 struct itimerval
*value
) );
30 FORWARD
_PROTOTYPE( void set_realtimer
, (struct mproc
*mp
,
31 struct itimerval
*value
) );
32 FORWARD
_PROTOTYPE( void cause_sigalrm
, (struct timer
*tp
) );
34 /*===========================================================================*
35 * ticks_from_timeval *
36 *===========================================================================*/
37 PRIVATE
clock_t ticks_from_timeval(tv
)
42 /* Large delays cause a lot of problems. First, the alarm system call
43 * takes an unsigned seconds count and the library has cast it to an int.
44 * That probably works, but on return the library will convert "negative"
45 * unsigneds to errors. Presumably no one checks for these errors, so
46 * force this call through. Second, If unsigned and long have the same
47 * size, converting from seconds to ticks can easily overflow. Finally,
48 * the kernel has similar overflow bugs adding ticks.
50 * Fixing this requires a lot of ugly casts to fit the wrong interface
51 * types and to avoid overflow traps. ALRM_EXP_TIME has the right type
52 * (clock_t) although it is declared as long. How can variables like
53 * this be declared properly without combinatorial explosion of message
57 /* In any case, the following conversion must always round up. */
59 ticks
= (clock_t) (system_hz
* (unsigned long) tv
->tv_sec
);
60 if ( (unsigned long) ticks
/ system_hz
!= (unsigned long) tv
->tv_sec
) {
64 ((system_hz
* (unsigned long) tv
->tv_usec
+ (US
-1)) / US
);
67 if (ticks
< 0) ticks
= LONG_MAX
;
72 /*===========================================================================*
73 * timeval_from_ticks *
74 *===========================================================================*/
75 PRIVATE
void timeval_from_ticks(tv
, ticks
)
79 tv
->tv_sec
= (long) (ticks
/ system_hz
);
80 tv
->tv_usec
= (long) ((ticks
% system_hz
) * US
/ system_hz
);
83 /*===========================================================================*
85 *===========================================================================*/
86 PRIVATE
int is_sane_timeval(tv
)
89 /* This imposes a reasonable time value range for setitimer. */
90 return (tv
->tv_sec
>= 0 && tv
->tv_sec
<= MAX_SECS
&&
91 tv
->tv_usec
>= 0 && tv
->tv_usec
< US
);
94 /*===========================================================================*
96 *===========================================================================*/
97 PUBLIC
int do_itimer()
99 struct itimerval ovalue
, value
; /* old and new interval timers */
100 int setval
, getval
; /* set and/or retrieve the values? */
103 /* Make sure 'which' is one of the defined timers. */
104 if (m_in
.which_timer
< 0 || m_in
.which_timer
>= NR_ITIMERS
)
107 /* Determine whether to set and/or return the given timer value, based on
108 * which of the new_val and old_val parameters are nonzero. At least one of
109 * them must be nonzero.
111 setval
= (m_in
.new_val
!= NULL
);
112 getval
= (m_in
.old_val
!= NULL
);
114 if (!setval
&& !getval
) return(EINVAL
);
116 /* If we're setting a new value, copy the new timer from user space.
117 * Also, make sure its fields have sane values.
120 r
= sys_datacopy(who_e
, (vir_bytes
) m_in
.new_val
,
121 PM_PROC_NR
, (vir_bytes
) &value
, (phys_bytes
) sizeof(value
));
122 if (r
!= OK
) return(r
);
124 if (!is_sane_timeval(&value
.it_value
) ||
125 !is_sane_timeval(&value
.it_interval
))
129 switch (m_in
.which_timer
) {
131 if (getval
) get_realtimer(mp
, &ovalue
);
133 if (setval
) set_realtimer(mp
, &value
);
138 case ITIMER_VIRTUAL
:
140 getset_vtimer(mp
, m_in
.which_timer
,
141 (setval
) ? &value
: NULL
,
142 (getval
) ? &ovalue
: NULL
);
148 panic("invalid timer type: %d", m_in
.which_timer
);
151 /* If requested, copy the old interval timer to user space. */
152 if (r
== OK
&& getval
) {
153 r
= sys_datacopy(PM_PROC_NR
, (vir_bytes
) &ovalue
,
154 who_e
, (vir_bytes
) m_in
.old_val
, (phys_bytes
) sizeof(ovalue
));
160 /*===========================================================================*
162 *===========================================================================*/
163 PUBLIC
int do_alarm()
165 struct itimerval value
, ovalue
;
166 int remaining
; /* previous time left in seconds */
168 /* retrieve the old timer value, in seconds (rounded up) */
169 get_realtimer(mp
, &ovalue
);
171 remaining
= ovalue
.it_value
.tv_sec
;
172 if (ovalue
.it_value
.tv_usec
> 0) remaining
++;
174 /* set the new timer value */
175 memset(&value
, 0, sizeof(value
));
176 value
.it_value
.tv_sec
= m_in
.seconds
;
178 set_realtimer(mp
, &value
);
180 /* and return the old timer value */
184 /*===========================================================================*
186 *===========================================================================*/
187 PRIVATE
void getset_vtimer(rmp
, which
, value
, ovalue
)
190 struct itimerval
*value
;
191 struct itimerval
*ovalue
;
193 clock_t newticks
, *nptr
; /* the new timer value, in ticks */
194 clock_t oldticks
, *optr
; /* the old ticks value, in ticks */
197 /* The default is to provide sys_vtimer with two null pointers, i.e. to do
202 /* If the old timer value is to be retrieved, have 'optr' point to the
203 * location where the old value is to be stored, and copy the interval.
205 if (ovalue
!= NULL
) {
208 timeval_from_ticks(&ovalue
->it_interval
, rmp
->mp_interval
[which
]);
211 /* If a new timer value is to be set, store the new timer value and have
212 * 'nptr' point to it. Also, store the new interval.
215 newticks
= ticks_from_timeval(&value
->it_value
);
218 /* If no timer is set, the interval must be zero. */
220 rmp
->mp_interval
[which
] = 0;
222 rmp
->mp_interval
[which
] =
223 ticks_from_timeval(&value
->it_interval
);
226 /* Find out which kernel timer number to use. */
228 case ITIMER_VIRTUAL
: num
= VT_VIRTUAL
; break;
229 case ITIMER_PROF
: num
= VT_PROF
; break;
230 default: panic("invalid vtimer type: %d", which
);
233 /* Make the kernel call. If requested, also retrieve and store
234 * the old timer value.
236 if ((r
= sys_vtimer(rmp
->mp_endpoint
, num
, nptr
, optr
)) != OK
)
237 panic("sys_vtimer failed: %d", r
);
239 if (ovalue
!= NULL
) {
240 /* If the alarm expired already, we should take into account the
241 * interval. Return zero only if the interval is zero as well.
243 if (oldticks
<= 0) oldticks
= rmp
->mp_interval
[which
];
245 timeval_from_ticks(&ovalue
->it_value
, oldticks
);
249 /*===========================================================================*
251 *===========================================================================*/
252 PUBLIC
void check_vtimer(proc_nr
, sig
)
256 register struct mproc
*rmp
;
259 rmp
= &mproc
[proc_nr
];
261 /* Translate back the given signal to a timer type and kernel number. */
263 case SIGVTALRM
: which
= ITIMER_VIRTUAL
; num
= VT_VIRTUAL
; break;
264 case SIGPROF
: which
= ITIMER_PROF
; num
= VT_PROF
; break;
265 default: panic("invalid vtimer signal: %d", sig
);
268 /* If a repetition interval was set for this virtual timer, tell the
269 * kernel to set a new timeout for the virtual timer.
271 if (rmp
->mp_interval
[which
] > 0)
272 sys_vtimer(rmp
->mp_endpoint
, num
, &rmp
->mp_interval
[which
], NULL
);
275 /*===========================================================================*
277 *===========================================================================*/
278 PRIVATE
void get_realtimer(rmp
, value
)
280 struct itimerval
*value
;
282 clock_t exptime
; /* time at which alarm will expire */
283 clock_t uptime
; /* current system time */
284 clock_t remaining
; /* time left on alarm */
287 /* First determine remaining time, in ticks, of previous alarm, if set. */
288 if (rmp
->mp_flags
& ALARM_ON
) {
289 if ( (s
= getuptime(&uptime
)) != OK
)
290 panic("get_realtimer couldn't get uptime: %d", s
);
291 exptime
= *tmr_exp_time(&rmp
->mp_timer
);
293 remaining
= exptime
- uptime
;
295 /* If the alarm expired already, we should take into account the
296 * interval. Return zero only if the interval is zero as well.
298 if (remaining
<= 0) remaining
= rmp
->mp_interval
[ITIMER_REAL
];
303 /* Convert the result to a timeval structure. */
304 timeval_from_ticks(&value
->it_value
, remaining
);
306 /* Similarly convert and store the interval of the timer. */
307 timeval_from_ticks(&value
->it_interval
, rmp
->mp_interval
[ITIMER_REAL
]);
310 /*===========================================================================*
312 *===========================================================================*/
313 PRIVATE
void set_realtimer(rmp
, value
)
315 struct itimerval
*value
;
317 clock_t ticks
; /* New amount of ticks to the next alarm. */
318 clock_t interval
; /* New amount of ticks for the alarm's interval. */
320 /* Convert the timeval structures in the 'value' structure to ticks. */
321 ticks
= ticks_from_timeval(&value
->it_value
);
322 interval
= ticks_from_timeval(&value
->it_interval
);
324 /* If no timer is set, the interval must be zero. */
325 if (ticks
<= 0) interval
= 0;
327 /* Apply these values. */
328 set_alarm(rmp
, ticks
);
329 rmp
->mp_interval
[ITIMER_REAL
] = interval
;
332 /*===========================================================================*
334 *===========================================================================*/
335 PUBLIC
void set_alarm(rmp
, ticks
)
336 struct mproc
*rmp
; /* process that wants the alarm */
337 clock_t ticks
; /* how many ticks delay before the signal */
340 pm_set_timer(&rmp
->mp_timer
, ticks
, cause_sigalrm
, rmp
->mp_endpoint
);
341 rmp
->mp_flags
|= ALARM_ON
;
342 } else if (rmp
->mp_flags
& ALARM_ON
) {
343 pm_cancel_timer(&rmp
->mp_timer
);
344 rmp
->mp_flags
&= ~ALARM_ON
;
348 /*===========================================================================*
350 *===========================================================================*/
351 PRIVATE
void cause_sigalrm(tp
)
355 register struct mproc
*rmp
;
357 /* get process from timer */
358 if(pm_isokendpt(tmr_arg(tp
)->ta_int
, &proc_nr_n
) != OK
) {
359 printf("PM: ignoring timer for invalid endpoint %d\n",
360 tmr_arg(tp
)->ta_int
);
364 rmp
= &mproc
[proc_nr_n
];
366 if ((rmp
->mp_flags
& (IN_USE
| EXITING
)) != IN_USE
) return;
367 if ((rmp
->mp_flags
& ALARM_ON
) == 0) return;
369 /* If an interval is set, set a new timer; otherwise clear the ALARM_ON flag.
370 * The set_alarm call will be calling pm_set_timer from within this callback
371 * from the pm_expire_timers function. This is safe, but we must not use the
372 * "tp" structure below this point anymore. */
373 if (rmp
->mp_interval
[ITIMER_REAL
] > 0)
374 set_alarm(rmp
, rmp
->mp_interval
[ITIMER_REAL
]);
375 else rmp
->mp_flags
&= ~ALARM_ON
;
377 check_sig(rmp
->mp_pid
, SIGALRM
, FALSE
/* ksig */);