setitimer: allow ITIMER_PROF to be used as a monotonic timer, return -EINVAL if a tv_usec exceeds 999999
@@ -557,21 +557,43 @@ closure_function(1, 1, void, itimer_expire,
remove_unix_timer(ut); /* deallocs closure for us */
}
+#define USEC_LIMIT 999999
+
sysreturn setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value)
{
clock_id clockid;
process p = current->p;
- if (which == ITIMER_VIRTUAL || which == ITIMER_PROF) {
- msg_err("timer type %d not yet supported\n");
+ /* Since we are a unikernel, and ITIMER_REAL accounts for both
+ user and system time, we'll just treat it like an ITIMER_REAL.
+
+ This isn't entirely accurate because it accounts for system
+ time that isn't on behalf of running threads. A more accurate
+ method might be to create a timer heap per clock domain (in
+ this case timer heaps attached to the process itself). We are
+ presently limited by all timers mapping to monotonic system
+ time. */
+ if (which == ITIMER_VIRTUAL) {
+ msg_err("timer type %d not yet supported\n", which);
+ if (new_value) {
+ msg_err(" (it_value %T, it_interval %T)\n",
+ time_from_timeval(&new_value->it_value),
+ time_from_timeval(&new_value->it_interval));
+ }
return -EOPNOTSUPP;
- } else if (which != ITIMER_REAL) {
- return -EINVAL;
- } else {
+ } else if (which == ITIMER_REAL) {
clockid = CLOCK_ID_REALTIME;
+ } else if (which == ITIMER_PROF) {
+ clockid = CLOCK_ID_MONOTONIC;
+ } else {
+ return -EINVAL;
}
+ if (new_value && (new_value->it_value.tv_usec > USEC_LIMIT ||
+ new_value->it_interval.tv_usec > USEC_LIMIT))
+ return -EINVAL;
+
unix_timer ut = vector_get(p->itimers, which);
if (!ut) {
ut = allocate_unix_timer(UNIX_TIMER_TYPE_ITIMER, clockid);
