Bläddra i källkod

:new: usleep()、nanosleep()

fslongjin 2 år sedan
förälder
incheckning
676260c537

+ 1 - 1
kernel/common/dirent.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#include <common/miniLibc/sys/types.h>
+#include <common/sys/types.h>
 struct dirent
 {
     ino_t d_ino;    // 文件序列号

+ 1 - 1
kernel/common/glib.h

@@ -8,7 +8,7 @@
 //引入对bool类型的支持
 #include <stdbool.h>
 #include <stdint.h>
-#include <common/miniLibc/stddef.h>
+#include <common/stddef.h>
 #include <arch/arch.h>
 
 #define sti() __asm__ __volatile__("sti\n\t" :: \

+ 0 - 0
kernel/common/miniLibc/stddef.h → kernel/common/stddef.h


+ 0 - 0
kernel/common/miniLibc/sys/types.h → kernel/common/sys/types.h


+ 38 - 0
kernel/common/time.h

@@ -0,0 +1,38 @@
+#pragma once
+
+#include "stddef.h"
+
+// 操作系统定义时间以ns为单位
+#define CLOCKS_PER_SEC 1000000
+
+struct tm
+{
+    int tm_sec;   /* Seconds.	[0-60] (1 leap second) */
+    int tm_min;   /* Minutes.	[0-59] */
+    int tm_hour;  /* Hours.	[0-23] */
+    int tm_mday;  /* Day.		[1-31] */
+    int tm_mon;   /* Month.	[0-11] */
+    int tm_year;  /* Year	- 1900.  */
+    int tm_wday;  /* Day of week.	[0-6] */
+    int tm_yday;  /* Days in year.[0-365]	*/
+    int tm_isdst; /* DST.		[-1/0/1]*/
+
+    long int __tm_gmtoff;  /* Seconds east of UTC.  */
+    const char *__tm_zone; /* Timezone abbreviation.  */
+};
+
+
+struct timespec
+{
+    long int tv_sec;    // 秒
+    long int tv_nsec;   // 纳秒
+};
+
+/**
+ * @brief 休眠指定时间
+ * 
+ * @param rqtp 指定休眠的时间
+ * @param rmtp 返回的剩余休眠时间
+ * @return int 
+ */
+extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

+ 2 - 2
kernel/driver/timers/HPET/HPET.c

@@ -58,7 +58,7 @@ void HPET_handler(uint64_t number, uint64_t param, struct pt_regs *regs)
     switch (param)
     {
     case 0: // 定时器0中断
-        ++timer_jiffies;
+        timer_jiffies += HPET0_INTERVAL;
 
         /*
         // 将HEPT中断消息转发到ap:1处理器
@@ -68,7 +68,7 @@ void HPET_handler(uint64_t number, uint64_t param, struct pt_regs *regs)
 
         // 若当前时间比定时任务的时间间隔大,则进入中断下半部
         if (container_of(list_next(&timer_func_head.list), struct timer_func_list_t, list)->expire_jiffies <= timer_jiffies)
-            raise_softirq((1 << TIMER_SIRQ));
+            raise_softirq(TIMER_SIRQ);
 
         // 当时间到了,或进程发生切换时,刷新帧缓冲区
         if (timer_jiffies >= video_refresh_expire_jiffies || (video_last_refresh_pid != current_pcb->pid))

+ 11 - 1
kernel/process/process.c

@@ -702,13 +702,23 @@ struct process_control_block *process_get_pcb(long pid)
  * @param pcb 进程的pcb
  */
 void process_wakeup(struct process_control_block *pcb)
+{
+    pcb->state = PROC_RUNNING;
+    sched_cfs_enqueue(pcb);
+}
+
+/**
+ * @brief 将进程加入到调度器的就绪队列中,并标志当前进程需要被调度
+ *
+ * @param pcb 进程的pcb
+ */
+void process_wakeup_immediately(struct process_control_block *pcb)
 {
     pcb->state = PROC_RUNNING;
     sched_cfs_enqueue(pcb);
     // 将当前进程标志为需要调度,缩短新进程被wakeup的时间
     current_pcb->flags |= PF_NEED_SCHED;
 }
-
 /**
  * @brief 拷贝当前进程的标志位
  *

+ 7 - 0
kernel/process/process.h

@@ -286,6 +286,13 @@ struct process_control_block *process_get_pcb(long pid);
  */
 void process_wakeup(struct process_control_block *pcb);
 
+/**
+ * @brief 将进程加入到调度器的就绪队列中,并标志当前进程需要被调度
+ *
+ * @param pcb 进程的pcb
+ */
+void process_wakeup_immediately(struct process_control_block *pcb);
+
 /**
  * @brief 使当前进程去执行新的代码
  *

+ 14 - 1
kernel/syscall/syscall.c

@@ -10,11 +10,14 @@
 #include <filesystem/VFS/VFS.h>
 #include <driver/keyboard/ps2_keyboard.h>
 #include <process/process.h>
+#include <time/sleep.h>
 
 // 导出系统调用入口函数,定义在entry.S中
 extern void system_call(void);
 extern void syscall_int(void);
 
+
+
 /**
  * @brief 导出系统调用处理函数的符号
  *
@@ -723,6 +726,15 @@ uint64_t sys_exit(struct pt_regs *regs)
     return process_do_exit(regs->r8);
 }
 
+
+uint64_t sys_nanosleep(struct pt_regs * regs)
+{
+    const struct timespec * rqtp = (const struct timespec*)regs->r8;
+    struct timespec * rmtp = (struct timespec*)regs->r9;
+
+    return nanosleep(rqtp, rmtp);
+}
+
 ul sys_ahci_end_req(struct pt_regs *regs)
 {
     ahci_end_request();
@@ -757,5 +769,6 @@ system_call_t system_call_table[MAX_SYSTEM_CALL_NUM] =
         [15] = sys_wait4,
         [16] = sys_exit,
         [17] = sys_mkdir,
-        [18 ... 254] = system_call_not_exists,
+        [18] = sys_nanosleep,
+        [19 ... 254] = system_call_not_exists,
         [255] = sys_ahci_end_req};

+ 1 - 0
kernel/syscall/syscall_num.h

@@ -28,5 +28,6 @@
 #define SYS_WAIT4 15 // 等待进程退出
 #define SYS_EXIT 16 // 进程退出
 #define SYS_MKDIR 17 // 创建文件夹
+#define SYS_NANOSLEEP 18 // 纳秒级休眠
 
 #define SYS_AHCI_END_REQ 255    // AHCI DMA请求结束end_request的系统调用

+ 4 - 1
kernel/time/Makefile

@@ -1,10 +1,13 @@
 
-all: timer.o 
+all: timer.o sleep.o
 
 CFLAGS += -I .
 
 timer.o: timer.c
 	gcc $(CFLAGS) -c timer.c -o timer.o
 
+sleep.o: sleep.c
+	gcc $(CFLAGS) -c sleep.c -o sleep.o
+
 clean:
 	echo "Done."

+ 62 - 0
kernel/time/sleep.c

@@ -0,0 +1,62 @@
+#include "sleep.h"
+#include <common/errno.h>
+#include <time/timer.h>
+#include <process/process.h>
+#include <sched/sched.h>
+#include <mm/slab.h>
+/**
+ * @brief nanosleep定时事件到期后,唤醒指定的进程
+ *
+ * @param pcb 待唤醒的进程的pcb
+ */
+void nanosleep_handler(void *pcb)
+{
+    process_wakeup((struct process_control_block *)pcb);
+}
+
+/**
+ * @brief 休眠指定时间
+ *
+ * @param rqtp 指定休眠的时间
+ * @param rmtp 返回的剩余休眠时间
+ * @return int
+ */
+int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+    int64_t total_ns = rqtp->tv_nsec;
+    // kdebug("totalns = %ld", total_ns);
+    if (total_ns < 0 || total_ns >= 1000000000)
+        return -EINVAL;
+
+    // todo: 对于小于500us的时间,使用spin/rdtsc来进行定时
+    if (total_ns < 50000)
+        return 0;
+
+    if (total_ns < 500000)
+        total_ns = 500000;
+
+    // 增加定时任务
+    struct timer_func_list_t *sleep_task = (struct timer_func_list_t *)kmalloc(sizeof(struct timer_func_list_t), 0);
+    memset(sleep_task, 0, sizeof(struct timer_func_list_t));
+
+    
+
+    
+    timer_func_init_us(sleep_task, &nanosleep_handler, (void *)current_pcb, total_ns / 1000);
+    
+    timer_func_add(sleep_task);
+
+    current_pcb->state = PROC_INTERRUPTIBLE;
+    current_pcb->flags |= PF_NEED_SCHED;
+    sched_cfs();
+
+    // todo: 增加信号唤醒的功能后,设置rmtp
+
+    if (rmtp != NULL)
+    {
+        rmtp->tv_nsec = 0;
+        rmtp->tv_sec = 0;
+    }
+
+    return 0;
+}

+ 16 - 0
kernel/time/sleep.h

@@ -0,0 +1,16 @@
+#pragma once
+
+#include <common/glib.h>
+#include <process/ptrace.h>
+#include <common/time.h>
+
+
+/**
+ * @brief 休眠指定时间
+ * 
+ * @param rqtp 指定休眠的时间
+ * @param rmtp 返回的剩余休眠时间
+ * @return int 
+ */
+int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
+

+ 19 - 3
kernel/time/timer.c

@@ -30,7 +30,7 @@ void timer_init()
 
 void do_timer_softirq(void *data)
 {
-    
+    // todo: 修改这里以及softirq的部分,使得timer具有并行性
     struct timer_func_list_t *tmp = container_of(list_next(&timer_func_head.list), struct timer_func_list_t, list);
     int cycle_count = 0;
     while ((!list_empty(&timer_func_head.list)) && (tmp->expire_jiffies <= timer_jiffies))
@@ -60,11 +60,27 @@ void timer_func_init(struct timer_func_list_t *timer_func, void (*func)(void *da
 {
     list_init(&timer_func->list);
     timer_func->func = func;
-    timer_func->data = data,
-    // timer_func->expire_jiffies = timer_jiffies + expire_ms / 5 + expire_ms % HPET0_INTERVAL ? 1 : 0; // 设置过期的时间片
+    timer_func->data = data;
     timer_func->expire_jiffies = cal_next_n_ms_jiffies(expire_ms); // 设置过期的时间片
 }
 
+/**
+ * @brief 初始化定时功能
+ *
+ * @param timer_func 队列结构体
+ * @param func 定时功能处理函数
+ * @param data 传输的数据
+ * @param expire_us 定时时长(单位:us)
+ */
+void timer_func_init_us(struct timer_func_list_t *timer_func, void (*func)(void *data), void *data, uint64_t expire_us)
+{
+    list_init(&timer_func->list);
+    timer_func->func = func;
+    timer_func->data = data;
+    timer_func->expire_jiffies = cal_next_n_us_jiffies(expire_us); // 设置过期的时间片
+    // kdebug("timer_func->expire_jiffies=%ld",cal_next_n_us_jiffies(expire_us));
+}
+
 /**
  * @brief 将定时功能添加到列表中
  *

+ 12 - 2
kernel/time/timer.h

@@ -7,9 +7,9 @@
 uint64_t volatile timer_jiffies = 0; // 系统时钟计数
 
 // 计算接下来n毫秒对应的系统时间片
-#define cal_next_n_ms_jiffies(expire_ms) (timer_jiffies + 1000*expire_ms / HPET0_INTERVAL + ((1000*expire_ms % HPET0_INTERVAL) ? 1 : 0))
+#define cal_next_n_ms_jiffies(expire_ms) (timer_jiffies + 1000*expire_ms)
 // 计算接下来n微秒对应的系统时间片
-#define cal_next_n_us_jiffies(expire_us) (timer_jiffies + expire_us / HPET0_INTERVAL + ((expire_us % HPET0_INTERVAL) ? 1 : 0))
+#define cal_next_n_us_jiffies(expire_us) (timer_jiffies + expire_us)
 
 void timer_init();
 
@@ -38,6 +38,16 @@ extern struct timer_func_list_t timer_func_head;
  */
 void timer_func_init(struct timer_func_list_t *timer_func, void (*func)(void *data), void *data, uint64_t expire_ms);
 
+/**
+ * @brief 初始化定时功能
+ *
+ * @param timer_func 队列结构体
+ * @param func 定时功能处理函数
+ * @param data 传输的数据
+ * @param expire_us 定时时长(单位:us)
+ */
+void timer_func_init_us(struct timer_func_list_t *timer_func, void (*func)(void *data), void *data, uint64_t expire_us);
+
 /**
  * @brief 将定时功能添加到列表中
  *

+ 5 - 1
user/apps/about/about.c

@@ -1,5 +1,7 @@
 #include <libc/stdio.h>
-#include<libc/stdlib.h>
+#include <libc/stdlib.h>
+#include <libc/unistd.h>
+
 void print_ascii_logo()
 {
     printf(" ____                                      ___   ____ \n");
@@ -24,6 +26,8 @@ int main()
 {
     // printf("Hello World!\n");
     print_ascii_logo();
+    usleep(500000);
+    usleep(500000);
     print_copyright();
     // exit(0);
     // while (1)

+ 5 - 2
user/libs/libc/Makefile

@@ -9,7 +9,7 @@ libc_sub_dirs += sysdeps/x86_64
 endif
 
 
-libc: unistd.o fcntl.o malloc.o errno.o printf.o stdlib.o ctype.o string.o dirent.o
+libc: unistd.o fcntl.o malloc.o errno.o printf.o stdlib.o ctype.o string.o dirent.o time.o
 	@list='$(libc_sub_dirs)'; for subdir in $$list; do \
     		echo "make all in $$subdir";\
     		cd $$subdir;\
@@ -42,4 +42,7 @@ string.o: string.c
 	gcc $(CFLAGS) -c string.c -o string.o
 
 dirent.o: dirent.c
-	gcc $(CFLAGS) -c dirent.c -o dirent.o
+	gcc $(CFLAGS) -c dirent.c -o dirent.o
+
+time.o: time.c
+	gcc $(CFLAGS) -c time.c -o time.o

+ 32 - 0
user/libs/libc/time.c

@@ -0,0 +1,32 @@
+#include "time.h"
+#include "errno.h"
+#include "unistd.h"
+#include <libsystem/syscall.h>
+
+/**
+ * @brief 休眠指定时间
+ *
+ * @param rqtp 指定休眠的时间
+ * @param rmtp 返回的剩余休眠时间
+ * @return int
+ */
+int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+    return syscall_invoke(SYS_NANOSLEEP, (uint64_t)rqtp, (uint64_t)rmtp, 0, 0, 0, 0, 0, 0);
+}
+
+/**
+ * @brief 睡眠指定时间
+ *
+ * @param usec 微秒
+ * @return int
+ */
+int usleep(useconds_t usec)
+{
+    struct timespec ts = {
+        tv_sec : (long int)(usec / 1000000),
+        tv_nsec : (long int)(usec % 1000000) * 1000UL
+    };
+    
+    return nanosleep(&ts, NULL);
+}

+ 38 - 0
user/libs/libc/time.h

@@ -0,0 +1,38 @@
+#pragma once
+
+#include "stddef.h"
+
+// 操作系统定义时间以ns为单位
+#define CLOCKS_PER_SEC 1000000
+
+struct tm
+{
+    int tm_sec;   /* Seconds.	[0-60] (1 leap second) */
+    int tm_min;   /* Minutes.	[0-59] */
+    int tm_hour;  /* Hours.	[0-23] */
+    int tm_mday;  /* Day.		[1-31] */
+    int tm_mon;   /* Month.	[0-11] */
+    int tm_year;  /* Year	- 1900.  */
+    int tm_wday;  /* Day of week.	[0-6] */
+    int tm_yday;  /* Days in year.[0-365]	*/
+    int tm_isdst; /* DST.		[-1/0/1]*/
+
+    long int __tm_gmtoff;  /* Seconds east of UTC.  */
+    const char *__tm_zone; /* Timezone abbreviation.  */
+};
+
+
+struct timespec
+{
+    long int tv_sec;    // 秒
+    long int tv_nsec;   // 纳秒
+};
+
+/**
+ * @brief 休眠指定时间
+ * 
+ * @param rqtp 指定休眠的时间
+ * @param rmtp 返回的剩余休眠时间
+ * @return int 
+ */
+int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

+ 8 - 0
user/libs/libc/unistd.h

@@ -89,3 +89,11 @@ int64_t chdir(char *dest_path);
  * @return int 
  */
 int execv(const char* path, char * const argv[]);
+
+/**
+ * @brief 睡眠指定时间
+ * 
+ * @param usec 微秒
+ * @return int 
+ */
+extern int usleep(useconds_t usec);

+ 1 - 0
user/libs/libsystem/syscall.h

@@ -22,6 +22,7 @@
 #define SYS_WAIT4 15 // 等待进程退出
 #define SYS_EXIT 16 // 进程退出
 #define SYS_MKDIR 17 // 创建文件夹
+#define SYS_NANOSLEEP 18 // 纳秒级休眠
 
 /**
  * @brief 用户态系统调用函数