Selaa lähdekoodia

同步机制--锁(信号量)实现

simon 1 vuosi sitten
vanhempi
commit
70d7060215
9 muutettua tiedostoa jossa 226 lisäystä ja 14 poistoa
  1. 37 0
      device/console.c
  2. 12 0
      device/console.h
  3. 6 4
      kernel/init.c
  4. 4 9
      kernel/main.c
  5. 8 1
      makefile
  6. 86 0
      thread/sync.c
  7. 37 0
      thread/sync.h
  8. 32 0
      thread/thread.c
  9. 4 0
      thread/thread.h

+ 37 - 0
device/console.c

@@ -0,0 +1,37 @@
+#include "console.h"
+#include "../thread/sync.h"
+#include "../thread/thread.h"
+#include "../lib/kernel/print.h"
+
+static struct lock console_lock; // lock
+
+void console_init(void)
+{
+    lock_init(&console_lock);
+}
+void console_acquire(void)
+{
+    lock_acquire(&console_lock);
+}
+void console_release(void)
+{
+    lock_release(&console_lock);
+}
+void console_put_str(char *str)
+{
+    console_acquire();
+    put_str(str);
+    console_release();
+}
+void console_put_char(uint8_t char_ascii)
+{
+    console_acquire();
+    put_char(char_ascii);
+    console_release();
+}
+void console_put_int(uint32_t num)
+{
+    console_acquire();
+    put_int(num);
+    console_release();
+}

+ 12 - 0
device/console.h

@@ -0,0 +1,12 @@
+#ifndef __DEVICE_CONSOLE_H
+#define __DEVICE_CONSOLE_H
+#include "../lib/kernel/print.h"
+
+void console_init(void);
+void console_acquire(void);
+void console_release(void);
+void console_put_str(char *str);
+void console_put_char(uint8_t char_ascii);
+void console_put_int(uint32_t num);
+
+#endif // __DEVICE_CONSOLE_H

+ 6 - 4
kernel/init.c

@@ -2,14 +2,16 @@
 #include "../lib/kernel/print.h"
 #include "interrupt.h"
 #include "../device/timer.h"
+#include "../device/console.h"
 #include "memory.h"
 #include "../thread/thread.h"
 
 void init_all(void)
 {
     put_str("init_all\n");
-    itd_init();    // 初始化中断
-    timer_init();  // 初始化定时器
-    mem_init();    // 初始化内存管理系统
-    thread_init(); // 初始化线程管理系统
+    itd_init();     // 初始化中断
+    mem_init();     // 初始化内存管理系统
+    thread_init();  // 初始化线程管理系统
+    timer_init();   // 初始化定时器
+    console_init(); // 初始化 console
 }

+ 4 - 9
kernel/main.c

@@ -4,6 +4,7 @@
 #include "memory.h"
 #include "../thread/thread.h"
 #include "interrupt.h"
+#include "../device/console.h"
 
 void thread_a_func(void *);
 void thread_b_func(void *);
@@ -27,9 +28,7 @@ int main(void)
     // 主线程会一直执行, 直到被中断或被其他线程强制结束
     while (1)
     {
-        intr_disable();
-        put_str("Main ");
-        intr_enable();
+        console_put_str("Main ");
     }
     return 0;
 }
@@ -40,9 +39,7 @@ void thread_a_func(void *arg)
     char *para = arg;
     while (1)
     {
-        intr_disable();
-        put_str(para);
-        intr_enable();
+        console_put_str(para);
     }
 }
 void thread_b_func(void *arg)
@@ -51,8 +48,6 @@ void thread_b_func(void *arg)
     char *para = arg;
     while (1)
     {
-        intr_disable();
-        put_str(para);
-        intr_enable();
+        console_put_str(para);
     }
 }

+ 8 - 1
makefile

@@ -13,7 +13,8 @@ LDFLAGS = -Ttext $(ENTRY_POINT) -e main -Map $(BUILD_BIN_DIR)/kernel.map
 OBJS = $(BUILD_O_DIR)/main.o $(BUILD_O_DIR)/init.o $(BUILD_O_DIR)/interrupt.o  \
 	$(BUILD_O_DIR)/timer.o $(BUILD_O_DIR)/kernel.o $(BUILD_O_DIR)/print.o   \
 	$(BUILD_O_DIR)/debug.o $(BUILD_O_DIR)/string.o $(BUILD_O_DIR)/bitmap.o  \
-	$(BUILD_O_DIR)/memory.o $(BUILD_O_DIR)/thread.o $(BUILD_O_DIR)/list.o $(BUILD_O_DIR)/switch.o
+	$(BUILD_O_DIR)/memory.o $(BUILD_O_DIR)/thread.o $(BUILD_O_DIR)/list.o  \
+	$(BUILD_O_DIR)/switch.o $(BUILD_O_DIR)/sync.o $(BUILD_O_DIR)/console.o
 
 ################################ C 代码编译 ################################
 $(BUILD_O_DIR)/main.o: kernel/main.c lib/kernel/print.h lib/stdint.h kernel/init.h
@@ -46,6 +47,12 @@ $(BUILD_O_DIR)/thread.o: thread/thread.c thread/thread.h
 $(BUILD_O_DIR)/list.o: lib/kernel/list.c lib/kernel/list.h lib/stdint.h kernel/interrupt.h
 	$(CC) $(CFLAGS) $< -o $@
 
+$(BUILD_O_DIR)/sync.o: thread/sync.c thread/sync.h
+	$(CC) $(CFLAGS) $< -o $@
+
+$(BUILD_O_DIR)/console.o: device/console.c device/console.h
+	$(CC) $(CFLAGS) $< -o $@
+
 ################################ 汇编代码编译 ################################
 $(BUILD_O_DIR)/kernel.o: kernel/kernel.S
 	$(AS) $(ASFLAGS) $< -o $@

+ 86 - 0
thread/sync.c

@@ -0,0 +1,86 @@
+#include "sync.h"
+
+// 初始化信号量
+void semaphore_init(struct semaphore *sem, uint8_t value)
+{
+    sem->value = value;
+    list_init(&sem->waiters);
+}
+// 初始化锁
+void lock_init(struct lock *lock)
+{
+    lock->holder = NULL;
+    lock->holder_repeat_count = 0;
+    semaphore_init(&lock->sem, 1); // acquire 1
+}
+
+// 信号量 down 操作 P
+void semaphore_down(struct semaphore *sem)
+{
+    enum intr_status old_status = intr_disable(); // 关中断,保证原子操作
+    while (sem->value == 0)
+    { // value 为 0, 表示已经被别人持有
+        ASSERT(!elem_find(&sem->waiters, &running_thread()->general_tag));
+        // 当前线程不应该出现在信号量的 waiters 中
+        if (elem_find(&sem->waiters, &running_thread()->general_tag))
+        {
+            PANIC("semaphore_down: blocked thread in waiters list\n");
+        }
+        // 若信号量的值为 0,则当前线程把自己加入等待队列,然后阻塞自己
+        list_append(&sem->waiters, &running_thread()->general_tag);
+        thread_block(TASK_BLOCKED); // 阻塞自己,直到被其它线程唤醒
+    }
+    // value 为 1 或被唤醒后,会执行下面的代码,也就是获得了锁
+    sem->value--;
+    ASSERT(sem->value == 0);
+    intr_set_status(old_status); // enable interrupt
+}
+
+// 信号量 up 操作 V
+void semaphore_up(struct semaphore *sem)
+{
+    enum intr_status old_status = intr_disable(); // 关中断,保证原子操作
+    ASSERT(sem->value == 0);
+    if (!list_empty(&sem->waiters))
+    {
+        struct list_elem *elem = list_pop(&sem->waiters);
+        struct task_struct *thread_blocked = elem2entry(struct task_struct, general_tag, elem);
+        thread_unblock(thread_blocked);
+    }
+    sem->value++;
+    ASSERT(sem->value == 1);
+
+    intr_set_status(old_status); // 恢复之前的中断
+}
+
+// 获取锁
+void lock_acquire(struct lock *plock)
+{
+    // 排除曾经自己已经持有锁但还未将其释放的情况
+    if (plock->holder != running_thread())
+    {
+        semaphore_down(&plock->sem); // 对信号量执行 P 操作,原子操作
+        plock->holder = running_thread();
+        ASSERT(plock->holder_repeat_count == 0);
+        plock->holder_repeat_count = 1;
+    }
+    else
+    {
+        plock->holder_repeat_count++; // 重入次数加 1
+    }
+}
+// 释放锁
+void lock_release(struct lock *plock)
+{
+    ASSERT(plock->holder == running_thread());
+    if (plock->holder_repeat_count > 1)
+    {
+        plock->holder_repeat_count--;
+        return;
+    }
+    ASSERT(plock->holder_repeat_count == 1);
+
+    plock->holder = NULL;
+    plock->holder_repeat_count = 0;
+    semaphore_up(&plock->sem); // 对信号量执行 V 操作,原子操作
+}

+ 37 - 0
thread/sync.h

@@ -0,0 +1,37 @@
+#ifndef __THREAD_SYNC_H
+#define __THREAD_SYNC_H
+#include "../lib/kernel/list.h"
+#include "../lib/stdint.h"
+#include "thread.h"
+#include "../kernel/interrupt.h"
+#include "../kernel/debug.h"
+
+// 信号量结构
+struct semaphore
+{
+    uint8_t value;
+    struct list waiters; // 等待该信号量的线程列表
+};
+
+struct lock
+{
+    struct task_struct *holder;   // 持有该锁的线程
+    struct semaphore sem;         // 用二元信号量实现锁
+    uint32_t holder_repeat_count; // 持有该锁的线程重入的次数
+};
+
+// 初始化信号量
+void semaphore_init(struct semaphore *sem, uint8_t value);
+// 初始化锁
+void lock_init(struct lock *lock);
+
+// 信号量 down 操作 P
+void semaphore_down(struct semaphore *sem);
+// 信号量 up 操作 V
+void semaphore_up(struct semaphore *sem);
+// 获取锁
+void lock_acquire(struct lock *plock);
+// 释放锁
+void lock_release(struct lock *plock);
+
+#endif // __THREAD_SYNC_H

+ 32 - 0
thread/thread.c

@@ -133,6 +133,38 @@ void schedule(void)
     switch_to(cur, next); // 切换线程
 }
 
+// 当前线程将自己阻塞,标志其状态为 status(不可运行状态)
+void thread_block(enum task_status status)
+{ // 只有这三种状态才做阻塞
+    ASSERT((status == TASK_BLOCKED) || (status == TASK_WAITING) || (status == TASK_HANGING));
+    enum intr_status old_status = intr_disable(); // 关中断
+    struct task_struct *cur = running_thread();
+    cur->status = status; // 设置其状态为 status, 设置之前 cur->status == TASK_RUNNING
+    schedule();           // 将当前线程换下处理器
+    //! 待当前线程被解除阻塞后继续运行下面的 intr_set_status
+    intr_set_status(old_status); // 恢复中断
+}
+
+// 解除线程的阻塞状态,标志其状态为 TASK_RUNNING
+// pthread 指需要被接触阻塞的线程
+void thread_unblock(struct task_struct *pthread)
+{
+    enum intr_status old_status = intr_disable(); // 关中断
+    ASSERT((pthread->status == TASK_BLOCKED) || (pthread->status == TASK_WAITING) || (pthread->status == TASK_HANGING));
+    if (pthread->status != TASK_READY)
+    {
+        ASSERT(!elem_find(&thread_ready_list, &pthread->general_tag));
+        if (elem_find(&thread_ready_list, &pthread->general_tag))
+        {
+            PANIC("thread_unblock: blocked thread in ready_list\n");
+        }
+        list_append(&thread_ready_list, &pthread->general_tag); // 加入到队列的最前面,使其尽快得到调度
+        pthread->status = TASK_READY;
+    }
+
+    intr_set_status(old_status); // 恢复中断
+}
+
 // 初始化线程环境
 void thread_init(void)
 {

+ 4 - 0
thread/thread.h

@@ -105,6 +105,10 @@ void init_thread(struct task_struct *pthread, char *name, int prio);
 struct task_struct *thread_start(char *name, int prio, thread_func function, void *func_arg);
 // 任务调度
 void schedule(void);
+// 当前线程将自己阻塞,标志其状态为 status
+void thread_block(enum task_status status);
+// 解除线程的阻塞状态,标志其状态为 TASK_RUNNING
+void thread_unblock(struct task_struct *pthread);
 // 初始化线程环境
 void thread_init(void);