From: acevest Date: Sat, 24 Jan 2026 04:46:44 +0000 (+0800) Subject: 锁逻辑优化 X-Git-Url: http://repos.zhaoyanbai.com/Mou_128.png?a=commitdiff_plain;h=91889ac1f33ffb1c2549aaa5f923b9cd9c3b4bb1;p=kernel.git 锁逻辑优化 --- diff --git a/include/completion.h b/include/completion.h index a91a4c9..6346883 100644 --- a/include/completion.h +++ b/include/completion.h @@ -12,14 +12,14 @@ #include typedef struct completion { - volatile int done; + unsigned int done; wait_queue_head_t wait; // 仅用于调试 char* name; } completion_t; -#define COMPLETION_INITIALIZER(x) {0, WAIT_QUEUE_HEAD_INITIALIZER(x).wait} +#define COMPLETION_INITIALIZER(x) {0, WAIT_QUEUE_HEAD_INITIALIZER(x.wait)} void init_completion(completion_t* x); diff --git a/include/wait.h b/include/wait.h index ba922fc..2833f35 100644 --- a/include/wait.h +++ b/include/wait.h @@ -38,6 +38,7 @@ void add_wait_queue(wait_queue_head_t* head, wait_queue_entry_t* wq); void del_wait_queue(wait_queue_head_t* head, wait_queue_entry_t* wq); // prepare_to_wait 不会调用schedule +void __prepare_to_wait(wait_queue_head_t* head, wait_queue_entry_t* wqe, unsigned int state); void prepare_to_wait(wait_queue_head_t* head, wait_queue_entry_t* wq, unsigned int state); void __end_wait(wait_queue_entry_t* wq); @@ -47,6 +48,8 @@ void __end_wait(wait_queue_entry_t* wq); // wake_up只唤醒不立即重新调度 void wake_up(wait_queue_head_t* head); +void wake_up_all(wait_queue_head_t* head); + // nr == 0 代表唤醒所有 void __wake_up(wait_queue_head_t* head, int nr); @@ -68,37 +71,13 @@ void __wake_up(wait_queue_head_t* head, int nr); irq_restore(flags); \ void schedule(); \ schedule(); \ + irq_save(flags); \ __end_wait(&__wait); \ + irq_restore(flags); \ } \ } \ } while (0) -#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); \ - while (1) { \ - prepare_to_wait(head, &__wait, TASK_WAIT); \ - if ((condition)) { \ - break; \ - } \ - void schedule(); \ - schedule(); \ - } \ - __end_wait(&__wait); \ - } while (0) -#endif - #define wait_event(head, condition) \ do { \ if ((condition)) { \ diff --git a/kernel/completion.c b/kernel/completion.c index d7f14a0..26023cd 100644 --- a/kernel/completion.c +++ b/kernel/completion.c @@ -11,15 +11,33 @@ #include void wait_completion(completion_t* x) { - wait_event(&x->wait, (x->done != 0)); - x->done--; + uint32_t eflags; + DECLARE_WAIT_QUEUE_ENTRY(__wait, current); + + while (1) { + irq_save(eflags); + if (x->done > 0) { + x->done--; + irq_restore(eflags); + return; + } + + __prepare_to_wait(&x->wait, &__wait, TASK_WAIT); + irq_restore(eflags); + + schedule(); + + irq_save(eflags); + __end_wait(&__wait); + irq_restore(eflags); + } } void complete(completion_t* x) { uint32_t iflags; irq_save(iflags); x->done++; - __wake_up(&x->wait, 1); + wake_up_all(&x->wait); irq_restore(iflags); } diff --git a/kernel/wait.c b/kernel/wait.c index d301c6a..27ecefd 100644 --- a/kernel/wait.c +++ b/kernel/wait.c @@ -19,25 +19,30 @@ volatile void init_wait_queue_head(wait_queue_head_t* wqh) { volatile void prepare_to_wait(wait_queue_head_t* head, wait_queue_entry_t* wqe, unsigned int state) { unsigned long flags; irq_save(flags); + __prepare_to_wait(head, wqe, state); + irq_restore(flags); +} + +volatile void __prepare_to_wait(wait_queue_head_t* head, wait_queue_entry_t* wqe, unsigned int state) { // 进程可能等待一个condition满足后被唤醒 // 然后又发现这个conditon又不满足了,需要继续wait // 这时候又会把自己加到等待队列里 // 所以这里需要加一个判断,如果已经加过了,就不需要再加了,不然会出问题 if (list_empty(&wqe->entry)) { - list_add_tail(&wqe->entry, &head->task_list); + // list_add_tail(&wqe->entry, &head->task_list); + list_add(&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); + // unsigned long flags; + // irq_save(flags); list_del_init(&wqe->entry); - irq_restore(flags); + // irq_restore(flags); } volatile void add_wait_queue(wait_queue_head_t* head, wait_queue_entry_t* wqe) { @@ -77,6 +82,11 @@ volatile void __wake_up(wait_queue_head_t* head, int nr) { } volatile void wake_up(wait_queue_head_t* head) { + // + __wake_up(head, 1); // wake up one +} + +volatile void wake_up_all(wait_queue_head_t* head) { // __wake_up(head, 0); // wake up all }