Pārlūkot izejas kodu

Move bottom-half to workqueue for safe sleep

Based on issue #191 (@trulykyle)'s feedback, the original bottomhalf.c
example was calling msleep() inside a tasklet, which runs in atomic
context and can lead to a kernel crash. This patch moves the time-
consuming work to a workqueue, which runs in process context and allows
sleeping, while preserving the immediate LED control logic in the ISR.

Close #191
Jimmy Ma 2 mēneši atpakaļ
vecāks
revīzija
3682d9e6d5
1 mainītis faili ar 9 papildinājumiem un 8 dzēšanām
  1. 9 8
      examples/bottomhalf.c

+ 9 - 8
examples/bottomhalf.c

@@ -15,6 +15,7 @@
 #include <linux/printk.h>
 #include <linux/printk.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/version.h>
+#include <linux/workqueue.h>
 
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0)
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 10, 0)
 #define NO_GPIO_REQUEST_ARRAY
 #define NO_GPIO_REQUEST_ARRAY
@@ -42,16 +43,17 @@ static struct gpio buttons[] = {
     { 18, GPIOF_IN, "LED 1 OFF BUTTON" },
     { 18, GPIOF_IN, "LED 1 OFF BUTTON" },
 };
 };
 
 
-/* Tasklet containing some non-trivial amount of processing */
-static void bottomhalf_tasklet_fn(unsigned long data)
+/* Workqueue function containing some non-trivial amount of processing */
+static void bottomhalf_work_fn(struct work_struct *work)
 {
 {
-    pr_info("Bottom half tasklet starts\n");
+    pr_info("Bottom half workqueue starts\n");
     /* do something which takes a while */
     /* do something which takes a while */
-    mdelay(500);
-    pr_info("Bottom half tasklet ends\n");
+    msleep(500);
+
+    pr_info("Bottom half workqueue ends\n");
 }
 }
 
 
-static DECLARE_TASKLET_OLD(buttontask, bottomhalf_tasklet_fn);
+static DECLARE_WORK(bottomhalf_work, bottomhalf_work_fn);
 
 
 /* interrupt function triggered when a button is pressed */
 /* interrupt function triggered when a button is pressed */
 static irqreturn_t button_isr(int irq, void *data)
 static irqreturn_t button_isr(int irq, void *data)
@@ -63,8 +65,7 @@ static irqreturn_t button_isr(int irq, void *data)
         gpio_set_value(leds[0].gpio, 0);
         gpio_set_value(leds[0].gpio, 0);
 
 
     /* Do the rest at leisure via the scheduler */
     /* Do the rest at leisure via the scheduler */
-    tasklet_schedule(&buttontask);
-
+    schedule_work(&bottomhalf_work);
     return IRQ_HANDLED;
     return IRQ_HANDLED;
 }
 }