softirq、workについてQueue、tasklet学習後のポイントまとめ
18164 ワード
この文書はlinuxバージョンに基づいています:4.14.111
簡単なまとめでsoftirq、work_Queue,taskletの3つの中断下半部の動作原理と区別について,3つの形式の簡単な例を添付した.
一、運行原理①softirq:
softirqリクエストを処理するカーネルスレッドについて:
ksoftirqdの処理も同様に呼び出し__によって行われることがわかる.do_ソフトウェアqはソフトウェアqを実行します.softirqのトリガ方式:1)通過_do_softirqアクティブトリガは、通常、ハード割り込み終了時、すなわちirq_exitは、invoke_を呼び出すこともできます.softirq() -> __do_ソフトブレークをトリガして後半部のISR(Interrupt Service Routines)を実行する.2)ksoftirqdによる受動トリガ;
② work_Queue:カーネルスレッドに依存しています.後で詳しく説明し、ここにリンクを添付します(SPI Flashで駆動中の kthread 関連操作を例に挙げます).
③tasklet:softirqの1つのactionであり、特殊なsoftirqと理解され、softirq_Initで初期化され、そのコールバック関数はtasklet_Actionは、ここでは説明せず、割り込みコンテキストでも実行されます.
二、動作方式の違いsoftirqとtaskletは中断コンテキストで実行され、実行中にsleepスリープ、ブロックなどの操作が発生してはならない、work_Queueはプロセスコンテキストで実行され、スリープ、ブロック、スケジューリングの発生などを行うことができます.
三、テスト例及び運行結果
① softirq:
1)第1部はカーネルの修正です.softirqは静的に作成できるため、修正ファイルは/kernel/softirq.cパッチファイルは以下の通りです.
2)テストモジュールの作成:
3)モジュールを取り付けた後のテスト結果:
② work_queue:
1)テストモジュールの作成:
2) モジュールのインストール後のテスト結果:
③ tasklet:
1)テストモジュールの作成:
2) モジュールのインストール後のテスト結果:
四、文末の総括の下で1つの駆動を書く時、もしこの3種類の仕事の方式を選ぶならば
基本的には、スリープ閉塞の必要性がある場合は、work_queueは唯一の選択です.
そうでない場合はtaskletを使用したほうがいいです.性能の向上に専念しなければならない場合はsoftirqを考慮しますが、使用が難しいので、プログラムの再入力性に注意してください.
簡単なまとめでsoftirq、work_Queue,taskletの3つの中断下半部の動作原理と区別について,3つの形式の簡単な例を添付した.
一、運行原理①softirq:
void __do_softirq(void)
{
int max_restart = MAX_SOFTIRQ_RESTART; ///< 10
struct softirq_action *h;
...
pending = local_softirq_pending(); ///< pending , softirq
__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET); ///< softirq, preempt
while ((softirq_bit = ffs(pending))) {
...
/* action */
h->action(h);
....
}
if (pending) {
/* softirq softirq , restart , 10 */
if (time_before(jiffies, end) && !need_resched() &&
--max_restart)
goto restart;
/* 10 , restart , softirq , */
wakeup_softirqd();
}
...
}
softirqリクエストを処理するカーネルスレッドについて:
static void wakeup_softirqd(void)
{
struct task_struct *tsk = __this_cpu_read(ksoftirqd);
if (tsk && tsk->state != TASK_RUNNING)
wake_up_process(tsk); ///< ksoftirqd
}
static void run_ksoftirqd(unsigned int cpu)
{
local_irq_disable();
if (local_softirq_pending()) {
__do_softirq(); ///< __do_softirq
local_irq_enable();
cond_resched_rcu_qs();
return;
}
local_irq_enable();
}
ksoftirqdの処理も同様に呼び出し__によって行われることがわかる.do_ソフトウェアqはソフトウェアqを実行します.softirqのトリガ方式:1)通過_do_softirqアクティブトリガは、通常、ハード割り込み終了時、すなわちirq_exitは、invoke_を呼び出すこともできます.softirq() -> __do_ソフトブレークをトリガして後半部のISR(Interrupt Service Routines)を実行する.2)ksoftirqdによる受動トリガ;
② work_Queue:カーネルスレッドに依存しています.後で詳しく説明し、ここにリンクを添付します(SPI Flashで駆動中の kthread 関連操作を例に挙げます).
③tasklet:softirqの1つのactionであり、特殊なsoftirqと理解され、softirq_Initで初期化され、そのコールバック関数はtasklet_Actionは、ここでは説明せず、割り込みコンテキストでも実行されます.
二、動作方式の違いsoftirqとtaskletは中断コンテキストで実行され、実行中にsleepスリープ、ブロックなどの操作が発生してはならない、work_Queueはプロセスコンテキストで実行され、スリープ、ブロック、スケジューリングの発生などを行うことができます.
三、テスト例及び運行結果
① softirq:
1)第1部はカーネルの修正です.softirqは静的に作成できるため、修正ファイルは/kernel/softirq.cパッチファイルは以下の通りです.
const char * const softirq_to_name[NR_SOFTIRQS] = {
"HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "IRQ_POLL",
- "TASKLET", "SCHED", "HRTIMER", "RCU"
+ "TASKLET", "SCHED", "HRTIMER", "RCU", "LANCE_TEST"
};
/*
@@ -441,6 +441,7 @@ void raise_softirq(unsigned int nr)
raise_softirq_irqoff(nr);
local_irq_restore(flags);
}
+EXPORT_SYMBOL(raise_softirq);
+static __latent_entropy void softirq_test_action(struct softirq_action *a)
+{
+ printk("This is softirq test.
");
+}
+
void __init softirq_init(void)
{
int cpu;
@@ -652,6 +658,8 @@ void __init softirq_init(void)
open_softirq(TASKLET_SOFTIRQ, tasklet_action);
open_softirq(HI_SOFTIRQ, tasklet_hi_action);
+
+ open_softirq(LANCE_TEST, softirq_test_action);
}
2)テストモジュールの作成:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int softirq_test_init(void)
{
raise_softirq(LANCE_TEST);
msleep(1000);
raise_softirq(LANCE_TEST);
return 0;
}
static void softirq_test_exit(void)
{
}
module_init(softirq_test_init);
module_exit(softirq_test_exit);
MODULE_LICENSE("GPL");
3)モジュールを取り付けた後のテスト結果:
cat proc/softirqs
CPU0 CPU1 CPU2 CPU3
LANCE_TEST: 0 0 0 0
/ # insmod softirq.ko
[ 9544.236966] This is softirq test.
[ 9545.252842] This is softirq test.
② work_queue:
1)テストモジュールの作成:
#include
#include
#include
#include
#include
#include
static struct work_struct lance_work = {0};
static struct workqueue_struct *queue;
void work_queue_cb(void)
{
printk(KERN_EMERG "This is work_queue test.
");
printk("Cur in interrupt context? %s.
", (in_interrupt() ? "Yes" : "No"));
}
static int work_queue_init(void)
{
queue = create_workqueue("work_queue_lance");
INIT_WORK(&lance_work, (typeof(lance_work.func))work_queue_cb);
queue_work(queue, &lance_work);
msleep(1000);
queue_work(queue, &lance_work);
return 0;
}
static void work_queue_exit(void)
{
destroy_workqueue(queue);
}
module_init(work_queue_init);
module_exit(work_queue_exit);
MODULE_LICENSE("GPL");
2) モジュールのインストール後のテスト結果:
/ # insmod work_queue.ko
[12633.889983] This is work_queue test.
[12633.893577] Cur in interrupt context? No.
[12634.917039] This is work_queue test.
/ # [12634.920623] Cur in interrupt context? No.
③ tasklet:
1)テストモジュールの作成:
#include
#include
#include
#include
#include
#include
static struct tasklet_struct tasklet = {0};
static struct timer_list timer = {0};
static void task_func(unsigned long data)
{
printk("This is tasklet test.
");
printk("Cur in interrupt context? %s.
", (in_interrupt() ? "Yes" : "No"));
//msleep(1000); ///<
}
void timer_handler(unsigned long data)
{
tasklet_schedule(&tasklet);
mod_timer(&timer, jiffies+msecs_to_jiffies(2000));
}
static int tasklet_test_init(void)
{
tasklet_init(&tasklet, task_func, 0);
init_timer(&timer);
timer.function = timer_handler;
timer.expires = jiffies + HZ;
add_timer(&timer);
return 0;
}
static void tasklet_test_exit(void)
{
del_timer(&timer);
tasklet_disable(&tasklet);
}
module_init(tasklet_test_init);
module_exit(tasklet_test_exit);
MODULE_LICENSE("GPL");
2) モジュールのインストール後のテスト結果:
/ # insmod tasklet.ko
/ # [12477.508765] This is tasklet test.
[12477.512089] Cur in interrupt context? Yes.
[12479.524783] This is tasklet test.
[12479.528108] Cur in interrupt context? Yes.
四、文末の総括の下で1つの駆動を書く時、もしこの3種類の仕事の方式を選ぶならば
基本的には、スリープ閉塞の必要性がある場合は、work_queueは唯一の選択です.
そうでない場合はtaskletを使用したほうがいいです.性能の向上に専念しなければならない場合はsoftirqを考慮しますが、使用が難しいので、プログラムの再入力性に注意してください.