mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Refactor kernel time API and add timespec API.
This commit is contained in:
parent
5424760719
commit
9ba7f26bf0
14 changed files with 398 additions and 116 deletions
|
@ -108,6 +108,7 @@ strstr.o \
|
|||
strtok.o \
|
||||
strtok_r.o \
|
||||
strxfrm.o \
|
||||
timespec.o \
|
||||
ungetc.o \
|
||||
vfscanf.o \
|
||||
vsscanf.o \
|
||||
|
|
4
libc/decl/clockid_t.h
Normal file
4
libc/decl/clockid_t.h
Normal file
|
@ -0,0 +1,4 @@
|
|||
#ifndef _CLOCKID_T_DECL
|
||||
#define _CLOCKID_T_DECL
|
||||
typedef __clockid_t clockid_t;
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -34,7 +34,7 @@ __BEGIN_DECLS
|
|||
@include(blkcnt_t.h)
|
||||
@include(blksize_t.h)
|
||||
@include(clock_t.h)
|
||||
/* TODO: clockid_t */
|
||||
@include(clockid_t.h)
|
||||
@include(dev_t.h)
|
||||
/* TODO: fsblkcnt_t */
|
||||
/* TODO: fsfilcnt_t */
|
||||
|
|
|
@ -30,12 +30,14 @@
|
|||
__BEGIN_DECLS
|
||||
|
||||
@include(clock_t.h)
|
||||
@include(clockid_t.h)
|
||||
@include(size_t.h)
|
||||
@include(pid_t.h)
|
||||
@include(time_t.h)
|
||||
@include(NULL.h)
|
||||
|
||||
__END_DECLS
|
||||
#include <sortix/clock.h>
|
||||
#include <sortix/timespec.h>
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
|
101
libc/include/timespec.h
Normal file
101
libc/include/timespec.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
The Sortix C Library 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.
|
||||
|
||||
The Sortix C Library 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 the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
timespec.h
|
||||
Utility functions for manipulation of struct timespec.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_TIMESPEC_H
|
||||
#define INCLUDE_TIMESPEC_H
|
||||
|
||||
#include <features.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
@include(time_t.h)
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#include <sortix/timespec.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
static inline bool timespec_eq(struct timespec a, struct timespec b)
|
||||
{
|
||||
return a.tv_sec == b.tv_sec && a.tv_nsec == b.tv_nsec;
|
||||
}
|
||||
|
||||
static inline bool timespec_neq(struct timespec a, struct timespec b)
|
||||
{
|
||||
return a.tv_sec != b.tv_sec || a.tv_nsec != b.tv_nsec;
|
||||
}
|
||||
|
||||
static inline bool timespec_lt(struct timespec a, struct timespec b)
|
||||
{
|
||||
return a.tv_sec < b.tv_sec ||
|
||||
(a.tv_sec == b.tv_sec && a.tv_nsec < b.tv_nsec);
|
||||
}
|
||||
|
||||
static inline bool timespec_le(struct timespec a, struct timespec b)
|
||||
{
|
||||
return a.tv_sec < b.tv_sec ||
|
||||
(a.tv_sec == b.tv_sec && a.tv_nsec <= b.tv_nsec);
|
||||
}
|
||||
|
||||
static inline bool timespec_gt(struct timespec a, struct timespec b)
|
||||
{
|
||||
return a.tv_sec > b.tv_sec ||
|
||||
(a.tv_sec == b.tv_sec && a.tv_nsec > b.tv_nsec);
|
||||
}
|
||||
|
||||
static inline bool timespec_ge(struct timespec a, struct timespec b)
|
||||
{
|
||||
return a.tv_sec > b.tv_sec ||
|
||||
(a.tv_sec == b.tv_sec && a.tv_nsec >= b.tv_nsec);
|
||||
}
|
||||
|
||||
static inline struct timespec timespec_make(time_t sec, long nsec)
|
||||
{
|
||||
struct timespec ret;
|
||||
ret.tv_sec = sec;
|
||||
ret.tv_nsec = nsec;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline struct timespec timespec_neg(struct timespec t)
|
||||
{
|
||||
if ( t.tv_nsec )
|
||||
return timespec_make(-t.tv_sec - 1, 1000000000 - t.tv_nsec);
|
||||
return timespec_make(-t.tv_sec, 0);
|
||||
}
|
||||
|
||||
static inline struct timespec timespec_nul()
|
||||
{
|
||||
return timespec_make(0, 0);
|
||||
}
|
||||
|
||||
struct timespec timespec_canonalize(struct timespec t);
|
||||
struct timespec timespec_add(struct timespec a, struct timespec b);
|
||||
struct timespec timespec_sub(struct timespec a, struct timespec b);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
60
libc/timespec.cpp
Normal file
60
libc/timespec.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
The Sortix C Library 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.
|
||||
|
||||
The Sortix C Library 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 the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
timespec.cpp
|
||||
Utility functions for manipulation of struct timespec.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <timespec.h>
|
||||
|
||||
static const long NANOSECONDS_PER_SECOND = 1000000000L;
|
||||
|
||||
// TODO: The C modulo operator doesn't do exactly what we desire.
|
||||
static long proper_modulo(long a, long b)
|
||||
{
|
||||
if ( 0 <= a )
|
||||
return a % b;
|
||||
long tmp = - (unsigned long) a % b;
|
||||
return tmp ? tmp : 0;
|
||||
}
|
||||
|
||||
extern "C" struct timespec timespec_canonalize(struct timespec t)
|
||||
{
|
||||
t.tv_sec += t.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
t.tv_nsec = proper_modulo(t.tv_nsec, NANOSECONDS_PER_SECOND);
|
||||
return t;
|
||||
}
|
||||
|
||||
extern "C" struct timespec timespec_add(struct timespec a, struct timespec b)
|
||||
{
|
||||
struct timespec ret;
|
||||
a = timespec_canonalize(a);
|
||||
b = timespec_canonalize(b);
|
||||
ret.tv_sec = a.tv_sec + b.tv_sec;
|
||||
ret.tv_nsec = a.tv_nsec + b.tv_nsec;
|
||||
return timespec_canonalize(ret);
|
||||
}
|
||||
|
||||
extern "C" struct timespec timespec_sub(struct timespec a, struct timespec b)
|
||||
{
|
||||
a = timespec_canonalize(a);
|
||||
b = timespec_canonalize(b);
|
||||
return timespec_add(a, timespec_neg(b));
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -17,25 +17,23 @@
|
|||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
time.h
|
||||
Handles interrupts whenever some time has passed and provides useful
|
||||
sortix/clock.h
|
||||
Supported logical clock devices.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_TIME_H
|
||||
#define SORTIX_TIME_H
|
||||
#ifndef INCLUDE_SORTIX_CLOCK_H
|
||||
#define INCLUDE_SORTIX_CLOCK_H
|
||||
|
||||
#include "cpu.h"
|
||||
#include <features.h>
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
namespace Time
|
||||
{
|
||||
void Init();
|
||||
void OnIRQ0(CPU::InterruptRegisters* Registers, void* user);
|
||||
float GetTimeSinceBoot();
|
||||
uintmax_t MicrosecondsSinceBoot();
|
||||
}
|
||||
}
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define CLOCK_REALTIME 0 /* Current real time. */
|
||||
#define CLOCK_MONOTONIC 1 /* Always increasing time. */
|
||||
#define CLOCK_BOOT 2 /* Time since system boot (uptime). */
|
||||
#define CLOCK_INIT 3 /* Time since 'init' process began. */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
47
sortix/include/sortix/kernel/time.h
Normal file
47
sortix/include/sortix/kernel/time.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix is free software: you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation, either version 3 of the License, or (at your option) any later
|
||||
version.
|
||||
|
||||
Sortix 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 General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/kernel/time.h
|
||||
Retrieving the current time.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX_KERNEL_TIME_H
|
||||
#define INCLUDE_SORTIX_KERNEL_TIME_H
|
||||
|
||||
#include <features.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <sortix/timespec.h>
|
||||
|
||||
namespace Sortix {
|
||||
namespace Time {
|
||||
|
||||
void Init();
|
||||
struct timespec Get(clockid_t clock, struct timespec* res = NULL);
|
||||
bool TryGet(clockid_t clock, struct timespec* time, struct timespec* res = NULL);
|
||||
|
||||
|
||||
} // namespace Time
|
||||
} // namespace Sortix
|
||||
|
||||
#endif
|
|
@ -149,6 +149,7 @@ typedef unsigned int __nlink_t;
|
|||
typedef __uintmax_t __ino_t;
|
||||
typedef __uintptr_t __dev_t;
|
||||
typedef __intmax_t __clock_t;
|
||||
typedef int __clockid_t;
|
||||
typedef long __time_t;
|
||||
typedef long __suseconds_t;
|
||||
|
||||
|
|
|
@ -149,6 +149,7 @@ typedef unsigned int __nlink_t;
|
|||
typedef __uintmax_t __ino_t;
|
||||
typedef __uintptr_t __dev_t;
|
||||
typedef __intmax_t __clock_t;
|
||||
typedef int __clockid_t;
|
||||
typedef long __time_t;
|
||||
typedef long __suseconds_t;
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <sortix/kernel/keyboard.h>
|
||||
#include <sortix/kernel/syscall.h>
|
||||
#include <sortix/kernel/interrupt.h>
|
||||
#include <sortix/kernel/time.h>
|
||||
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/stat.h>
|
||||
|
@ -56,7 +57,6 @@
|
|||
#include "kernelinfo.h"
|
||||
#include "x86-family/gdt.h"
|
||||
#include "x86-family/float.h"
|
||||
#include "time.h"
|
||||
#include "multiboot.h"
|
||||
#include "thread.h"
|
||||
#include "process.h"
|
||||
|
|
|
@ -22,17 +22,24 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/memorymanagement.h>
|
||||
#include <sortix/kernel/syscall.h>
|
||||
#include <sortix/kernel/interrupt.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <timespec.h>
|
||||
|
||||
#include <sortix/clock.h>
|
||||
#include <sortix/timespec.h>
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/memorymanagement.h>
|
||||
#include <sortix/kernel/syscall.h>
|
||||
#include <sortix/kernel/interrupt.h>
|
||||
#include <sortix/kernel/time.h>
|
||||
|
||||
#include "x86-family/gdt.h"
|
||||
#include "x86-family/float.h"
|
||||
#include "time.h"
|
||||
#include "thread.h"
|
||||
#include "process.h"
|
||||
#include "signal.h"
|
||||
|
@ -260,21 +267,27 @@ Thread::State GetThreadState(Thread* thread)
|
|||
return thread->state;
|
||||
}
|
||||
|
||||
int SysSleep(size_t secs)
|
||||
static void SleepUntil(struct timespec wakeat)
|
||||
{
|
||||
uintmax_t timetosleep = ((uintmax_t) secs) * 1000ULL * 1000ULL;
|
||||
uint32_t wakeat = Time::MicrosecondsSinceBoot() + timetosleep;
|
||||
do { Yield(); }
|
||||
while ( Time::MicrosecondsSinceBoot() < wakeat );
|
||||
while ( timespec_lt(Time::Get(CLOCK_BOOT), wakeat) )
|
||||
Yield();
|
||||
}
|
||||
|
||||
int sys_sleep(size_t secs)
|
||||
{
|
||||
struct timespec delay = timespec_make(secs, 0);
|
||||
struct timespec now = Time::Get(CLOCK_BOOT);
|
||||
SleepUntil(timespec_add(now, delay));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SysUSleep(size_t usecs)
|
||||
int sys_usleep(size_t usecs)
|
||||
{
|
||||
uintmax_t timetosleep = (uintmax_t) usecs;
|
||||
uint32_t wakeat = Time::MicrosecondsSinceBoot() + timetosleep;
|
||||
do { Yield(); }
|
||||
while ( Time::MicrosecondsSinceBoot() < wakeat );
|
||||
size_t secs = usecs / 1000000;
|
||||
size_t nsecs = (usecs % 1000000) * 1000;
|
||||
struct timespec delay = timespec_make(secs, nsecs);
|
||||
struct timespec now = Time::Get(CLOCK_BOOT);
|
||||
SleepUntil(timespec_add(now, delay));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -304,8 +317,8 @@ void Init()
|
|||
Interrupt::RegisterRawHandler(132, thread_exit_handler, true);
|
||||
Interrupt::RegisterHandler(132, ThreadExitCPU, NULL);
|
||||
|
||||
Syscall::Register(SYSCALL_SLEEP, (void*) SysSleep);
|
||||
Syscall::Register(SYSCALL_USLEEP, (void*) SysUSleep);
|
||||
Syscall::Register(SYSCALL_SLEEP, (void*) sys_sleep);
|
||||
Syscall::Register(SYSCALL_USLEEP, (void*) sys_usleep);
|
||||
}
|
||||
|
||||
} // namespace Scheduler
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <sortix/kernel/memorymanagement.h>
|
||||
#include <sortix/kernel/syscall.h>
|
||||
#include <sortix/kernel/interrupt.h>
|
||||
#include <sortix/kernel/time.h>
|
||||
|
||||
#include <sortix/mman.h>
|
||||
#include <sortix/signal.h>
|
||||
|
@ -38,7 +39,6 @@
|
|||
#include "process.h"
|
||||
#include "thread.h"
|
||||
#include "scheduler.h"
|
||||
#include "time.h"
|
||||
|
||||
namespace Sortix
|
||||
{
|
||||
|
|
212
sortix/time.cpp
212
sortix/time.cpp
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -23,11 +23,21 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <timespec.h>
|
||||
|
||||
#include <sortix/clock.h>
|
||||
#include <sortix/timespec.h>
|
||||
|
||||
#include <sortix/kernel/platform.h>
|
||||
#include <sortix/kernel/syscall.h>
|
||||
#include <sortix/kernel/copy.h>
|
||||
#include <sortix/kernel/interrupt.h>
|
||||
#include <sortix/kernel/syscall.h>
|
||||
#include <sortix/kernel/time.h>
|
||||
|
||||
#include "time.h"
|
||||
#include "process.h"
|
||||
#include "scheduler.h"
|
||||
#include "sound.h"
|
||||
|
@ -36,87 +46,131 @@
|
|||
#include "serialterminal.h"
|
||||
#endif
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#if !defined(PLATFORM_X86_FAMILY)
|
||||
#error No time subsystem is available for this CPU
|
||||
#error Provide a time implementation for this CPU.
|
||||
#endif
|
||||
|
||||
namespace Sortix
|
||||
namespace Sortix {
|
||||
namespace Time {
|
||||
|
||||
struct timespec since_boot;
|
||||
struct timespec since_boot_period;
|
||||
uint16_t since_boot_divisor;
|
||||
|
||||
static uint16_t DivisorOfFrequency(long frequency)
|
||||
{
|
||||
namespace Time
|
||||
// The value we send to the PIT is the value to divide it's input clock
|
||||
// (1193180 Hz) by, to get our required frequency. Note that the divisor
|
||||
// must be small enough to fit into 16 bits.
|
||||
return 1193180 / frequency;
|
||||
}
|
||||
|
||||
static long FrequencyOfDivisor(uint16_t divisor)
|
||||
{
|
||||
return 1193180 / divisor;
|
||||
}
|
||||
|
||||
static long RealFrequencyOfFrequency(long frequency)
|
||||
{
|
||||
return FrequencyOfDivisor(DivisorOfFrequency(frequency));
|
||||
}
|
||||
|
||||
static struct timespec PeriodOfFrequency(long frequency)
|
||||
{
|
||||
long period_ns = 1000000000L / frequency;
|
||||
return timespec_make(0, period_ns);
|
||||
}
|
||||
|
||||
static void RequestIRQ0(uint16_t divisor)
|
||||
{
|
||||
CPU::OutPortB(0x43, 0x36);
|
||||
CPU::OutPortB(0x40, divisor >> 0 & 0xFF);
|
||||
CPU::OutPortB(0x40, divisor >> 8 & 0xFF);
|
||||
}
|
||||
|
||||
static void InitializeTimer(long frequency)
|
||||
{
|
||||
long real_frequence = RealFrequencyOfFrequency(frequency);
|
||||
since_boot_divisor = DivisorOfFrequency(frequency);
|
||||
since_boot = timespec_nul();
|
||||
since_boot_period = PeriodOfFrequency(real_frequence);
|
||||
RequestIRQ0(since_boot_divisor);
|
||||
}
|
||||
|
||||
static void OnIRQ0(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
{
|
||||
since_boot = timespec_add(since_boot, since_boot_period);
|
||||
Scheduler::Switch(regs);
|
||||
|
||||
// TODO: There is a horrible bug that causes Sortix to only receive
|
||||
// one IRQ0 on my laptop, but it works in virtual machines. But
|
||||
// re-requesting an addtional time seems to work. Hacky and ugly.
|
||||
static bool did_ugly_irq0_hack = false;
|
||||
if ( !did_ugly_irq0_hack )
|
||||
{
|
||||
uintmax_t ticks;
|
||||
uintmax_t microsecondssinceboot;
|
||||
|
||||
const uint32_t Frequency = 100; // 100 Hz
|
||||
|
||||
uintmax_t MicrosecondsSinceBoot()
|
||||
{
|
||||
return microsecondssinceboot;
|
||||
}
|
||||
|
||||
extern "C" void RequestIRQ0()
|
||||
{
|
||||
// The value we send to the PIT is the value to divide it's input clock
|
||||
// (1193180 Hz) by, to get our required frequency. Important to note is
|
||||
// that the divisor must be small enough to fit into 16-bits.
|
||||
const uint32_t Divisor = 1193180 / Frequency;
|
||||
|
||||
// Send the command byte.
|
||||
CPU::OutPortB(0x43, 0x36);
|
||||
|
||||
// Divisor has to be sent byte-wise, so split here into upper/lower bytes.
|
||||
uint8_t L = (uint8_t) (Divisor & 0xFF);
|
||||
uint8_t H = (uint8_t) ((Divisor>>8) & 0xFF);
|
||||
|
||||
// Send the frequency divisor.
|
||||
CPU::OutPortB(0x40, L);
|
||||
CPU::OutPortB(0x40, H);
|
||||
}
|
||||
|
||||
bool didUglyIRQ0Hack;
|
||||
|
||||
int SysUptime(uintmax_t* usecssinceboot)
|
||||
{
|
||||
// TODO: Validate that usecssinceboot is a valid user-space pointer.
|
||||
*usecssinceboot = microsecondssinceboot;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
// Initialize our variables.
|
||||
ticks = 0;
|
||||
microsecondssinceboot = 0;
|
||||
|
||||
// First, register our timer callback.
|
||||
Interrupt::RegisterHandler(Interrupt::IRQ0, &OnIRQ0, NULL);
|
||||
|
||||
Syscall::Register(SYSCALL_UPTIME, (void*) SysUptime);
|
||||
|
||||
didUglyIRQ0Hack = false;
|
||||
|
||||
RequestIRQ0();
|
||||
}
|
||||
|
||||
void OnIRQ0(CPU::InterruptRegisters* Regs, void* /*user*/)
|
||||
{
|
||||
#ifdef PLATFORM_SERIAL
|
||||
SerialTerminal::OnTick();
|
||||
#endif
|
||||
|
||||
ticks++;
|
||||
microsecondssinceboot += (1000*1000)/Frequency;
|
||||
|
||||
// Let the scheduler switch to the next task.
|
||||
// TODO: Let the scheduler know how long has passed.
|
||||
Scheduler::Switch(Regs);
|
||||
|
||||
// TODO: There is a horrible bug that causes Sortix to only receive
|
||||
// one IRQ0 on my laptop, but it works in virtual machines. But
|
||||
// re-requesting an addtional time seems to work. Hacky and ugly.
|
||||
if ( !didUglyIRQ0Hack ) { RequestIRQ0(); didUglyIRQ0Hack = true; }
|
||||
}
|
||||
|
||||
// TODO: Implement all the other useful functions regarding time.
|
||||
RequestIRQ0(since_boot_divisor);
|
||||
did_ugly_irq0_hack = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool TryGet(clockid_t clock, struct timespec* time, struct timespec* res)
|
||||
{
|
||||
switch ( clock )
|
||||
{
|
||||
case CLOCK_REALTIME:
|
||||
return errno = ENOTSUP, false;
|
||||
case CLOCK_MONOTONIC:
|
||||
case CLOCK_BOOT:
|
||||
case CLOCK_INIT:
|
||||
// TODO: Is is possible to implement the below as atomic operations?
|
||||
Interrupt::Disable();
|
||||
if ( time )
|
||||
*time = since_boot;
|
||||
if ( res )
|
||||
*res = since_boot_period;
|
||||
Interrupt::Enable();
|
||||
return true;
|
||||
default:
|
||||
return errno = EINVAL, false;
|
||||
}
|
||||
}
|
||||
|
||||
struct timespec Get(clockid_t clock, struct timespec* res)
|
||||
{
|
||||
struct timespec ret;
|
||||
if ( !TryGet(clock, &ret, res) )
|
||||
return timespec_nul();
|
||||
return ret;
|
||||
}
|
||||
|
||||
uintmax_t MicrosecondsOfTimespec(struct timespec time)
|
||||
{
|
||||
uintmax_t seconds = time.tv_sec;
|
||||
uintmax_t nano_seconds = time.tv_nsec;
|
||||
return seconds * 1000000 + nano_seconds / 1000;
|
||||
}
|
||||
|
||||
// TODO: This system call is for compatibility. Provide user-space with better
|
||||
// facilities such as sys_clock_gettime.
|
||||
static int sys_uptime(uintmax_t* usecssinceboot)
|
||||
{
|
||||
struct timespec now;
|
||||
if ( !TryGet(CLOCK_BOOT, &now, NULL) )
|
||||
return -1;
|
||||
uintmax_t ret = MicrosecondsOfTimespec(now);
|
||||
if ( !CopyToUser(usecssinceboot, &ret, sizeof(ret)) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
Interrupt::RegisterHandler(Interrupt::IRQ0, &OnIRQ0, NULL);
|
||||
Syscall::Register(SYSCALL_UPTIME, (void*) sys_uptime);
|
||||
InitializeTimer(100/*Hz*/);
|
||||
}
|
||||
|
||||
} // namespace Time
|
||||
} // namespace Sortix
|
||||
|
|
Loading…
Add table
Reference in a new issue