ide_pci_controller[i].request_queue.count = 0;
INIT_LIST_HEAD(&ide_pci_controller[i].request_queue.list);
semaphore_init(&ide_pci_controller[i].request_queue.sem, 0);
- semaphore_init(&ide_pci_controller[i].disk_intr_sem, 0);
+ init_completion(&ide_pci_controller[i].intr_complete);
+ ide_pci_controller[i].intr_complete.name = i == 0 ? "ide0_intr_complete" : "ide1_intr_complete";
atomic_set(&ide_pci_controller[i].request_cnt, 0);
atomic_set(&ide_pci_controller[i].irq_cnt, 0);
printlxy(MPL_IDE0 + channel, MPO_IDE, "IDE%d req %u irq %u consumed %u", channel,
atomic_read(&(ide_ctrl->request_cnt)), ide_ctrl->irq_cnt, ide_ctrl->consumed_cnt);
- // up里不会立即重新调度进程
- up(&ide_ctrl->disk_intr_sem);
+ // complete会唤醒进程,但不会立即重新调度进程
+ complete(&ide_ctrl->intr_complete);
}
void ide_irq_handler(unsigned int irq, pt_regs_t *regs, void *devid) {
// 请求队列
disk_request_queue_t request_queue;
- // task disk与中断函数之间的信号量
- // 初始化成0
- semaphore_t disk_intr_sem;
+ // 中断处理函数通知task disk任务完成
+ completion_t intr_complete;
atomic_t request_cnt;
atomic_t irq_cnt;
extern ide_drive_t ide_drives[MAX_IDE_DRIVE_CNT];
ide_drive_t *ide_get_drive(dev_t dev);
-
-void sleep_on_ide();
-void wait_on_ide();
irq_restore(iflags);
retry++;
// wait on free list
- wait_on(&s->waitq);
+ // TODO
+ assert(0);
+ // wait_on(&s->waitq);
goto again;
}
assert(s != NULL);
assert(s - store < 3);
- wake_up(&s->waitq);
+ // TODO
+ assert(0);
+ // wake_up(&s->waitq);
}
bbuffer_t *bread(dev_t dev, uint64_t block, uint32_t size) {
#include <wait.h>
typedef struct completion {
- int done;
+ volatile int done;
wait_queue_head_t wait;
+
+ // 仅用于调试
+ char *name;
} completion_t;
#define COMPLETION_INITIALIZER(x) \
{ 0, WAIT_QUEUE_HEAD_INITIALIZER(x).wait }
-void wait_completion(completion_t *x);
void init_completion(completion_t *x);
+void wait_completion(completion_t *x);
+
+// 一次只唤醒一个进程
void complete(completion_t *x);
// 使用这个函数的时候需要注意
// 设置condition为真的语句和wake_up原子地执行
+// wake_up只唤醒不立即重新调度
void wake_up(wait_queue_head_t *head);
+
+// nr == 0 代表唤醒所有
void __wake_up(wait_queue_head_t *head, int nr);
// 以下wait_event被定义成宏,而不是函数是因为condition
// condition可能是一个表达式,如果定义成函数,往下传递就直接变成了一个值
// 如果在某一步这个值变了,并不会反应在这些逻辑判断上
+#define __wait_event(head, condition) \
+ do { \
+ DECLARE_WAIT_QUEUE_ENTRY(__wait, current); \
+ unsigned long flags; \
+ while (1) { \
+ irq_save(flags); \
+ prepare_to_wait(head, &__wait, TASK_WAIT); \
+ if ((condition)) { \
+ __end_wait(&__wait); \
+ irq_restore(flags); \
+ break; \
+ } else { \
+ irq_restore(flags); \
+ void schedule(); \
+ schedule(); \
+ __end_wait(&__wait); \
+ } \
+ } \
+ } while (0)
-// 只要保证condition设置为真时,它是和wake_up一起原子执行的
-// 那就能保证condition为真是如下__wait_event和wait_event里的if不出问题
-// 也就是不会出现if-break后进程又再次因为其它原因阻塞后,又被wake_up的逻辑
-// 设置为READY状态
+#if 0
+// __wait_event这个逻辑参考自Linux内核,但是发现它有BUG
+// 第一个问题
+// 1. 在进入到__wait_event后,prepare_to_wait前其它进程通过wake_up唤醒当前进程
+// 2. prepare_to_wait把当前进程设置为TASK_WAIT
+// 3. prepare_to_wait最后一句irq_restore(flags);执行完后 其实 condition 已经为true了
+// 4. 从if((conditon))到break再到__end_wait前都有可能被中断打断并重新schedule()
+// 只要在__end_wait的irq_save(flags);完全关闭中断前被中断打断并schedule把当前进程换下CPU,那么这次唤醒就会丢失
+// 如果只有一次唤醒,那么这个唤醒丢失后,当前进程就会一直处于WAIT状态并且永远不会再被调度到
+//
+// 但按理Linux内核不应该会出现这种BUG,还没研究明白,先把这段代码放在这里
#define __wait_event(head, condition) \
do { \
DECLARE_WAIT_QUEUE_ENTRY(__wait, current); \
} \
__end_wait(&__wait); \
} while (0)
-
-#define wait_event(head, condition) \
- do { \
- if (!(condition)) { \
- __wait_event(head, (condition)); \
- } \
+#endif
+
+#define wait_event(head, condition) \
+ do { \
+ if ((condition)) { \
+ break; \
+ } \
+ __wait_event(head, (condition)); \
} while (0)
-
-// 无条件wait
-void wait_on(wait_queue_head_t *head);
#include <sched.h>
void wait_completion(completion_t *x) {
- //
- wait_event(&x->wait, (x->done == 1));
+ wait_event(&x->wait, (x->done != 0));
+ x->done--;
}
void complete(completion_t *x) {
uint32_t iflags;
irq_save(iflags);
- x->done = 1;
- // wake_up(&x->wait);
- __wake_up(&x->wait, 0);
+ x->done++;
+ __wake_up(&x->wait, 1);
irq_restore(iflags);
}
void init_completion(completion_t *x) {
x->done = 0;
init_wait_queue_head(&x->wait);
+
+ // 测试字段
+ x->name = 0;
}
{
enable_irq();
+ // 这里面不能执行任务切换操作,比如信号量相关操作
irq_bh_handler();
disable_irq();
uint64_t pos = r->pos + drv->partions[part_id].lba_start;
assert(pos < drv->partions[part_id].lba_end);
+ // init_completion(&ide_ctrl->intr_complete);
+
switch (r->command) {
case DISK_REQ_IDENTIFY:
printk("try to read disk drive %u identify", drv_no);
}
// 等待硬盘中断
- // printk("down ide req\n");
- down(&ide_ctrl->disk_intr_sem);
+ wait_completion(&ide_ctrl->intr_complete);
// 读数据
if (DISK_REQ_IDENTIFY == r->command) {
volatile void prepare_to_wait(wait_queue_head_t *head, wait_queue_entry_t *wqe, unsigned int state) {
unsigned long flags;
irq_save(flags);
+ // 进程可能等待一个condition满足后被唤醒
+ // 然后又发现这个conditon又不满足了,需要继续wait
+ // 这时候又会把自己加到等待队列里
+ // 所以这里需要加一个判断,如果已经加过了,就不需要再加了,不然会出问题
if (list_empty(&wqe->entry)) {
list_add_tail(&wqe->entry, &head->task_list);
}
set_current_state(state);
+ current->reason = "p_wait";
irq_restore(flags);
}
volatile void __end_wait(wait_queue_entry_t *wqe) {
set_current_state(TASK_READY);
+ current->reason = "e_wait";
unsigned long flags;
irq_save(flags);
list_del_init(&wqe->entry);
//
__wake_up(head, 0); // wake up all
}
-
-volatile void wait_on(wait_queue_head_t *head) {
- DECLARE_WAIT_QUEUE_ENTRY(wait, current);
-
- unsigned long flags;
- irq_save(flags);
-
- current->state = TASK_WAIT;
- current->reason = "wait_on";
-
- list_add_tail(&wait.entry, &head->task_list);
-
- irq_restore(flags);
-
- schedule();
-
- __end_wait(&wait);
-}