]> Zhao Yanbai Git Server - kernel.git/commitdiff
锁逻辑优化
authoracevest <zhaoyanbai@126.com>
Sat, 24 Jan 2026 04:46:44 +0000 (12:46 +0800)
committeracevest <zhaoyanbai@126.com>
Sat, 24 Jan 2026 04:46:44 +0000 (12:46 +0800)
include/completion.h
include/wait.h
kernel/completion.c
kernel/wait.c

index a91a4c9678dd43060278f9656f7ad90a03bf1a2b..63468838e6925ab56879cbbb40fe6361479bcbd1 100644 (file)
 #include <wait.h>
 
 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);
 
index ba922fcfd29877753cccb49b7ced7d35eab4ddd2..2833f35ea74afd20fd6347d409e2480166bd6d7f 100644 (file)
@@ -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)) {               \
index d7f14a02b984b2b1fe3bfd4db248aea558b494b4..26023cd978ba4cc8b618f20a52282061d73ba952 100644 (file)
 #include <sched.h>
 
 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);
 }
 
index d301c6a4e1504f4dd38e1f03ee6c6a6b903a49e4..27ecefd01f64af5331c599954320aad8f68e953c 100644 (file)
@@ -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
 }