マイコンの割り込みをLinux上でシグナルとスレッドを使って再現してみた。
大まかな処理は、マルチスレッドで制御のスレッドとマイコンの処理相当を行うスレッドの2つを作成、
制御側からマイコンの処理相当のスレッドをシグナルで一時停止させ、その間に割り込みハンドラを実行する。
フルのソースコードは以下を参照。
https://github.com/yasuharu/micon_int_on_linux/
まずマイコン側の処理。UARTの受信を意図したもの。
uart_rx_handlerが割り込みハンドラ、micon_mainがマイコン側のメイン処理。
メイン側の処理は、マイコン用のスレッドを作成し、一定期間ごとに割り込みを生成する。
割り込みの生成タイミングは、お好きなタイミングでどうぞ。
シグナルはSIGUSR1とSIGUSR2を使用する。
SIGUSR1はマイコン側の処理をsuspend、SIGUSR2はマイコン側の処理をresumeするために使用する。
micon_thread内で以下の通り初期化する。
1void micon_thread() 2{ 3 struct sigaction sigusr1, sigusr2; 4 5 sigusr1.sa_flags = 0; 6 sigusr1.sa_handler = micon_thread_signal_usr1_handler; 7 sigemptyset(&sigusr1.sa_mask); 8 sigaction(SIGUSR1, &sigusr1, NULL); 9 10 sigusr2.sa_flags = 0; 11 sigusr2.sa_handler = micon_thread_signal_usr2_handler; 12 sigemptyset(&sigusr2.sa_mask); 13 sigaction(SIGUSR2, &sigusr2, NULL); 14 15 micon_main(); 16}
今回のポイントは、以下のコードの部分。
suspend/resumeでマイコン側のスレッドを一時停止させる。
SIGUSRT1のハンドラ(micon_thread_signal_usr1_handler)内では、
sigsuspendを呼んで、SIGUSR2が発生するまで待つ。
割り込みハンドラはメインのスレッド、シグナルのハンドラはマイコンのスレッドと、
それぞれで実行しているコンテキストが違うことに注意が必要。
特にシグナルのハンドラのsigsuspendを実行する前に、割り込みハンドラが実行されないよう、
int_statusで処理待ちを行うようにしている。
(ちなみに、int_statusは本来であればmutexでロックが必要)
割り込みが発生したときの処理をまとめると以下の図になる。
do_irq_handlerはこんな感じ。
int_statusを待つことだけ注意。