Bläddra i källkod

:wrench: 将软中断更改为不可重入

fslongjin 2 år sedan
förälder
incheckning
f4891cc8a3

+ 3 - 3
kernel/driver/interrupt/apic/apic.c

@@ -479,9 +479,9 @@ void do_IRQ(struct pt_regs *rsp, ul number)
     }
 
     // kdebug("before softirq");
-    // 检测是否有未处理的软中断
-    if (softirq_status != 0)
-        do_softirq();
+    // 进入软中断处理程序
+    do_softirq();
+    
     // kdebug("after softirq");
     // 检测当前进程是否持有自旋锁,若持有自旋锁,则不进行抢占式的进程调度
     if (current_pcb->preempt_count > 0)

+ 1 - 1
kernel/driver/timers/HPET/HPET.c

@@ -66,7 +66,7 @@ void HPET_handler(uint64_t number, uint64_t param, struct pt_regs *regs)
 
         // 若当前时间比定时任务的时间间隔大,则进入中断下半部
         if (container_of(list_next(&timer_func_head.list), struct timer_func_list_t, list)->expire_jiffies <= timer_jiffies)
-            set_softirq_status((1 << TIMER_SIRQ));
+            raise_softirq((1 << TIMER_SIRQ));
 
         // if (current_pcb->pid == 2)
         //     kwarn("timer_jiffies = %ld video_refresh_expire_jiffies=%ld", timer_jiffies, video_refresh_expire_jiffies);

+ 3 - 6
kernel/driver/timers/timer.c

@@ -27,22 +27,19 @@ void timer_init()
 
 void do_timer_softirq(void *data)
 {
-    // if(current_pcb->pid==3)
-    //     kdebug("pid3 timer irq");
+    
     struct timer_func_list_t *tmp = container_of(list_next(&timer_func_head.list), struct timer_func_list_t, list);
 
     while ((!list_empty(&timer_func_head.list)) && (tmp->expire_jiffies <= timer_jiffies))
     {
-        if (current_pcb->pid == 2)
-            kdebug("pid2 timer do");
+        
         timer_func_del(tmp);
         tmp->func(tmp->data);
         kfree(tmp);
         tmp = container_of(list_next(&timer_func_head.list), struct timer_func_list_t, list);
     }
 
-    softirq_ack(TIMER_SIRQ);
-    // printk_color(ORANGE, BLACK, "(HPET%ld)", timer_jiffies);
+    
 }
 
 /**

+ 0 - 1
kernel/driver/video/video.c

@@ -78,7 +78,6 @@ void video_refresh_framebuffer(void *data)
     // 暂时设置一个很大的值作为屏障,防止二次进入该区域(造成#GP)
     video_refresh_expire_jiffies = timer_jiffies + 100000;
     video_last_refresh_pid = current_pcb->pid;
-    softirq_ack(VIDEO_REFRESH_SIRQ);
 
     memcpy((void *)sc_info.fb_vaddr, (void *)sc_info.double_fb_vaddr, (sc_info.length << 2));
     video_refresh_expire_jiffies = cal_next_n_ms_jiffies(REFRESH_INTERVAL);

+ 61 - 11
kernel/exception/softirq.c

@@ -2,17 +2,52 @@
 #include <common/kprint.h>
 #include <process/process.h>
 #include <driver/video/video.h>
-uint64_t softirq_status = 0;
-void set_softirq_status(uint64_t status)
+#include <process/spinlock.h>
+
+static spinlock_t softirq_modify_lock; // 软中断状态(status)
+static volatile uint64_t softirq_pending = 0;
+static volatile uint64_t softirq_running = 0;
+
+void set_softirq_pending(uint64_t status)
 {
-    softirq_status |= status;
+    softirq_pending |= status;
 }
 
-uint64_t get_softirq_status()
+uint64_t get_softirq_pending()
 {
-    return softirq_status;
+    return softirq_pending;
 }
 
+#define get_softirq_running() (softirq_running)
+
+/**
+ * @brief 设置软中断运行结束
+ *
+ * @param softirq_num
+ */
+#define clear_softirq_running(softirq_num)        \
+    do                                            \
+    {                                             \
+        softirq_running &= (~(1 << softirq_num)); \
+    } while (0)
+
+// 设置软中断的运行状态(只应在do_softirq中调用此宏)
+#define set_softirq_running(softirq_num)       \
+    do                                         \
+    {                                          \
+        softirq_running |= (1 << softirq_num); \
+    } while (0)
+
+/**
+ * @brief 清除软中断pending标志位
+ *
+ */
+#define softirq_ack(sirq_num)                  \
+    do                                         \
+    {                                          \
+        softirq_pending &= (~(1 << sirq_num)); \
+    } while (0);
+
 /**
  * @brief 软中断注册函数
  *
@@ -44,21 +79,36 @@ void unregister_softirq(uint32_t irq_num)
 void do_softirq()
 {
     sti();
-    // video_refresh_framebuffer();
-    for (uint32_t i = 0; i < MAX_SOFTIRQ_NUM && softirq_status; ++i)
+
+    for (uint32_t i = 0; i < MAX_SOFTIRQ_NUM && softirq_pending; ++i)
     {
-        if (softirq_status & (1 << i) && softirq_vector[i].action != NULL)
+        if (softirq_pending & (1 << i) && softirq_vector[i].action != NULL && (!(get_softirq_running() & (1 << i))))
         {
-            softirq_vector[i].action(softirq_vector[i].data);
+            if (spin_trylock(&softirq_modify_lock))
+            {
+                // 检测该软中断是否已经被其他进程执行
+                if(get_softirq_running() & (1 << i))
+                {
+                    spin_unlock(&softirq_modify_lock);
+                    continue;
+                }
+                softirq_ack(i);
+                set_softirq_running(i);
+                spin_unlock(&softirq_modify_lock);
+
+                softirq_vector[i].action(softirq_vector[i].data);
+
+                clear_softirq_running(i);
+            }
         }
     }
 
     cli();
-    
 }
 
 void softirq_init()
 {
-    softirq_status = 0;
+    softirq_pending = 0;
     memset(softirq_vector, 0, sizeof(struct softirq_t) * MAX_SOFTIRQ_NUM);
+    spin_init(&softirq_modify_lock);
 }

+ 4 - 13
kernel/exception/softirq.h

@@ -24,20 +24,11 @@
 #define raise_softirq(sirq_num)            \
     do                                     \
     {                                      \
-        set_softirq_status(1 << sirq_num); \
+        set_softirq_pending(1 << sirq_num); \
     } while (0);
 
-/**
- * @brief 清除软中断标志位(需要软中断处理程序手动调用)
- * 
- */
-#define softirq_ack(sirq_num)        \
-    do                                 \
-    {                                  \
-        softirq_status &= (~(1 << sirq_num)); \
-    } while (0);
 
-extern uint64_t softirq_status;
+
 
 struct softirq_t
 {
@@ -63,8 +54,8 @@ void register_softirq(uint32_t irq_num, void (*action)(void *data), void *data);
  */
 void unregister_softirq(uint32_t irq_num);
 
-void set_softirq_status(uint64_t status);
-uint64_t get_softirq_status();
+void set_softirq_pending(uint64_t status);
+uint64_t get_softirq_pending();
 
 /**
  * @brief 软中断处理程序