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) {
setup_boot_irqs();
- setup_i8253(100);
+ setup_i8254(100);
boot_delay(DEFAULT_BOOT_DELAY_TICKS);
uint32_t esp;
uint32_t eip;
- uint32_t ticks;
+ int ticks;
uint32_t turn; // 时间片用完次数
uint32_t priority;
uint64_t jiffies;
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);
}
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));
+ // }
}
reenter--;
// 考察如果不需要调度程序,直接退出
- if (current->ticks != 0) {
+ if (current->need_resched == 0) {
return;
}
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);
}
}
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;
}
task_t *prev = current;
task_t *next = sel != 0 ? sel : root;
+ prev->need_resched = 0;
+
next->state = TASK_RUNNING;
next->reason = "";
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();
boot_delay(DEFAULT_BOOT_DELAY_TICKS);
- setup_i8253(100);
+ setup_i8254(100);
setup_irqs();
void ide_init();
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(¤t->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(¤t->pend, &delay_tasks);
+ irq_restore(flags);
+ }
schedule();
+ return 0;
}
int sysc_test() {}
#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;
#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")