实现gettimeofday()系统调用和clocksource+timekeeping子模块 (#278)

- 实现gettimeofday()系统调用
- 实现clocksource+timekeeping子模块部分功能
- 实现了timespec转换成日期时间
This commit is contained in:
houmkh
2023-06-17 22:48:15 +08:00
committed by GitHub
parent a55ac7b928
commit 36fd013004
34 changed files with 1988 additions and 78 deletions

View File

@ -17,7 +17,7 @@ export ASFLAGS := --64
LD_LIST := head.o
kernel_subdirs := common driver process debug arch exception mm smp sched syscall ktest libs ipc io
kernel_subdirs := common driver process debug arch exception mm smp sched syscall ktest libs ipc io time

View File

@ -1,18 +1,18 @@
use core::{arch::asm, ptr::read_volatile};
use core::arch::asm;
#[inline]
pub fn local_irq_save(flags: &mut u64) {
pub fn local_irq_save() -> usize {
let x: usize;
unsafe {
asm!("pushfq", "pop rax", "mov rax, {0}", "cli", out(reg)(*flags),);
asm!("pushfq ; pop {} ; cli", out(reg) x, options(nostack));
}
x
}
#[inline]
pub fn local_irq_restore(flags: &u64) {
let x = unsafe { read_volatile(flags) };
// 恢复先前保存的rflags的值x
pub fn local_irq_restore(x: usize) {
unsafe {
asm!("push r15",
"popfq", in("r15")(x));
asm!("push {} ; popfq", in(reg) x, options(nostack));
}
}

View File

@ -79,8 +79,7 @@ impl FpState {
/// @brief 从用户态进入内核时,保存浮点寄存器,并关闭浮点功能
pub fn fp_state_save(pcb: &mut process_control_block) {
// 该过程中不允许中断
let mut rflags: u64 = 0;
local_irq_save(&mut rflags);
let rflags = local_irq_save();
let fp: &mut FpState = if pcb.fp_state == null_mut() {
let f = Box::leak(Box::new(FpState::default()));
@ -112,14 +111,13 @@ pub fn fp_state_save(pcb: &mut process_control_block) {
"mov cr4, rax" */
)
}
local_irq_restore(&rflags);
local_irq_restore(rflags);
}
/// @brief 从内核态返回用户态时,恢复浮点寄存器,并开启浮点功能
pub fn fp_state_restore(pcb: &mut process_control_block) {
// 该过程中不允许中断
let mut rflags: u64 = 0;
local_irq_save(&mut rflags);
let rflags = local_irq_save();
if pcb.fp_state == null_mut() {
panic!("fp_state_restore: fp_state is null. pid={}", pcb.pid);
@ -143,5 +141,5 @@ pub fn fp_state_restore(pcb: &mut process_control_block) {
fp.restore();
fp.clear();
local_irq_restore(&rflags);
local_irq_restore(rflags);
}

View File

@ -48,8 +48,7 @@ impl InterruptArch for X86_64InterruptArch {
unsafe fn save_and_disable_irq() -> IrqFlagsGuard {
compiler_fence(Ordering::SeqCst);
let mut rflags: u64 = 0;
local_irq_save(&mut rflags);
let rflags = local_irq_save() as u64;
let flags = IrqFlags::new(rflags);
let guard = IrqFlagsGuard::new(flags);
compiler_fence(Ordering::SeqCst);
@ -58,7 +57,7 @@ impl InterruptArch for X86_64InterruptArch {
unsafe fn restore_irq(flags: IrqFlags) {
compiler_fence(Ordering::SeqCst);
local_irq_restore(&flags.flags());
local_irq_restore(flags.flags() as usize);
compiler_fence(Ordering::SeqCst);
}
}

View File

@ -67,3 +67,10 @@ extern struct cpu_core_info_t cpu_core_info[MAX_CPU_NUM];
* @return uint32_t 当前cpu核心晶振频率
*/
uint32_t cpu_get_core_crysral_freq();
/**
* @brief 获取处理器的tsc频率单位hz
*
* @return uint64_t
*/
uint64_t cpu_get_tsc_freq();

View File

@ -207,12 +207,13 @@ void HPET_enable()
// kdebug("[HPET0] conf register after modify=%#018lx", ((*(uint64_t *)(HPET_REG_BASE + TIM0_CONF))));
// kdebug("[HPET1] conf register =%#018lx", ((*(uint64_t *)(HPET_REG_BASE + TIM1_CONF))));
kinfo("HPET0 enabled.");
__write8b(HPET_REG_BASE + GEN_CONF, 3); // 置位旧设备中断路由兼容标志位、定时器组使能标志位
io_mfence();
// 注册中断
irq_register(34, &entry, &HPET_handler, 0, &HPET_intr_controller, "HPET0");
io_mfence();
__write8b(HPET_REG_BASE + GEN_CONF, 3); // 置位旧设备中断路由兼容标志位、定时器组使能标志位
kinfo("HPET0 enabled.");
io_mfence();
}
int HPET_init()

View File

@ -1,5 +1,6 @@
use crate::{
arch::interrupt::{cli, sti},
arch::CurrentIrqArch,
exception::InterruptArch,
include::bindings::bindings::{io_in8, io_out8},
syscall::SystemError,
};
@ -33,7 +34,7 @@ impl RtcTime {
///@return int 成功则为0
pub fn get(&mut self) -> Result<i32, SystemError> {
// 为防止中断请求打断该过程,需要先关中断
cli();
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
//0x0B
let status_register_b: u8 = read_cmos(0x0B); // 读取状态寄存器B
let is_24h: bool = if (status_register_b & 0x02) != 0 {
@ -81,7 +82,7 @@ impl RtcTime {
self.hour = ((self.hour & 0x7f) + 12) % 24;
} // 将十二小时制转为24小时
sti();
drop(irq_guard);
return Ok(0);
}

View File

@ -225,15 +225,14 @@ impl Softirq {
}
pub fn raise_softirq(&self, softirq_num: SoftirqNumber) {
let mut flags = 0;
local_irq_save(&mut flags);
let flags = local_irq_save();
let processor_id = smp_get_processor_id() as usize;
cpu_pending(processor_id).insert(VecStatus::from(softirq_num));
compiler_fence(Ordering::SeqCst);
local_irq_restore(&flags);
local_irq_restore(flags);
// kdebug!("raise_softirq exited");
}
pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) {

View File

@ -46,4 +46,5 @@
#include <process/process.h>
#include <sched/sched.h>
#include <smp/smp.h>
#include <time/clocksource.h>
#include <time/sleep.h>

View File

@ -120,3 +120,12 @@ uint32_t cpu_get_core_crysral_freq()
return c;
}
/**
* @brief 获取处理器的tsc频率单位hz
*
* @return uint64_t
*/
uint64_t cpu_get_tsc_freq()
{
return Cpu_tsc_freq;
}

View File

@ -14,7 +14,7 @@ use crate::syscall::SystemError;
/// @brief 保存中断状态到flags中关闭中断并对自旋锁加锁
#[inline]
pub fn spin_lock_irqsave(lock: *mut spinlock_t, flags: &mut u64) {
local_irq_save(flags);
*flags = local_irq_save() as u64;
unsafe {
spin_lock(lock);
}
@ -27,7 +27,7 @@ pub fn spin_unlock_irqrestore(lock: *mut spinlock_t, flags: &u64) {
spin_unlock(lock);
}
// kdebug!("123");
local_irq_restore(flags);
local_irq_restore(*flags as usize);
}
/// 判断一个自旋锁是否已经被加锁
@ -130,14 +130,14 @@ impl RawSpinlock {
/// @brief 保存中断状态到flags中关闭中断并对自旋锁加锁
pub fn lock_irqsave(&self, flags: &mut u64) {
local_irq_save(flags);
*flags = local_irq_save() as u64;
self.lock();
}
/// @brief 恢复rflags以及中断状态并解锁自旋锁
pub fn unlock_irqrestore(&self, flags: &u64) {
self.unlock();
local_irq_restore(flags);
local_irq_restore(*flags as usize);
}
/// @brief 尝试保存中断状态到flags中关闭中断并对自旋锁加锁
@ -145,11 +145,11 @@ impl RawSpinlock {
/// 加锁失败->false
#[inline(always)]
pub fn try_lock_irqsave(&self, flags: &mut u64) -> bool {
local_irq_save(flags);
*flags = local_irq_save() as u64;
if self.try_lock() {
return true;
}
local_irq_restore(flags);
local_irq_restore(*flags as usize);
return false;
}
}

View File

@ -51,7 +51,8 @@ void reload_gdt()
gdtp.size = bsp_gdt_size - 1;
gdtp.gdt_vaddr = (ul)phys_2_virt((ul)&GDT_Table);
asm volatile("lgdt (%0) \n\t" ::"r"(&gdtp) : "memory");
asm volatile("lgdt (%0) \n\t" ::"r"(&gdtp)
: "memory");
}
void reload_idt()
@ -62,7 +63,8 @@ void reload_idt()
// kdebug("gdtvaddr=%#018lx", p.gdt_vaddr);
// kdebug("gdt size=%d", p.size);
asm volatile("lidt (%0) \n\t" ::"r"(&idtp) : "memory");
asm volatile("lidt (%0) \n\t" ::"r"(&idtp)
: "memory");
}
// 初始化系统各模块
@ -124,15 +126,21 @@ void system_initialize()
current_pcb->cpu_id = 0;
current_pcb->preempt_count = 0;
// 先初始化系统调用模块
syscall_init();
io_mfence();
// 再初始化进程模块。顺序不能调转
// sched_init();
rs_timekeeping_init();
io_mfence();
rs_timer_init();
io_mfence();
rs_jiffies_init();
io_mfence();
rs_clocksource_boot_finish();
// 这里必须加内存屏障,否则会出错
io_mfence();
smp_init();

View File

@ -15,13 +15,16 @@ use super::socket::{SOCKET_SET, SOCKET_WAITQUEUE};
/// The network poll function, which will be called by timer.
///
/// The main purpose of this function is to poll all network interfaces.
struct NetWorkPollFunc();
#[derive(Debug)]
struct NetWorkPollFunc;
impl TimerFunction for NetWorkPollFunc {
fn run(&mut self) {
fn run(&mut self) -> Result<(), SystemError> {
poll_ifaces_try_lock(10).ok();
let next_time = next_n_ms_timer_jiffies(10);
let timer = Timer::new(Box::new(NetWorkPollFunc()), next_time);
let timer = Timer::new(Box::new(NetWorkPollFunc), next_time);
timer.activate();
return Ok(());
}
}
@ -29,7 +32,7 @@ pub fn net_init() -> Result<(), SystemError> {
dhcp_query()?;
// Init poll timer function
let next_time = next_n_ms_timer_jiffies(5);
let timer = Timer::new(Box::new(NetWorkPollFunc()), next_time);
let timer = Timer::new(Box::new(NetWorkPollFunc), next_time);
timer.activate();
return Ok(());
}

View File

@ -859,7 +859,8 @@ void process_exit_thread(struct process_control_block *pcb)
int process_release_pcb(struct process_control_block *pcb)
{
// 释放子进程的页表
process_exit_mm(pcb);
// BUG 暂时注释process_exit_mm
// process_exit_mm(pcb);
if ((pcb->flags & PF_KTHREAD)) // 释放内核线程的worker private结构体
free_kthread_struct(pcb);

View File

@ -16,7 +16,10 @@ use crate::{
io::SeekFrom,
kinfo,
net::syscall::SockAddr,
time::TimeSpec,
time::{
syscall::{PosixTimeZone, PosixTimeval, SYS_TIMEZONE},
TimeSpec,
},
};
#[repr(i32)]
@ -354,6 +357,7 @@ pub const SYS_ACCEPT: usize = 40;
pub const SYS_GETSOCKNAME: usize = 41;
pub const SYS_GETPEERNAME: usize = 42;
pub const SYS_GETTIMEOFDAY: usize = 43;
#[derive(Debug)]
pub struct Syscall;
@ -867,6 +871,43 @@ impl Syscall {
SYS_GETPEERNAME => {
Self::getpeername(args[0], args[1] as *mut SockAddr, args[2] as *mut u32)
}
SYS_GETTIMEOFDAY => {
let timeval = args[0] as *mut PosixTimeval;
let timezone_ptr = args[1] as *const PosixTimeZone;
let security_check = || {
if unsafe {
verify_area(timeval as u64, core::mem::size_of::<PosixTimeval>() as u64)
} == false
{
return Err(SystemError::EFAULT);
}
if unsafe {
verify_area(
timezone_ptr as u64,
core::mem::size_of::<PosixTimeZone>() as u64,
)
} == false
{
return Err(SystemError::EFAULT);
}
return Ok(());
};
let r = security_check();
if r.is_err() {
Err(r.unwrap_err())
} else {
let timezone = if !timezone_ptr.is_null() {
&SYS_TIMEZONE
} else {
unsafe { timezone_ptr.as_ref().unwrap() }
};
if !timeval.is_null() {
Self::gettimeofday(timeval, timezone)
} else {
Err(SystemError::EFAULT)
}
}
}
_ => panic!("Unsupported syscall ID: {}", syscall_num),
};

View File

@ -53,3 +53,6 @@
#define SYS_ACCEPT 40 // 接受一个socket连接
#define SYS_GETSOCKNAME 41 // 获取socket的名字
#define SYS_GETPEERNAME 42 // 获取socket的对端名字
#define SYS_GETTIMEOFDAY 43 // 获取当前时间
#define SYS_AHCI_END_REQ 255 // AHCI DMA请求结束end_request的系统调用

8
kernel/src/time/Makefile Normal file
View File

@ -0,0 +1,8 @@
CFLAGS += -I .
all: clocksource.o
clocksource.o: clocksource.c
$(CC) $(CFLAGS) -c clocksource.c -o clocksource.o

View File

@ -0,0 +1,8 @@
#include "clocksource.h"
#include <common/kthread.h>
void run_watchdog_kthread()
{
kdebug("run_watchdog_kthread");
kthread_run(rs_clocksource_watchdog_kthread, NULL, "clocksource_watchdog");
}

View File

@ -0,0 +1,8 @@
#pragma once
#include <common/kthread.h>
extern int rs_clocksource_watchdog_kthread(void *_data);
extern void rs_clocksource_boot_finish();
void run_watchdog_kthread();

View File

@ -0,0 +1,850 @@
use core::{
ffi::c_void,
fmt::Debug,
sync::atomic::{AtomicBool, Ordering},
};
use alloc::{boxed::Box, collections::LinkedList, string::String, sync::Arc, vec::Vec};
use lazy_static::__Deref;
use crate::{
include::bindings::bindings::run_watchdog_kthread, kdebug, kinfo, libs::spinlock::SpinLock,
syscall::SystemError,
};
use super::{
jiffies::clocksource_default_clock,
timer::{clock, Timer, TimerFunction},
NSEC_PER_SEC,
};
lazy_static! {
/// linked list with the registered clocksources
pub static ref CLOCKSOURCE_LIST: SpinLock<LinkedList<Arc<dyn Clocksource>>> =
SpinLock::new(LinkedList::new());
/// 被监视中的时钟源
pub static ref WATCHDOG_LIST: SpinLock<LinkedList<Arc<dyn Clocksource>>> =
SpinLock::new(LinkedList::new());
pub static ref CLOCKSOUCE_WATCHDOG:SpinLock<ClocksouceWatchdog> = SpinLock::new(ClocksouceWatchdog::new());
pub static ref OVERRIDE_NAME: SpinLock<String> = SpinLock::new(String::from(""));
}
/// 正在被使用时钟源
pub static CUR_CLOCKSOURCE: SpinLock<Option<Arc<dyn Clocksource>>> = SpinLock::new(None);
/// 是否完成加载
pub static mut FINISHED_BOOTING: AtomicBool = AtomicBool::new(false);
/// Interval: 0.5sec Threshold: 0.0625s
/// 系统节拍率
pub const HZ: u64 = 1000;
/// watchdog检查间隔
pub const WATCHDOG_INTERVAL: u64 = HZ >> 1;
/// 最大能接受的误差大小
pub const WATCHDOG_THRESHOLD: u32 = NSEC_PER_SEC >> 4;
// 时钟周期数
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct CycleNum(pub u64);
#[allow(dead_code)]
impl CycleNum {
#[inline(always)]
pub fn new(cycle: u64) -> Self {
Self(cycle)
}
#[inline(always)]
pub fn data(&self) -> u64 {
self.0
}
#[inline(always)]
#[allow(dead_code)]
pub fn add(&self, other: CycleNum) -> CycleNum {
CycleNum(self.data() + other.data())
}
#[inline(always)]
pub fn div(&self, other: CycleNum) -> CycleNum {
CycleNum(self.data() - other.data())
}
}
bitflags! {
#[derive(Default)]
pub struct ClocksourceMask: u64 {
}
/// 时钟状态标记
#[derive(Default)]
pub struct ClocksourceFlags: u64 {
/// 表示时钟设备是连续的
const CLOCK_SOURCE_IS_CONTINUOUS = 0x01;
/// 表示该时钟源需要经过watchdog检查
const CLOCK_SOURCE_MUST_VERIFY = 0x02;
/// 表示该时钟源是watchdog
const CLOCK_SOURCE_WATCHDOG = 0x10;
/// 表示该时钟源是高分辨率的
const CLOCK_SOURCE_VALID_FOR_HRES = 0x20;
/// 表示该时钟源误差过大
const CLOCK_SOURCE_UNSTABLE = 0x40;
}
}
impl From<u64> for ClocksourceMask {
fn from(value: u64) -> Self {
if value < 64 {
return Self::from_bits_truncate((1 << value) - 1);
}
return Self::from_bits_truncate(u64::MAX);
}
}
impl ClocksourceMask {
pub fn new(b: u64) -> Self {
Self { bits: b }
}
}
impl ClocksourceFlags {
pub fn new(b: u64) -> Self {
Self { bits: b }
}
}
#[derive(Debug)]
pub struct ClocksouceWatchdog {
/// 监视器
watchdog: Option<Arc<dyn Clocksource>>,
/// 检查器是否在工作的标志
is_running: bool,
/// 上一次检查的时刻
last_check: CycleNum,
/// 定时监视器的过期时间
timer_expires: u64,
}
impl ClocksouceWatchdog {
pub fn new() -> Self {
Self {
watchdog: None,
is_running: false,
last_check: CycleNum(0),
timer_expires: 0,
}
}
/// 获取watchdog
fn get_watchdog(&mut self) -> &mut Option<Arc<dyn Clocksource>> {
&mut self.watchdog
}
/// 启用检查器
pub fn clocksource_start_watchdog(&mut self) {
// 如果watchdog未被设置或者已经启用了就退出
let watchdog_list = &WATCHDOG_LIST.lock();
if self.is_running || self.watchdog.is_none() || watchdog_list.is_empty() {
return;
}
// 生成一个定时器
let wd_timer_func: Box<WatchdogTimerFunc> = Box::new(WatchdogTimerFunc {});
self.timer_expires += clock() + WATCHDOG_INTERVAL;
self.last_check = self.watchdog.as_ref().unwrap().clone().read();
let wd_timer = Timer::new(wd_timer_func, self.timer_expires);
wd_timer.activate();
self.is_running = true;
}
/// 停止检查器
/// list_len WATCHDOG_LIST长度
pub fn clocksource_stop_watchdog(&mut self, list_len: usize) {
if !self.is_running || (self.watchdog.is_some() && list_len != 0) {
return;
}
// TODO 当实现了周期性的定时器后 需要将监视用的定时器删除
self.is_running = false;
}
}
/// 定时检查器
#[derive(Debug)]
pub struct WatchdogTimerFunc;
impl TimerFunction for WatchdogTimerFunc {
fn run(&mut self) -> Result<(), SystemError> {
return clocksource_watchdog();
}
}
/// 时钟源的特性
pub trait Clocksource: Send + Sync + Debug {
// TODO 返回值类型可能需要改变
/// returns a cycle value, passes clocksource as argument
fn read(&self) -> CycleNum;
/// optional function to enable the clocksource
fn enable(&self) -> Result<i32, SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
/// optional function to disable the clocksource
fn disable(&self) -> Result<(), SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
/// vsyscall based read
fn vread(&self) -> Result<CycleNum, SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
/// suspend function for the clocksource, if necessary
fn suspend(&self) -> Result<(), SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
/// resume function for the clocksource, if necessary
fn resume(&self) -> Result<(), SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
// 获取时钟源数据
fn clocksource_data(&self) -> ClocksourceData;
fn update_clocksource_data(&self, _data: ClocksourceData) -> Result<(), SystemError> {
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
}
// 获取时钟源
fn clocksource(&self) -> Arc<dyn Clocksource>;
}
/// # 实现整数log2的运算
///
/// ## 参数
///
/// * `x` - 要计算的数字
///
/// ## 返回值
///
/// * `u32` - 返回\log_2(x)的值
fn log2(x: u32) -> u32 {
let mut result = 0;
let mut x = x;
if x >= 1 << 16 {
x >>= 16;
result |= 16;
}
if x >= 1 << 8 {
x >>= 8;
result |= 8;
}
if x >= 1 << 4 {
x >>= 4;
result |= 4;
}
if x >= 1 << 2 {
x >>= 2;
result |= 2;
}
if x >= 1 << 1 {
result |= 1;
}
result
}
impl dyn Clocksource {
/// # 计算时钟源能记录的最大时间跨度
pub fn clocksource_max_deferment(&self) -> u64 {
let cs_data_guard = self.clocksource_data();
let max_nsecs: u64;
let mut max_cycles: u64;
max_cycles = (1 << (63 - (log2(cs_data_guard.mult) + 1))) as u64;
max_cycles = max_cycles.min(cs_data_guard.mask.bits);
max_nsecs = clocksource_cyc2ns(
CycleNum(max_cycles),
cs_data_guard.mult,
cs_data_guard.shift,
);
return max_nsecs - (max_nsecs >> 5);
}
/// # 注册时钟源
///
/// ## 返回值
///
/// * `Ok(0)` - 时钟源注册成功。
/// * `Err(SystemError)` - 时钟源注册失败。
pub fn register(&self) -> Result<i32, SystemError> {
let ns = self.clocksource_max_deferment();
let mut cs_data = self.clocksource_data();
cs_data.max_idle_ns = ns as u32;
self.update_clocksource_data(cs_data)?;
// 将时钟源加入到时钟源队列中
self.clocksource_enqueue();
// 将时钟源加入到监视队列中
self.clocksource_enqueue_watchdog()
.expect("register: failed to enqueue watchdog list");
// 选择一个最好的时钟源
clocksource_select();
kdebug!("clocksource_register successfully");
return Ok(0);
}
/// # 将时钟源插入时钟源队列
pub fn clocksource_enqueue(&self) {
// 根据rating由大到小排序
let cs_data = self.clocksource_data();
let list_guard = &mut CLOCKSOURCE_LIST.lock();
let mut spilt_pos: usize = 0;
for (pos, ele) in list_guard.iter().enumerate() {
if ele.clocksource_data().rating < cs_data.rating {
spilt_pos = pos;
break;
}
}
let mut temp_list = list_guard.split_off(spilt_pos);
let cs = self.clocksource();
list_guard.push_back(cs);
list_guard.append(&mut temp_list);
// kdebug!(
// "CLOCKSOURCE_LIST len = {:?},clocksource_enqueue sccessfully",
// list_guard.len()
// );
}
/// # 将时间源插入监控队列
///
/// ## 返回值
///
/// * `Ok(0)` - 时间源插入监控队列成功
/// * `Err(SystemError)` - 时间源插入监控队列失败
pub fn clocksource_enqueue_watchdog(&self) -> Result<i32, SystemError> {
// BUG 可能需要lock irq
let mut cs_data = self.clocksource_data();
let cs = self.clocksource();
if cs_data
.flags
.contains(ClocksourceFlags::CLOCK_SOURCE_MUST_VERIFY)
{
let mut list_guard = WATCHDOG_LIST.lock_irqsave();
// cs是被监视的
cs_data
.flags
.remove(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG);
cs.update_clocksource_data(cs_data)?;
list_guard.push_back(cs);
} else {
// cs是监视器
if cs_data
.flags
.contains(ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS)
{
// 如果时钟设备是连续的
cs_data
.flags
.insert(ClocksourceFlags::CLOCK_SOURCE_VALID_FOR_HRES);
cs.update_clocksource_data(cs_data.clone())?;
}
// 将时钟源加入到监控队列中
let mut list_guard = WATCHDOG_LIST.lock();
list_guard.push_back(cs.clone());
drop(list_guard);
// 对比当前注册的时间源的精度和监视器的精度
let cs_watchdog = &mut CLOCKSOUCE_WATCHDOG.lock();
if cs_watchdog.watchdog.is_none()
|| cs_data.rating
> cs_watchdog
.watchdog
.clone()
.unwrap()
.clocksource_data()
.rating
{
// 当前注册的时间源的精度更高或者没有监视器,替换监视器
cs_watchdog.watchdog.replace(cs);
clocksource_reset_watchdog();
}
// 启动监视器
cs_watchdog.clocksource_start_watchdog();
}
return Ok(0);
}
/// # 将时钟源标记为unstable
///
/// ## 参数
/// * `delta` - 时钟源误差
pub fn set_unstable(&self, delta: i64) -> Result<i32, SystemError> {
let mut cs_data = self.clocksource_data();
// 打印出unstable的时钟源信息
kdebug!(
"clocksource :{:?} is unstable, its delta is {:?}",
cs_data.name,
delta
);
cs_data.flags.remove(
ClocksourceFlags::CLOCK_SOURCE_VALID_FOR_HRES | ClocksourceFlags::CLOCK_SOURCE_WATCHDOG,
);
cs_data
.flags
.insert(ClocksourceFlags::CLOCK_SOURCE_UNSTABLE);
self.update_clocksource_data(cs_data)?;
// 启动watchdog线程 进行后续处理
if unsafe { FINISHED_BOOTING.load(Ordering::Relaxed) } {
// TODO 在实现了工作队列后将启动线程换成schedule work
unsafe { run_watchdog_kthread() }
}
return Ok(0);
}
/// # 将时间源从监视链表中弹出
fn clocksource_dequeue_watchdog(&self) {
let data = self.clocksource_data();
let mut locked_watchdog = CLOCKSOUCE_WATCHDOG.lock();
let watchdog = locked_watchdog
.get_watchdog()
.clone()
.unwrap()
.clocksource_data();
let mut list = WATCHDOG_LIST.lock();
let mut size = list.len();
let mut del_pos: usize = size;
for (pos, ele) in list.iter().enumerate() {
let ele_data = ele.clocksource_data();
if ele_data.name.eq(&data.name) && ele_data.rating.eq(&data.rating) {
// 记录要删除的时钟源在监视链表中的下标
del_pos = pos;
}
}
if data
.flags
.contains(ClocksourceFlags::CLOCK_SOURCE_MUST_VERIFY)
{
// 如果时钟源是需要被检查的,直接删除时钟源
if del_pos != size {
let mut temp_list = list.split_off(del_pos);
temp_list.pop_front();
list.append(&mut temp_list);
}
} else if watchdog.name.eq(&data.name) && watchdog.rating.eq(&data.rating) {
// 如果要删除的时钟源是监视器,则需要找到一个新的监视器
// TODO 重新设置时钟源
// 将链表解锁防止reset中双重加锁 并释放保存的旧的watchdog的数据
// 代替了clocksource_reset_watchdog()的功能将所有时钟源的watchdog标记清除
for ele in list.iter() {
ele.clocksource_data()
.flags
.remove(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG);
}
// 遍历所有时间源,寻找新的监视器
let mut clocksource_list = CLOCKSOURCE_LIST.lock();
let mut replace_pos: usize = clocksource_list.len();
for (pos, ele) in clocksource_list.iter().enumerate() {
let ele_data = ele.clocksource_data();
if ele_data.name.eq(&data.name) && ele_data.rating.eq(&data.rating)
|| ele_data
.flags
.contains(ClocksourceFlags::CLOCK_SOURCE_MUST_VERIFY)
{
// 当前时钟源是要被删除的时钟源或没被检查过的时钟源
// 不适合成为监视器
continue;
}
let watchdog = locked_watchdog.get_watchdog().clone();
if watchdog.is_none()
|| ele_data.rating > watchdog.unwrap().clocksource_data().rating
{
// 如果watchdog不存在或者当前时钟源的精度高于watchdog的精度则记录当前时钟源的下标
replace_pos = pos;
}
}
// 使用刚刚找到的更好的时钟源替换旧的watchdog
if replace_pos < clocksource_list.len() {
let mut temp_list = clocksource_list.split_off(replace_pos);
let new_wd = temp_list.front().unwrap().clone();
clocksource_list.append(&mut temp_list);
// 替换watchdog
locked_watchdog.watchdog.replace(new_wd);
// drop(locked_watchdog);
}
// 删除时钟源
if del_pos != size {
let mut temp_list = list.split_off(del_pos);
temp_list.pop_front();
list.append(&mut temp_list);
}
}
// 清除watchdog标记
let mut cs_data = self.clocksource_data();
cs_data
.flags
.remove(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG);
self.update_clocksource_data(cs_data)
.expect("clocksource_dequeue_watchdog: failed to update clocksource data");
size = list.len();
// 停止当前的watchdog
locked_watchdog.clocksource_stop_watchdog(size - 1);
}
/// # 将时钟源从时钟源链表中弹出
fn clocksource_dequeue(&self) {
let mut list = CLOCKSOURCE_LIST.lock();
let data = self.clocksource_data();
let mut del_pos: usize = list.len();
for (pos, ele) in list.iter().enumerate() {
let ele_data = ele.clocksource_data();
if ele_data.name.eq(&data.name) && ele_data.rating.eq(&data.rating) {
// 记录时钟源在链表中的下标
del_pos = pos;
}
}
// 删除时钟源
if del_pos != list.len() {
let mut temp_list = list.split_off(del_pos);
temp_list.pop_front();
list.append(&mut temp_list);
}
}
/// # 注销时钟源
#[allow(dead_code)]
pub fn unregister(&self) {
// 将时钟源从监视链表中弹出
self.clocksource_dequeue_watchdog();
// 将时钟源从时钟源链表中弹出
self.clocksource_dequeue();
// 检查是否有更好的时钟源
clocksource_select();
}
/// # 修改时钟源的精度
///
/// ## 参数
///
/// * `rating` - 指定的时钟精度
fn clocksource_change_rating(&self, rating: i32) {
// 将时钟源从链表中弹出
self.clocksource_dequeue();
let mut data = self.clocksource_data();
// 修改时钟源的精度
data.set_rating(rating);
self.update_clocksource_data(data)
.expect("clocksource_change_rating:updata clocksource failed");
// 插入时钟源到时钟源链表中
self.clocksource_enqueue();
// 检查是否有更好的时钟源
clocksource_select();
}
}
#[derive(Debug, Clone)]
pub struct ClocksourceData {
/// 时钟源名字
pub name: String,
/// 时钟精度
pub rating: i32,
pub mask: ClocksourceMask,
pub mult: u32,
pub shift: u32,
pub max_idle_ns: u32,
pub flags: ClocksourceFlags,
pub watchdog_last: CycleNum,
}
impl ClocksourceData {
#[allow(dead_code)]
pub fn new(
name: String,
rating: i32,
mask: ClocksourceMask,
mult: u32,
shift: u32,
max_idle_ns: u32,
flags: ClocksourceFlags,
) -> Self {
let csd = ClocksourceData {
name,
rating,
mask,
mult,
shift,
max_idle_ns,
flags,
watchdog_last: CycleNum(0),
};
return csd;
}
pub fn set_name(&mut self, name: String) {
self.name = name;
}
pub fn set_rating(&mut self, rating: i32) {
self.rating = rating;
}
pub fn set_mask(&mut self, mask: ClocksourceMask) {
self.mask = mask;
}
pub fn set_mult(&mut self, mult: u32) {
self.mult = mult;
}
pub fn set_shift(&mut self, shift: u32) {
self.shift = shift;
}
pub fn set_max_idle_ns(&mut self, max_idle_ns: u32) {
self.max_idle_ns = max_idle_ns;
}
pub fn set_flags(&mut self, flags: ClocksourceFlags) {
self.flags = flags;
}
#[allow(dead_code)]
pub fn remove_flags(&mut self, flags: ClocksourceFlags) {
self.flags.remove(flags)
}
#[allow(dead_code)]
pub fn insert_flags(&mut self, flags: ClocksourceFlags) {
self.flags.insert(flags)
}
}
/// converts clocksource cycles to nanoseconds
///
pub fn clocksource_cyc2ns(cycles: CycleNum, mult: u32, shift: u32) -> u64 {
return (cycles.data() * mult as u64) >> shift;
}
/// # 重启所有的时间源
#[allow(dead_code)]
pub fn clocksource_resume() {
let list = CLOCKSOURCE_LIST.lock();
for ele in list.iter() {
let data = ele.clocksource_data();
match ele.resume() {
Ok(_) => continue,
Err(_) => {
kdebug!("clocksource {:?} resume failed", data.name)
}
}
}
clocksource_resume_watchdog();
}
/// # 暂停所有的时间源
#[allow(dead_code)]
pub fn clocksource_suspend() {
let list = CLOCKSOURCE_LIST.lock();
for ele in list.iter() {
let data = ele.clocksource_data();
match ele.suspend() {
Ok(_) => continue,
Err(_) => {
kdebug!("clocksource {:?} suspend failed", data.name)
}
}
}
}
/// # 根据watchdog的精度来检查被监视的时钟源的误差
///
/// ## 返回值
///
/// * `Ok()` - 检查完成
/// * `Err(SystemError)` - 错误码
pub fn clocksource_watchdog() -> Result<(), SystemError> {
let mut cs_watchdog = CLOCKSOUCE_WATCHDOG.lock();
// watchdog没有在运行的话直接退出
if !cs_watchdog.is_running || cs_watchdog.watchdog.is_none() {
return Ok(());
}
let cur_watchdog = cs_watchdog.watchdog.as_ref().unwrap().clone();
let cur_wd_data = cur_watchdog.as_ref().clocksource_data();
let cur_wd_nowclock = cur_watchdog.as_ref().read().data();
let wd_last = cs_watchdog.last_check.data();
let wd_dev_nsec = clocksource_cyc2ns(
CycleNum((cur_wd_nowclock - wd_last) & cur_wd_data.mask.bits),
cur_wd_data.mult,
cur_wd_data.shift,
);
cs_watchdog.last_check = CycleNum(cur_wd_nowclock);
drop(cs_watchdog);
let watchdog_list = &mut WATCHDOG_LIST.lock();
for cs in watchdog_list.iter() {
let mut cs_data = cs.clocksource_data();
// 判断时钟源是否已经被标记为不稳定
if cs_data
.flags
.contains(ClocksourceFlags::CLOCK_SOURCE_UNSTABLE)
{
// 启动watchdog_kthread
unsafe { run_watchdog_kthread() };
continue;
}
// 读取时钟源现在的时间
let cs_now_clock = cs.read();
// 如果时钟源没有被监视,则开始监视他
if !cs_data
.flags
.contains(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG)
{
cs_data
.flags
.insert(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG);
// 记录此次检查的时刻
cs_data.watchdog_last = cs_now_clock;
cs.update_clocksource_data(cs_data.clone())?;
continue;
}
// 计算时钟源的误差
let cs_dev_nsec = clocksource_cyc2ns(
CycleNum(cs_now_clock.div(cs_data.watchdog_last).data() & cs_data.mask.bits),
cs_data.mult,
cs_data.shift,
);
// 记录此次检查的时刻
cs_data.watchdog_last = cs_now_clock;
cs.update_clocksource_data(cs_data.clone())?;
if cs_dev_nsec.abs_diff(wd_dev_nsec) > WATCHDOG_THRESHOLD.into() {
// 误差过大标记为unstable
cs.set_unstable((cs_dev_nsec - wd_dev_nsec).try_into().unwrap())?;
continue;
}
// 判断是否要切换为高精度模式
if !cs_data
.flags
.contains(ClocksourceFlags::CLOCK_SOURCE_VALID_FOR_HRES)
&& cs_data
.flags
.contains(ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS)
&& cur_wd_data
.flags
.contains(ClocksourceFlags::CLOCK_SOURCE_IS_CONTINUOUS)
{
cs_data
.flags
.insert(ClocksourceFlags::CLOCK_SOURCE_VALID_FOR_HRES);
cs.update_clocksource_data(cs_data)?;
// TODO 通知tick机制 切换为高精度模式
}
let mut cs_watchdog = CLOCKSOUCE_WATCHDOG.lock();
// FIXME 需要保证所有cpu时间统一
cs_watchdog.timer_expires += WATCHDOG_INTERVAL;
//创建定时器执行watchdog
let watchdog_func = Box::new(WatchdogTimerFunc {});
let watchdog_timer = Timer::new(watchdog_func, cs_watchdog.timer_expires);
watchdog_timer.activate();
}
return Ok(());
}
/// # watchdog线程的逻辑执行unstable的后续操作
pub fn clocksource_watchdog_kthread() {
let mut del_vec: Vec<usize> = Vec::new();
let mut del_clocks: Vec<Arc<dyn Clocksource>> = Vec::new();
let wd_list = &mut WATCHDOG_LIST.lock();
// 将不稳定的时钟源弹出监视链表
for (pos, ele) in wd_list.iter().enumerate() {
let data = ele.clocksource_data();
if data.flags.contains(ClocksourceFlags::CLOCK_SOURCE_UNSTABLE) {
del_vec.push(pos);
del_clocks.push(ele.clone());
}
}
for pos in del_vec {
let mut temp_list = wd_list.split_off(pos);
temp_list.pop_front();
wd_list.append(&mut temp_list);
}
// 检查是否需要停止watchdog
CLOCKSOUCE_WATCHDOG
.lock()
.clocksource_stop_watchdog(wd_list.len());
// 将不稳定的时钟源精度都设置为最低
for clock in del_clocks.iter() {
clock.clocksource_change_rating(0);
}
}
/// # 清空所有时钟源的watchdog标志位
pub fn clocksource_reset_watchdog() {
let list_guard = WATCHDOG_LIST.lock();
for ele in list_guard.iter() {
ele.clocksource_data()
.flags
.remove(ClocksourceFlags::CLOCK_SOURCE_WATCHDOG);
}
}
/// # 重启检查器
pub fn clocksource_resume_watchdog() {
clocksource_reset_watchdog();
}
/// # 根据精度选择最优的时钟源,或者接受用户指定的时间源
pub fn clocksource_select() {
let list_guard = CLOCKSOURCE_LIST.lock();
if unsafe { FINISHED_BOOTING.load(Ordering::Relaxed) } || list_guard.is_empty() {
return;
}
let mut best = list_guard.front().unwrap().clone();
let override_name = OVERRIDE_NAME.lock();
// 判断是否有用户空间指定的时间源
for ele in list_guard.iter() {
if ele.clocksource_data().name.eq(override_name.deref()) {
// TODO 判断是否是高精度模式
// 暂时不支持高精度模式
// 如果是高精度模式,但是时钟源不支持高精度模式的话,就要退出循环
best = ele.clone();
break;
}
}
// 对比当前的时钟源和记录到最好的时钟源的精度
if CUR_CLOCKSOURCE.lock().as_ref().is_some() {
// 当前时钟源不为空
let cur_clocksource = CUR_CLOCKSOURCE.lock().as_ref().unwrap().clone();
let best_name = &best.clocksource_data().name;
if cur_clocksource.clocksource_data().name.ne(best_name) {
kinfo!("Switching to the clocksource {:?}\n", best_name);
drop(cur_clocksource);
CUR_CLOCKSOURCE.lock().replace(best);
// TODO 通知timerkeeping 切换了时间源
}
} else {
// 当前时钟源为空
CUR_CLOCKSOURCE.lock().replace(best);
}
kdebug!(" clocksource_select finish");
}
/// # clocksource模块加载完成
pub fn clocksource_boot_finish() {
let mut cur_clocksource = CUR_CLOCKSOURCE.lock();
cur_clocksource.replace(clocksource_default_clock());
unsafe { FINISHED_BOOTING.store(true, Ordering::Relaxed) };
// 清除不稳定的时钟源
clocksource_watchdog_kthread();
kdebug!("clocksource_boot_finish");
}
// ======== 以下为对C的接口 ========
/// # 完成对clocksource模块的加载
#[no_mangle]
pub extern "C" fn rs_clocksource_boot_finish() {
clocksource_boot_finish();
}
/// # 启动watchdog线程的辅助函数
#[no_mangle]
pub extern "C" fn rs_clocksource_watchdog_kthread(_data: c_void) -> i32 {
clocksource_watchdog_kthread();
return 0;
}

View File

@ -0,0 +1,3 @@
#pragma once
extern void rs_jiffies_init();

100
kernel/src/time/jiffies.rs Normal file
View File

@ -0,0 +1,100 @@
use alloc::{
string::ToString,
sync::{Arc, Weak},
};
use crate::{kdebug, libs::spinlock::SpinLock, syscall::SystemError};
use super::{
clocksource::{Clocksource, ClocksourceData, ClocksourceFlags, ClocksourceMask, CycleNum, HZ},
timer::clock,
NSEC_PER_SEC,
};
lazy_static! {
pub static ref DEFAULT_CLOCK: Arc<ClocksourceJiffies> = ClocksourceJiffies::new();
}
pub const CLOCK_TICK_RATE: u32 = HZ as u32 * 100000;
pub const JIFFIES_SHIFT: u32 = 8;
pub const LATCH: u32 = ((CLOCK_TICK_RATE + (HZ as u32) / 2) / HZ as u32) as u32;
pub const ACTHZ: u32 = sh_div(CLOCK_TICK_RATE, LATCH, 8);
pub const NSEC_PER_JIFFY: u32 = ((NSEC_PER_SEC << 8) / ACTHZ) as u32;
pub const fn sh_div(nom: u32, den: u32, lsh: u32) -> u32 {
(((nom) / (den)) << (lsh)) + ((((nom) % (den)) << (lsh)) + (den) / 2) / (den)
}
#[derive(Debug)]
pub struct ClocksourceJiffies(SpinLock<InnerJiffies>);
#[derive(Debug)]
pub struct InnerJiffies {
data: ClocksourceData,
self_ref: Weak<ClocksourceJiffies>,
}
impl Clocksource for ClocksourceJiffies {
fn read(&self) -> CycleNum {
CycleNum(clock())
}
fn clocksource_data(&self) -> ClocksourceData {
let inner = self.0.lock();
return inner.data.clone();
}
fn clocksource(&self) -> Arc<dyn Clocksource> {
self.0.lock().self_ref.upgrade().unwrap()
}
fn update_clocksource_data(&self, _data: ClocksourceData) -> Result<(), SystemError> {
let d = &mut self.0.lock().data;
d.set_flags(_data.flags);
d.set_mask(_data.mask);
d.set_max_idle_ns(_data.max_idle_ns);
d.set_mult(_data.mult);
d.set_name(_data.name);
d.set_rating(_data.rating);
d.set_shift(_data.shift);
return Ok(());
}
fn enable(&self) -> Result<i32, SystemError> {
return Ok(0);
}
}
impl ClocksourceJiffies {
pub fn new() -> Arc<Self> {
let data = ClocksourceData {
name: "jiffies".to_string(),
rating: 1,
mask: ClocksourceMask::new(0xffffffff),
mult: NSEC_PER_JIFFY << JIFFIES_SHIFT,
shift: JIFFIES_SHIFT,
max_idle_ns: Default::default(),
flags: ClocksourceFlags::new(0),
watchdog_last: CycleNum(0),
};
let jieffies = Arc::new(ClocksourceJiffies(SpinLock::new(InnerJiffies {
data,
self_ref: Default::default(),
})));
jieffies.0.lock().self_ref = Arc::downgrade(&jieffies);
return jieffies;
}
}
pub fn clocksource_default_clock() -> Arc<ClocksourceJiffies> {
DEFAULT_CLOCK.clone()
}
pub fn jiffies_init() {
//注册jiffies
let jiffies = clocksource_default_clock() as Arc<dyn Clocksource>;
match jiffies.register() {
Ok(_) => kdebug!("jiffies_init sccessfully"),
Err(_) => kdebug!("jiffies_init failed, no default clock running"),
}
}
#[no_mangle]
pub extern "C" fn rs_jiffies_init() {
jiffies_init();
}

View File

@ -2,11 +2,14 @@ use core::{fmt, ops};
use self::timekeep::ktime_get_real_ns;
pub mod clocksource;
pub mod jiffies;
pub mod sleep;
pub mod syscall;
pub mod timeconv;
pub mod timekeep;
pub mod timekeeping;
pub mod timer;
/* Time structures. (Partitially taken from smoltcp)
The `time` module contains structures used to represent both
@ -18,6 +21,20 @@ absolute and relative time.
[Instant]: struct.Instant.html
[Duration]: struct.Duration.html
*/
#[allow(dead_code)]
pub const MSEC_PER_SEC: u32 = 1000;
#[allow(dead_code)]
pub const USEC_PER_MSEC: u32 = 1000;
#[allow(dead_code)]
pub const NSEC_PER_USEC: u32 = 1000;
#[allow(dead_code)]
pub const NSEC_PER_MSEC: u32 = 1000000;
#[allow(dead_code)]
pub const USEC_PER_SEC: u32 = 1000000;
#[allow(dead_code)]
pub const NSEC_PER_SEC: u32 = 1000000000;
#[allow(dead_code)]
pub const FSEC_PER_SEC: u64 = 1000000000000000;
/// 表示时间的结构体符合POSIX标准。
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]

View File

@ -1,10 +1,42 @@
use core::ptr::null_mut;
use core::{
ffi::{c_int, c_longlong},
ptr::null_mut,
};
use crate::{
kdebug,
syscall::{Syscall, SystemError},
time::{sleep::nanosleep, TimeSpec},
};
use super::timekeeping::do_gettimeofday;
pub type PosixTimeT = c_longlong;
pub type PosixSusecondsT = c_int;
#[repr(C)]
#[derive(Default, Debug)]
pub struct PosixTimeval {
pub tv_sec: PosixTimeT,
pub tv_usec: PosixSusecondsT,
}
#[repr(C)]
#[derive(Default, Debug)]
/// 当前时区信息
pub struct PosixTimeZone {
/// 格林尼治相对于当前时区相差的分钟数
pub tz_minuteswest: c_int,
/// DST矫正时差
pub tz_dsttime: c_int,
}
/// 系统时区 暂时写定为东八区
pub const SYS_TIMEZONE: PosixTimeZone = PosixTimeZone {
tz_minuteswest: -480,
tz_dsttime: 0,
};
impl Syscall {
/// @brief 休眠指定时间单位纳秒提供给C的接口
///
@ -44,4 +76,22 @@ impl Syscall {
pub fn clock() -> Result<usize, SystemError> {
return Ok(super::timer::clock() as usize);
}
pub fn gettimeofday(
tv: *mut PosixTimeval,
_timezone: &PosixTimeZone,
) -> Result<usize, SystemError> {
// TODO; 处理时区信息
kdebug!("enter sys_do_gettimeofday");
if tv == null_mut() {
return Err(SystemError::EFAULT);
}
let posix_time = do_gettimeofday();
unsafe {
(*tv).tv_sec = posix_time.tv_sec;
(*tv).tv_usec = posix_time.tv_usec;
}
kdebug!("exit sys_do_gettimeofday");
return Ok(0);
}
}

143
kernel/src/time/timeconv.rs Normal file
View File

@ -0,0 +1,143 @@
use super::syscall::PosixTimeT;
/// 一小时所包含的秒数
const SECS_PER_HOUR: i64 = 60 * 60;
/// 一天所包含的秒数
const SECS_PER_DAY: i64 = SECS_PER_HOUR * 24;
/// 每年中每个月最后一天所对应天数
const MON_OF_YDAY: [[i64; 13]; 2] = [
// 普通年
[0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365],
// 闰年
[0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366],
];
#[derive(Debug)]
#[allow(dead_code)]
pub struct CalendarTime {
tm_sec: i32,
tm_min: i32,
tm_hour: i32,
tm_mday: i32,
tm_mon: i32,
tm_wday: i32,
tm_yday: i32,
tm_year: i32,
}
impl CalendarTime {
pub fn new() -> Self {
CalendarTime {
tm_year: Default::default(),
tm_sec: Default::default(),
tm_min: Default::default(),
tm_hour: Default::default(),
tm_mday: Default::default(),
tm_mon: Default::default(),
tm_wday: Default::default(),
tm_yday: Default::default(),
}
}
}
/// # 判断是否是闰年
///
/// ## 参数
///
/// * 'year' - 年份
fn is_leap(year: u32) -> bool {
let mut flag = false;
if (year % 4 == 0 && year % 100 != 0) || year % 400 == 0 {
flag = true;
}
return flag;
}
/// # 计算除法
///
/// # 参数
///
/// * 'left' - 被除数
/// * 'right' - 除数
fn math_div(left: u32, right: u32) -> u32 {
return left / right;
}
/// # 计算两年之间的闰年数目
///
/// ## 参数
///
/// * 'y1' - 起始年份
/// * 'y2' - 结束年份
fn leaps_between(y1: u32, y2: u32) -> u32 {
// 算出y1之前的闰年数量
let y1_leaps = math_div(y1 - 1, 4) - math_div(y1 - 1, 100) + math_div(y1 - 1, 400);
// 算出y2之前的闰年数量
let y2_leaps = math_div(y2 - 1, 4) - math_div(y2 - 1, 100) + math_div(y2 - 1, 400);
y2_leaps - y1_leaps
}
/// # 将秒数转换成日期
///
/// ## 参数
///
/// * 'totalsecs' - 1970年1月1日 00:00:00 UTC到现在的秒数
/// * 'offset' - 指定的秒数对应的时间段(含)的偏移量(以秒为单位)
#[allow(dead_code)]
pub fn time_to_calendar(totalsecs: PosixTimeT, offset: i32) -> CalendarTime {
let mut result = CalendarTime::new();
// 计算对应的天数
let mut days = totalsecs / SECS_PER_DAY;
// 一天中剩余的秒数
let mut rem = totalsecs % SECS_PER_DAY;
// 加入偏移量
rem += offset as i64;
while rem < 0 {
rem += SECS_PER_DAY;
days -= 1;
}
while rem >= SECS_PER_DAY {
rem -= SECS_PER_DAY;
days += 1;
}
// 计算对应的小时数
result.tm_hour = (rem / SECS_PER_HOUR) as i32;
rem = rem % SECS_PER_HOUR;
// 计算对应的分钟数
result.tm_min = (rem / 60) as i32;
rem = rem % 60;
// 秒数
result.tm_sec = rem as i32;
// totalsec是从1970年1月1日 00:00:00 UTC到现在的秒数
// 当时是星期四
result.tm_wday = ((4 + days) % 7) as i32;
let mut year = 1970;
while days < 0 || (is_leap(year) && days >= 366) || (!is_leap(year) && days >= 365) {
// 假设每一年都是365天计算出大概的年份
let guess_year = year + math_div(days.try_into().unwrap(), 365);
// 将已经计算过的天数去掉
days -= ((guess_year - year) * 365 + leaps_between(year, guess_year)) as i64;
year = guess_year;
}
result.tm_year = (year - 1900) as i32;
result.tm_yday = days as i32;
let mut il = 0;
if is_leap(year) {
il = 1
};
let mut mon = 0;
for i in MON_OF_YDAY[il] {
if days < i {
break;
}
mon += 1;
}
days -= MON_OF_YDAY[il][mon - 1];
result.tm_mon = (mon - 1) as i32;
result.tm_mday = (days + 1) as i32;
result
}

View File

@ -0,0 +1,3 @@
#pragma once
extern void rs_timekeeping_init();

View File

@ -0,0 +1,312 @@
use alloc::sync::Arc;
use core::sync::atomic::{compiler_fence, AtomicBool, AtomicI64, Ordering};
use x86_64::align_up;
use crate::{
arch::CurrentIrqArch,
exception::InterruptArch,
kdebug,
libs::rwlock::RwLock,
time::{jiffies::clocksource_default_clock, timekeep::ktime_get_real_ns, TimeSpec},
};
use super::{
clocksource::{clocksource_cyc2ns, Clocksource, CycleNum, HZ},
syscall::PosixTimeval,
NSEC_PER_SEC, USEC_PER_SEC,
};
/// NTP周期频率
pub const NTP_INTERVAL_FREQ: u64 = HZ;
/// NTP周期长度
pub const NTP_INTERVAL_LENGTH: u64 = NSEC_PER_SEC as u64 / NTP_INTERVAL_FREQ;
/// NTP转换比例
pub const NTP_SCALE_SHIFT: u32 = 32;
/// timekeeping休眠标志false为未休眠
pub static TIMEKEEPING_SUSPENDED: AtomicBool = AtomicBool::new(false);
/// 已经递增的微秒数
static __ADDED_USEC: AtomicI64 = AtomicI64::new(0);
/// 已经递增的秒数
static __ADDED_SEC: AtomicI64 = AtomicI64::new(0);
/// timekeeper全局变量用于管理timekeeper模块
static mut __TIMEKEEPER: Option<Timekeeper> = None;
#[derive(Debug)]
pub struct Timekeeper(RwLock<TimekeeperData>);
#[allow(dead_code)]
#[derive(Debug)]
pub struct TimekeeperData {
/// 用于计时的当前时钟源。
clock: Option<Arc<dyn Clocksource>>,
/// 当前时钟源的移位值。
shift: i32,
/// 一个NTP间隔中的时钟周期数。
cycle_interval: CycleNum,
/// 一个NTP间隔中时钟移位的纳秒数。
xtime_interval: u64,
///
xtime_remainder: i64,
/// 每个NTP间隔累积的原始纳米秒
raw_interval: i64,
/// 时钟移位纳米秒余数
xtime_nsec: u64,
/// 积累时间和ntp时间在ntp位移纳秒量上的差距
ntp_error: i64,
/// 用于转换时钟偏移纳秒和ntp偏移纳秒的偏移量
ntp_error_shift: i32,
/// NTP调整时钟乘法器
mult: u32,
raw_time: TimeSpec,
wall_to_monotonic: TimeSpec,
total_sleep_time: TimeSpec,
xtime: TimeSpec,
}
impl TimekeeperData {
pub fn new() -> Self {
Self {
clock: None,
shift: Default::default(),
cycle_interval: CycleNum(0),
xtime_interval: Default::default(),
xtime_remainder: Default::default(),
raw_interval: Default::default(),
xtime_nsec: Default::default(),
ntp_error: Default::default(),
ntp_error_shift: Default::default(),
mult: Default::default(),
xtime: TimeSpec {
tv_nsec: 0,
tv_sec: 0,
},
wall_to_monotonic: TimeSpec {
tv_nsec: 0,
tv_sec: 0,
},
total_sleep_time: TimeSpec {
tv_nsec: 0,
tv_sec: 0,
},
raw_time: TimeSpec {
tv_nsec: 0,
tv_sec: 0,
},
}
}
}
impl Timekeeper {
/// # 设置timekeeper的参数
///
/// ## 参数
///
/// * 'clock' - 指定的时钟实际类型。初始为ClocksourceJiffies
pub fn timekeeper_setup_internals(&self, clock: Arc<dyn Clocksource>) {
let mut timekeeper = self.0.write();
// 更新clock
let mut clock_data = clock.clocksource_data();
clock_data.watchdog_last = clock.read();
if clock.update_clocksource_data(clock_data).is_err() {
kdebug!("timekeeper_setup_internals:update_clocksource_data run failed");
}
timekeeper.clock.replace(clock.clone());
let clock_data = clock.clocksource_data();
let mut temp = NTP_INTERVAL_LENGTH << clock_data.shift;
let ntpinterval = temp;
temp += (clock_data.mult / 2) as u64;
// do div
timekeeper.cycle_interval = CycleNum(temp);
timekeeper.xtime_interval = temp * clock_data.mult as u64;
timekeeper.xtime_remainder = (ntpinterval - timekeeper.xtime_interval) as i64;
timekeeper.raw_interval = (timekeeper.xtime_interval >> clock_data.shift) as i64;
timekeeper.xtime_nsec = 0;
timekeeper.shift = clock_data.shift as i32;
timekeeper.ntp_error = 0;
timekeeper.ntp_error_shift = (NTP_SCALE_SHIFT - clock_data.shift) as i32;
timekeeper.mult = clock_data.mult;
}
/// # 获取当前时钟源距离上次检测走过的纳秒数
#[allow(dead_code)]
pub fn tk_get_ns(&self) -> u64 {
let timekeeper = self.0.read();
let clock = timekeeper.clock.clone().unwrap();
let clock_now = clock.read();
let clcok_data = clock.clocksource_data();
let clock_delta = clock_now.div(clcok_data.watchdog_last).data() & clcok_data.mask.bits();
return clocksource_cyc2ns(CycleNum(clock_delta), clcok_data.mult, clcok_data.shift);
}
}
pub fn timekeeper() -> &'static Timekeeper {
return unsafe { __TIMEKEEPER.as_ref().unwrap() };
}
pub fn timekeeper_init() {
unsafe { __TIMEKEEPER = Some(Timekeeper(RwLock::new(TimekeeperData::new()))) };
}
/// # 获取1970.1.1至今的UTC时间戳(最小单位:nsec)
///
/// ## 返回值
///
/// * 'TimeSpec' - 时间戳
pub fn getnstimeofday() -> TimeSpec {
kdebug!("enter getnstimeofday");
// let mut nsecs: u64 = 0;0
let mut _xtime = TimeSpec {
tv_nsec: 0,
tv_sec: 0,
};
loop {
match timekeeper().0.try_read() {
None => continue,
Some(tk) => {
_xtime = tk.xtime;
drop(tk);
// nsecs = timekeeper().tk_get_ns();
// TODO 不同架构可能需要加上不同的偏移量
break;
}
}
}
// xtime.tv_nsec += nsecs as i64;
let sec = __ADDED_SEC.load(Ordering::SeqCst);
_xtime.tv_sec += sec;
while _xtime.tv_nsec >= NSEC_PER_SEC.into() {
_xtime.tv_nsec -= NSEC_PER_SEC as i64;
_xtime.tv_sec += 1;
}
// TODO 将xtime和当前时间源的时间相加
return _xtime;
}
/// # 获取1970.1.1至今的UTC时间戳(最小单位:usec)
///
/// ## 返回值
///
/// * 'PosixTimeval' - 时间戳
pub fn do_gettimeofday() -> PosixTimeval {
let tp = getnstimeofday();
return PosixTimeval {
tv_sec: tp.tv_sec,
tv_usec: (tp.tv_nsec / 1000) as i32,
};
}
/// # 初始化timekeeping模块
pub fn timekeeping_init() {
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
timekeeper_init();
// TODO 有ntp模块后 在此初始化ntp模块
let clock = clocksource_default_clock();
clock
.enable()
.expect("clocksource_default_clock enable failed");
timekeeper().timekeeper_setup_internals(clock);
// 暂时不支持其他架构平台对时间的设置 所以使用x86平台对应值初始化
let mut timekeeper = timekeeper().0.write();
timekeeper.xtime.tv_nsec = ktime_get_real_ns();
// 初始化wall time到monotonic的时间
let mut nsec = -timekeeper.xtime.tv_nsec;
let mut sec = -timekeeper.xtime.tv_sec;
// FIXME: 这里有个奇怪的奇怪的bug
let num = nsec % NSEC_PER_SEC as i64;
nsec += num * NSEC_PER_SEC as i64;
sec -= num;
timekeeper.wall_to_monotonic.tv_nsec = nsec;
timekeeper.wall_to_monotonic.tv_sec = sec;
__ADDED_USEC.store(0, Ordering::SeqCst);
__ADDED_SEC.store(0, Ordering::SeqCst);
drop(irq_guard);
kdebug!("timekeeping_init successfully");
}
/// # 使用当前时钟源增加wall time
pub fn update_wall_time() {
let rsp = unsafe { crate::include::bindings::bindings::get_rsp() } as usize;
let _stack_use = align_up(rsp as u64, 32768) - rsp as u64;
// kdebug!("enter update_wall_time, stack_use = {:}",stack_use);
compiler_fence(Ordering::SeqCst);
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
// 如果在休眠那就不更新
if TIMEKEEPING_SUSPENDED.load(Ordering::SeqCst) {
return;
}
// ===== 请不要删除这些注释 =====
// let clock = timekeeper.clock.clone().unwrap();
// let clock_data = clock.clocksource_data();
// let offset = (clock.read().div(clock_data.watchdog_last).data()) & clock_data.mask.bits();
// timekeeper.xtime_nsec = (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift;
// // TODO 当有ntp模块之后 需要将timekeep与ntp进行同步并检查
// timekeeper.xtime.tv_nsec = ((timekeeper.xtime_nsec as i64) >> timekeeper.shift) + 1;
// timekeeper.xtime_nsec -= (timekeeper.xtime.tv_nsec as u64) << timekeeper.shift;
// timekeeper.xtime.tv_nsec += offset as i64;
// while unlikely(timekeeper.xtime.tv_nsec >= NSEC_PER_SEC.into()) {
// timekeeper.xtime.tv_nsec -= NSEC_PER_SEC as i64;
// timekeeper.xtime.tv_sec += 1;
// // TODO 需要处理闰秒
// }
// ================
compiler_fence(Ordering::SeqCst);
// 一分钟同步一次
__ADDED_USEC.fetch_add(500, Ordering::SeqCst);
compiler_fence(Ordering::SeqCst);
let mut retry = 10;
let usec = __ADDED_USEC.load(Ordering::SeqCst);
if usec % USEC_PER_SEC as i64 == 0 {
compiler_fence(Ordering::SeqCst);
__ADDED_SEC.fetch_add(1, Ordering::SeqCst);
compiler_fence(Ordering::SeqCst);
}
loop {
if (usec & !((1 << 26) - 1)) != 0 {
if __ADDED_USEC
.compare_exchange(usec, 0, Ordering::SeqCst, Ordering::SeqCst)
.is_ok()
|| retry == 0
{
// 同步时间
// 我感觉这里会出问题:多个读者不退出的话,写者就无法写入
// 然后这里会超时,导致在中断返回之后,会不断的进入这个中断,最终爆栈。
let mut timekeeper = timekeeper().0.write();
timekeeper.xtime.tv_nsec = ktime_get_real_ns();
timekeeper.xtime.tv_sec = 0;
__ADDED_SEC.store(0, Ordering::SeqCst);
drop(timekeeper);
break;
}
retry -= 1;
} else {
break;
}
}
// TODO 需要检查是否更新时间源
compiler_fence(Ordering::SeqCst);
drop(irq_guard);
compiler_fence(Ordering::SeqCst);
}
// TODO timekeeping_adjust
// TODO wall_to_monotic
// ========= 以下为对C的接口 =========
#[no_mangle]
pub extern "C" fn rs_timekeeping_init() {
timekeeping_init();
}

View File

@ -2,6 +2,7 @@
#include <common/glib.h>
#include <driver/timers/HPET/HPET.h>
#include <common/kthread.h>
// 定义LONG_MAX为最大超时时间 - 允许负数
#define MAX_TIMEOUT (int64_t)((1ul << 63) - 1)

View File

@ -1,4 +1,8 @@
use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
use core::{
fmt::Debug,
intrinsics::unlikely,
sync::atomic::{compiler_fence, AtomicBool, AtomicU64, Ordering},
};
use alloc::{
boxed::Box,
@ -7,31 +11,33 @@ use alloc::{
};
use crate::{
arch::{
asm::current::current_pcb,
interrupt::{cli, sti},
sched::sched,
arch::{asm::current::current_pcb, sched::sched, CurrentIrqArch},
exception::{
softirq::{softirq_vectors, SoftirqNumber, SoftirqVec},
InterruptArch,
},
exception::softirq::{softirq_vectors, SoftirqNumber, SoftirqVec},
include::bindings::bindings::{process_control_block, process_wakeup, pt_regs, PROC_RUNNING},
include::bindings::bindings::{process_control_block, process_wakeup, PROC_RUNNING},
kdebug, kerror,
libs::spinlock::SpinLock,
syscall::SystemError,
};
use super::timekeeping::update_wall_time;
const MAX_TIMEOUT: i64 = i64::MAX;
const TIMER_RUN_CYCLE_THRESHOLD: usize = 20;
static mut TIMER_JIFFIES: u64 = 0;
static TIMER_JIFFIES: AtomicU64 = AtomicU64::new(0);
lazy_static! {
pub static ref TIMER_LIST: SpinLock<LinkedList<Arc<Timer>>> = SpinLock::new(LinkedList::new());
}
/// 定时器要执行的函数的特征
pub trait TimerFunction: Send + Sync {
fn run(&mut self);
pub trait TimerFunction: Send + Sync + Debug {
fn run(&mut self) -> Result<(), SystemError>;
}
#[derive(Debug)]
/// WakeUpHelper函数对应的结构体
pub struct WakeUpHelper {
pcb: &'static mut process_control_block,
@ -44,13 +50,15 @@ impl WakeUpHelper {
}
impl TimerFunction for WakeUpHelper {
fn run(&mut self) {
fn run(&mut self) -> Result<(), SystemError> {
unsafe {
process_wakeup(self.pcb);
}
return Ok(());
}
}
#[derive(Debug)]
pub struct Timer(SpinLock<InnerTimer>);
impl Timer {
@ -97,6 +105,7 @@ impl Timer {
break;
}
}
let mut temp_list: LinkedList<Arc<Timer>> = timer_list.split_off(split_pos);
timer_list.push_back(inner_guard.self_ref.upgrade().unwrap());
timer_list.append(&mut temp_list);
@ -106,11 +115,18 @@ impl Timer {
#[inline]
fn run(&self) {
self.0.lock().timer_func.run();
let r = self.0.lock().timer_func.run();
if unlikely(r.is_err()) {
kerror!(
"Failed to run timer function: {self:?} {:?}",
r.err().unwrap()
);
}
}
}
/// 定时器类型
#[derive(Debug)]
pub struct InnerTimer {
/// 定时器结束时刻
pub expire_jiffies: u64,
@ -179,7 +195,7 @@ impl SoftirqVec for DoTimerSoftirq {
continue;
}
let timer_list_front_guard = timer_list_front_guard.unwrap();
if timer_list_front_guard.expire_jiffies > unsafe { TIMER_JIFFIES as u64 } {
if timer_list_front_guard.expire_jiffies > TIMER_JIFFIES.load(Ordering::SeqCst) {
drop(timer_list_front_guard);
timer_list.push_front(timer_list_front);
break;
@ -205,11 +221,11 @@ pub fn timer_init() {
/// 计算接下来n毫秒对应的定时器时间片
pub fn next_n_ms_timer_jiffies(expire_ms: u64) -> u64 {
return unsafe { TIMER_JIFFIES as u64 } + 1000 * (expire_ms);
return TIMER_JIFFIES.load(Ordering::SeqCst) + 1000 * (expire_ms);
}
/// 计算接下来n微秒对应的定时器时间片
pub fn next_n_us_timer_jiffies(expire_us: u64) -> u64 {
return unsafe { TIMER_JIFFIES as u64 } + (expire_us);
return TIMER_JIFFIES.load(Ordering::SeqCst) + (expire_us);
}
/// @brief 让pcb休眠timeout个jiffies
@ -229,15 +245,17 @@ pub fn schedule_timeout(mut timeout: i64) -> Result<i64, SystemError> {
return Err(SystemError::EINVAL);
} else {
// 禁用中断,防止在这段期间发生调度,造成死锁
cli();
timeout += unsafe { TIMER_JIFFIES } as i64;
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
timeout += TIMER_JIFFIES.load(Ordering::SeqCst) as i64;
let timer = Timer::new(WakeUpHelper::new(current_pcb()), timeout as u64);
timer.activate();
current_pcb().state &= (!PROC_RUNNING) as u64;
sti();
drop(irq_guard);
sched();
let time_remaining: i64 = timeout - unsafe { TIMER_JIFFIES } as i64;
let time_remaining: i64 = timeout - TIMER_JIFFIES.load(Ordering::SeqCst) as i64;
if time_remaining >= 0 {
// 被提前唤醒,返回剩余时间
return Ok(time_remaining);
@ -270,21 +288,22 @@ pub fn timer_get_first_expire() -> Result<u64, SystemError> {
}
pub fn update_timer_jiffies(add_jiffies: u64) -> u64 {
unsafe { TIMER_JIFFIES += add_jiffies };
return unsafe { TIMER_JIFFIES };
let prev = TIMER_JIFFIES.fetch_add(add_jiffies, Ordering::SeqCst);
compiler_fence(Ordering::SeqCst);
update_wall_time();
compiler_fence(Ordering::SeqCst);
return prev + add_jiffies;
}
pub fn clock() -> u64 {
return unsafe { TIMER_JIFFIES };
return TIMER_JIFFIES.load(Ordering::SeqCst);
}
// ====== 重构完成后请删掉extern C ======
#[no_mangle]
pub extern "C" fn rs_clock() -> u64 {
clock()
}
#[no_mangle]
pub extern "C" fn sys_clock(_regs: *const pt_regs) -> u64 {
clock()
}
// ====== 以下为给C提供的接口 ======
#[no_mangle]

View File

@ -0,0 +1,25 @@
CC=$(DragonOS_GCC)/x86_64-elf-gcc
LD=ld
OBJCOPY=objcopy
# 修改这里把它改为你的relibc的sysroot路径
RELIBC_OPT=$(DADK_BUILD_CACHE_DIR_RELIBC_0_1_0)
CFLAGS=-I $(RELIBC_OPT)/include
tmp_output_dir=$(ROOT_PATH)/bin/tmp/user
output_dir=$(DADK_BUILD_CACHE_DIR_TEST_GETTIMEOFDAY_0_1_0)
LIBC_OBJS:=$(shell find $(RELIBC_OPT)/lib -name "*.o" | sort )
LIBC_OBJS+=$(RELIBC_OPT)/lib/libc.a
all: main.o
mkdir -p $(tmp_output_dir)
$(LD) -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/test_gettimeofday $(shell find . -name "*.o") $(LIBC_OBJS) -T link.lds
$(OBJCOPY) -I elf64-x86-64 -R ".eh_frame" -R ".comment" -O elf64-x86-64 $(tmp_output_dir)/test_gettimeofday $(output_dir)/test_gettimeofday.elf
mv $(output_dir)/test_gettimeofday.elf $(output_dir)/test_gettimeofday
main.o: main.c
$(CC) $(CFLAGS) -c main.c -o main.o
clean:
rm -f *.o

View File

@ -0,0 +1,239 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
*(.rela.init)
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
*(.rela.fini)
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
*(.rela.ctors)
*(.rela.dtors)
*(.rela.got)
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
/* Thread Local Storage sections */
.tdata :
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we do not
pad the .data section. */
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}

View File

@ -0,0 +1,25 @@
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
// #include <sleep.h>
#include <unistd.h>
#include <time.h>
int main()
{
struct timeval *tv = malloc(sizeof(struct timeval));
// struct timezone *tz = malloc(sizeof(struct timezone));
// for (int i = 0; i < 15; i++)
// {
// gettimeofday(tv, NULL);
// printf("%ld.%06ld\n", tv->tv_sec, tv->tv_usec);
// for (int i = 0; i < 10; i++)
// {
// usleep(500000);
// }
// }
gettimeofday(tv, NULL);
printf("tv = %ld.%06ld\n", tv->tv_sec, tv->tv_usec);
// printf("tz_minuteswest = %d,tz_dsttime = %d", (*tz).tz_minuteswest, (*tz).tz_dsttime);
return 0;
}

View File

@ -0,0 +1,28 @@
{
"name": "test_gettimeofday",
"version": "0.1.0",
"description": "一个用来测试gettimeofday能够正常运行的app",
"task_type": {
"BuildFromSource": {
"Local": {
"path": "apps/test_gettimeofday"
}
}
},
"depends": [
{
"name": "relibc",
"version": "0.1.0"
}
],
"build": {
"build_command": "make"
},
"install": {
"in_dragonos_path": "/bin"
},
"clean": {
"clean_command": "make clean"
},
"envs": []
}