🪄 ホットスポット安定化の魔法 ― 第一の魔法 ― 子プロセスを呼ばない魔法(TGIFChanger-Py 開発記、魔法シリーズ)
子プロセスを呼ばない魔法 ― 緑を赤に変える呪いを解く

TGIFChanger-Py 開発記、魔法シリーズの一本目。いちばん手こずって、いちばん効果が大きかった「解呪」から始めます。
かかっていた呪い
Pi-Star / WPSD のホットスポットで tgif_daemon.py を動かしていると、ダッシュボードの DMR Net インジケータが緑から赤にときどき落ちる。落ちれば当然 TGIF ネットワークから切れ、再接続にしばらくかかる。GPIO で外部 LED やリレーを叩く処理を入れてから明らかに頻度が上がった ― そんな心当たりがありました。Pi Zero のように非力な機種ほど呪いが濃く出る。これがヒントでした。
呪いを追う
GPIO の HIGH/LOW を、当時は gpioset –mode=wait を subprocess.Popen で起動して制御していました。つまり GPIO を一回叩くたびに子プロセスを fork/exec で召喚しているわけです。
# 旧き呪文(呪いの元)
proc = subprocess.Popen(
["gpioset", "--mode=wait", chip, f"{pin}=1"]
)Pi-Star/WPSD 上では MMDVMHost と DMRGateway が常時タイトなタイミングで動いています。そこへ daemon が頻繁に子プロセスを呼び出すと、わずかな CPU スパイクとスケジューリングの乱れが MMDVMHost のネットワーク処理を圧迫し、キープアライブを取りこぼして「切断」と判定される ― という筋でした。非力な Pi ほど出やすいのと符合します。
呪いの正体
GPIO を叩くために毎回プロセスを召喚していたことそのものでした。pinctrl を subprocess.run で呼ぶ箇所も同罪です。
解呪の魔法
子プロセスを一切召喚せず、GPIO はすべてライブラリ関数の直接詠唱に置き換えました。fork() をゼロにする、という方針です。
# 新しき魔法:libgpiod を直接詠唱する(召喚ゼロ)
import gpiod
chip = gpiod.Chip("gpiochip0")
line = chip.get_line(pin)
line.request(consumer="tgifchanger", type=gpiod.LINE_REQ_DIR_OUT)
line.set_value(1) # HIGH
line.set_value(0) # LOWこれを tgif_daemon.py v2.4.0 に封じ込めました。導入は基本的にファイル差し替えだけ、sudo apt install python3-libgpiod を入れておくとより確実、という形にしてあります。差し替え後、緑が赤に落ちる呪いはほぼ消えました。
魔導書に記す
常時稼働のリアルタイム処理の隣で、むやみにプロセスを召喚してはいけない。 CLI ツールを subprocess で呼ぶのは手軽な呪文ですが、唱える頻度が高いとそのコストが本体に跳ね返ります。ライブラリに直接詠唱できる術があるなら、最初からそれを使うべきでした。
次の魔法は、この解呪を「全 Pi 対応」でやろうとして幻惑にはまった話です。
📝 執筆:JJ2TAB(尾張旭 DMR デジピーター 管理人)
🏛 JJ2YYK あいちデジタルコミュニケーションハムクラブ