]> Zhao Yanbai Git Server - kernel.git/commitdiff
解决task_t.ticks可能被时钟中断减为负数的问题
authoracevest <zhaoyanbai@126.com>
Sat, 11 May 2024 01:40:36 +0000 (09:40 +0800)
committeracevest <zhaoyanbai@126.com>
Sat, 11 May 2024 04:53:05 +0000 (12:53 +0800)
boot/boot.c
include/task.h
kernel/clock.c
kernel/irq.c
kernel/sched.c
kernel/setup.c
kernel/syscall.c
kernel/task_init.c
kernel/task_root.c

index f7ad9f091bc4a91d4d4950b1a49c9dc21b977463..74987969ae7bd0052463bc6811b49d0c2cfee140 100644 (file)
@@ -53,7 +53,7 @@ void setup_gdt();
 void setup_idt();
 void setup_gates();
 void set_tss();
-void setup_i8253(uint16_t);
+void setup_i8254(uint16_t);
 void setup_boot_irqs();
 
 void check_kernel(unsigned long addr, unsigned long magic) {
@@ -78,7 +78,7 @@ void check_kernel(unsigned long addr, unsigned long magic) {
 
     setup_boot_irqs();
 
-    setup_i8253(100);
+    setup_i8254(100);
 
     boot_delay(DEFAULT_BOOT_DELAY_TICKS);
 
index d47538ed56e3490793eff7620491c76179cb8a04..30f96de57c76938953533eee6cfbcef0ae2a4ea4 100644 (file)
@@ -48,7 +48,7 @@ typedef union task_union {
         uint32_t esp;
         uint32_t eip;
 
-        uint32_t ticks;
+        int ticks;
         uint32_t turn;  // 时间片用完次数
         uint32_t priority;
         uint64_t jiffies;
index 6c7ac6316781e4d5a34211b10493d123e4ba2efa..e78622f606192fe8746870449f5b7286a354fcfb 100644 (file)
@@ -36,15 +36,24 @@ void clk_handler(unsigned int irq, pt_regs_t *regs, void *dev_id) {
     current->jiffies = jiffies;
 
     // 中断目前虽然不能嵌套,但依然可以打断前一个中断的下半部分处理
-    // 若前一个时钟中断将这个值减到0
-    // 同时其下半部分处理时间过长,直到这个时钟中断还没处理完
-    // 那么这个时钟中断是完全可以打断它,且在这里把这个ticks从0减到负数
-    // 而这个是uint32_t型,因此会溢出成0xFFFFFFFF
-    if (current->ticks > 0) {
-        current->ticks--;
+    // 若前一个时钟中断将这个值减到0,会将该进程设置为need_resched,同时分配新的时间片值,以在下半部处理完后再重新调度就绪进程运行
+    // 而如果其下半部分需要处理的事情很多,处理时间过长,两个时钟中断之间的时间还不足以处理完
+    // 那么下一个时钟中断是完全可以打断还没处理完的下半部逻辑
+    // 打断后该时钟中断不应该继续减少该进程的时间片,因为这会造成该进程在后续的调底中少了实际的运行时间
+    if (1 == current->need_resched) {
+        // 这种情况必然已经发生了该时钟中断打断了下半部处理程序
+        return;
     }
 
-    assert(current->ticks <= TASK_MAX_PRIORITY);  // 防止ticks被减到0后再减溢出
+    current->ticks--;
+
+    if (0 == current->ticks) {
+        current->need_resched = 1;
+        current->ticks = current->priority;
+        current->turn++;
+    }
+
+    assert(current->ticks >= 0);  // 防止ticks被减到0后再减溢出
 
     add_irq_bh_handler(clk_bh_handler, NULL);
 }
@@ -73,23 +82,56 @@ void clk_bh_handler(void *arg) {
     debug_print_all_tasks();
 }
 
-void setup_i8253(uint16_t hz) {
-    // 最低频率为18.2Hz(1193180/65536,最大计数值是65536是因为往计数器里写0就从65536开始计数)
+uint16_t read_i8254_counter(uint8_t counter_no) {
+    const uint8_t i8254_cmd_port = 0x43;
+    const uint8_t i8254_data_port = 0x40 + counter_no;
+
+    assert(counter_no < 3);
+
+    uint8_t cmd = 0x00;
+    cmd |= 0x03 << 6;                 // read back command
+    cmd |= 0x01 << 4;                 // don't latch status
+    cmd |= 0x01 << (counter_no + 1);  // read back timer channel n
+
+    uint16_t value = 0;
+
+    outb_p(cmd, i8254_cmd_port);
+
+    value |= inb(i8254_data_port) << 0;
+    value |= inb(i8254_data_port) << 8;
+
+    return value;
+}
+
+void setup_i8254(uint16_t hz) {
+    // PC/AT 8254的连接方法
+    // 第0个计数器连连到了8259A的IRQ0
+    // 第1个计数器连连到了DRAM刷新电路,通常情况下,该通道的频率设置为15.2kHz
+    // 第2个计数器连连到了音频驱动单元,可以通过频率控制发声
+
+    // 8254的最低频率为18.2Hz(1193180/65536,最大计数值是65536是因为往计数器里写0就从65536开始计数)
     assert(hz >= 19);
 
     const uint8_t counter_no = 0;  // 第0个计数器
     const uint8_t read_write_latch = 3;  // 0 锁存数据供CPU读;1只读写低字节;2只读写高字节;3先读写低字节,后读写高字节
     const uint8_t mode = 2;  //
+    const uint8_t BCD = 0;   // 0 二进制;1 BCD码
 
-    const uint8_t cmd = (counter_no << 6) | (read_write_latch << 4) | (mode << 1);  // 第0位为0表示二进制,为1表示BCD
+    const uint8_t cmd =
+        ((counter_no & 0x03) << 6) | ((read_write_latch & 0x03) << 4) | ((mode & 0x07) << 1) | ((BCD & 0x01) << 0);
 
-    const uint8_t i8253_cmd_port = 0x43;
-    const uint8_t i8253_data_port = 0x40 + counter_no;
+    const uint8_t i8254_cmd_port = 0x43;
+    const uint8_t i8254_data_port = 0x40 + counter_no;
 
     const uint32_t clock_rate = 1193180;
     uint16_t latch = (clock_rate + hz / 2) / hz;
 
-    outb_p(cmd, i8253_cmd_port);
-    outb_p(latch & 0xFF, i8253_data_port);
-    outb(latch >> 8, i8253_data_port);
+    // 必须先写控制命令,再写入初始计数值
+    outb_p(cmd, i8254_cmd_port);
+    outb_p((latch >> 0) & 0xFF, i8254_data_port);
+    outb_p((latch >> 8) & 0xFF, i8254_data_port);
+
+    // for (uint8_t i = 0; i < 3; i++) {
+    //     printk("i8254 counter%u value %u\n", i, read_i8254_counter(i));
+    // }
 }
index b6f6a5b45b1378d27c60cee74ec845b5969c213e..b25f38244628bab97f982524f3b20940eb4edf8e 100644 (file)
@@ -136,7 +136,7 @@ __attribute__((regparm(1))) void irq_handler(pt_regs_t *regs) {
     reenter--;
 
     // 考察如果不需要调度程序,直接退出
-    if (current->ticks != 0) {
+    if (current->need_resched == 0) {
         return;
     }
 
index b2af86ea03c226e089b4de843823b7cea231804c..86d9105bf53646f160dc432b81ddc55d04c61637 100644 (file)
@@ -167,12 +167,12 @@ const char *task_state(unsigned int state) {
 void debug_print_all_tasks() {
     task_t *p = 0;
     list_head_t *pos = 0, *t = 0;
-    printl(MPL_TASK_TITLE, "         NAME       STATE TK/PI REASON     SCHED      KEEP");
+    printl(MPL_TASK_TITLE, "         NAME       STATE TK/PI REASON     SCHED      KEEP       TURN");
     list_for_each_safe(pos, t, &all_tasks) {
         p = list_entry(pos, task_t, list);
-        printl(MPL_TASK_0 + p->pid, "%08x%s%-6s:%u %s %02u/%02u %-10s %-10u %-10u", p,
+        printl(MPL_TASK_0 + p->pid, "%08x%s%-6s:%u %s %02u/%02u %-10s %-10u %-10u %-10u", p,
                p->state == TASK_RUNNING ? ">" : " ", p->name, p->pid, task_state(p->state), p->ticks, p->priority,
-               p->reason, p->sched_cnt, p->sched_keep_cnt);
+               p->reason, p->sched_cnt, p->sched_keep_cnt, p->turn);
     }
 }
 
@@ -182,17 +182,12 @@ void schedule() {
     task_t *p = 0;
     list_head_t *pos = 0, *t = 0;
 
-    assert(current->ticks <= TASK_MAX_PRIORITY);
+    assert(current->ticks >= 0);
     assert(current->priority <= TASK_MAX_PRIORITY);
 
     unsigned long iflags;
     irq_save(iflags);
 
-    if (0 == current->ticks) {
-        current->turn++;
-        current->ticks = current->priority;
-    }
-
     if (current->state == TASK_RUNNING) {
         current->state = TASK_READY;
     }
@@ -233,6 +228,8 @@ void schedule() {
     task_t *prev = current;
     task_t *next = sel != 0 ? sel : root;
 
+    prev->need_resched = 0;
+
     next->state = TASK_RUNNING;
     next->reason = "";
 
index 12e2314fbcea5425c1fb3bc23169c402b30e4d17..a44c16932dac40dbd3abb695b2e96d133893d804 100644 (file)
@@ -24,7 +24,7 @@ extern void init_buffer();
 extern void setup_gdt();
 extern void setup_idt();
 extern void setup_gate();
-void setup_i8253(uint16_t hz);
+void setup_i8254(uint16_t hz);
 extern void detect_cpu();
 extern void setup_sysc();
 extern void setup_pci();
@@ -87,7 +87,7 @@ void setup_kernel() {
 
     boot_delay(DEFAULT_BOOT_DELAY_TICKS);
 
-    setup_i8253(100);
+    setup_i8254(100);
     setup_irqs();
 
     void ide_init();
index 9979ce1938ce3185bf5ac35ff46cc1356db4aeed..c1f5c010172b7aa8d0ef91be97d10fc685234e99 100644 (file)
@@ -43,20 +43,24 @@ int sysc_none() {
 
 extern uint64_t jiffies;
 
-// 特别说明:如果想把这个函数的参数ticks改为uint64_t
+// 特别说明:如果想把这个函数的参数ticks改为int64_t
 // 那么就需要在编写用户级的系统调用库函数的时候注意
 // 不仅需要填写 ebx,还要填写 ecx
 // 不然就可能出现诡异的一直WAIT,不会调度到该任务的问题
-int sysc_wait(uint32_t ticks) {
-    unsigned long flags;
-    irq_save(flags);
-    current->state = TASK_WAIT;
-    current->reason = "sysc_wait";
-    current->delay_jiffies = jiffies + ticks;
-    list_add(&current->pend, &delay_tasks);
-    irq_restore(flags);
-
+int sysc_wait(int ticks) {
+    if (ticks < 0) {
+        return -EINVAL;
+    } else {
+        unsigned long flags;
+        irq_save(flags);
+        current->state = TASK_WAIT;
+        current->reason = "sysc_wait";
+        current->delay_jiffies = jiffies + ticks;
+        list_add(&current->pend, &delay_tasks);
+        irq_restore(flags);
+    }
     schedule();
+    return 0;
 }
 
 int sysc_test() {}
index 30753e7ec6724d7eeeb8bd578154316f28472c96..7064470895bc2240f197a8f096fc2dd5ba3a2b5b 100644 (file)
@@ -9,7 +9,7 @@
 #include <syscall.h>
 #include <system.h>
 #include <types.h>
-int sysc_wait(uint32_t ticks);
+int sysc_wait(int ticks);
 void init_task_entry() {
     current->priority = 10;
 
index 9ea4224defb1dfd616e133d77a5118dc62052641..528f3a9ac2732a0f6b62e67a6754766a1df12b97 100644 (file)
@@ -22,7 +22,7 @@
 #include <types.h>
 
 int do_fork(pt_regs_t *regs, unsigned long flags);
-int sysc_wait(uint32_t ticks);
+int sysc_wait(int ticks);
 
 #define get_eflags(x) __asm__ __volatile__("pushfl; popl %0;" : "=g"(x)::"memory")