/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */ /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */ /* Copyright (C) 2014 Stony Brook University This file is part of Graphene Library OS. Graphene Library OS is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Graphene Library OS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ /* * shim_alarm.c * * Implementation of system call "alarm", "setitmer" and "getitimer". */ #include #include #include #include #include void signal_alarm (IDTYPE target, void * arg) { debug("alarm goes off, signaling thread %u\n", target); struct shim_thread * thread = lookup_thread(target); if (!thread) return; append_signal(thread, SIGALRM, NULL, true); } int shim_do_alarm (unsigned int seconds) { uint64_t usecs = 1000000ULL * seconds; uint64_t usecs_left = install_async_event(NULL, usecs, &signal_alarm, NULL); // Alarm expects the number of seconds remaining. Round up. int secs = usecs_left / 1000000ULL; if (usecs_left % 1000000ULL) secs++; return secs; } static struct { unsigned long timeout; unsigned long reset; } real_itimer; void signal_itimer (IDTYPE target, void * arg) { master_lock(); if (real_itimer.timeout != (unsigned long) arg) { master_unlock(); return; } real_itimer.timeout += real_itimer.reset; real_itimer.reset = 0; master_unlock(); } #ifndef ITIMER_REAL # define ITIMER_REAL 0 #endif int shim_do_setitimer (int which, struct __kernel_itimerval * value, struct __kernel_itimerval * ovalue) { if (which != ITIMER_REAL) return -ENOSYS; if (!value) return -EFAULT; unsigned long setup_time = DkSystemTimeQuery(); unsigned long next_value = value->it_value.tv_sec * 1000000 + value->it_value.tv_usec; unsigned long next_reset = value->it_interval.tv_sec * 1000000 + value->it_interval.tv_usec; master_lock(); unsigned long current_timeout = real_itimer.timeout > setup_time ? real_itimer.timeout - setup_time : 0; unsigned long current_reset = real_itimer.reset; uint64_t ret = install_async_event(NULL, next_value, &signal_itimer, (void *) (setup_time + next_value)); if (ret < 0) { master_unlock(); return ret; } real_itimer.timeout = setup_time + next_value; real_itimer.reset = next_reset; master_unlock(); if (ovalue) { ovalue->it_interval.tv_sec = current_reset / 1000000; ovalue->it_interval.tv_usec = current_reset % 1000000; ovalue->it_value.tv_sec = current_timeout / 1000000; ovalue->it_value.tv_usec = current_timeout % 1000000; } return 0; } int shim_do_getitimer (int which, struct __kernel_itimerval * value) { if (which != ITIMER_REAL) return -ENOSYS; if (!value) return -EFAULT; unsigned long setup_time = DkSystemTimeQuery(); master_lock(); unsigned long current_timeout = real_itimer.timeout > setup_time ? real_itimer.timeout - setup_time : 0; unsigned long current_reset = real_itimer.reset; master_unlock(); value->it_interval.tv_sec = current_reset / 1000000; value->it_interval.tv_usec = current_reset % 1000000; value->it_value.tv_sec = current_timeout / 1000000; value->it_value.tv_usec = current_timeout % 1000000; return 0; }