Udevイベントで長時間プロセスを実行するにはどうすればよいですか?


11

USBモデムが接続されているときにppp接続を実行したいので、次のudevルールを使用します。

ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="16d8",\
    RUN+="/usr/local/bin/newPPP.sh $env{DEVNAME}"

(私のモデムは/devとして表示されますttyACM0

newPPP.sh:

#!/bin/bash
/usr/bin/pon prov $1 >/dev/null 2>&1 &

問題:

udevイベントが発生すると、newPPP.shが実行されているが、newPPP.shプロセスは〜4-5s後に殺されます。ppp接続する時間がありません(そのタイムアウトはダイヤルアップの場合10秒です)。

どうすれば殺されない長い時間のプロセスを実行できますか?

を使ってみましたnohupが、うまくいきませんでした。

システム:Arch Linux

更新

maxschlepzigのおかげここで解決策を見つけました。

私はat nowudevプロセスから切り離されたジョブを実行するために使用します。

しかし、1つの質問は未解決のままです:なぜ機能しnohup、機能し&ないのですか?

回答:


11

systemdサポートを備えたまともなディストリビューションを実行する場合、最も簡単で技術的に最も安全な方法は、デバイスユニットを使用することです。

このようにして、systemdは長時間実行スクリプトを完全に制御し、デバイスがシャットダウン/削除されるとプロセスを適切に終了することもできます-プロセスを切り離すと、プロセスの状態の完全な制御を放棄することになりますそしてその歴史。

さらに、を実行することで、デバイスとそれに接続されてsystemctl status my-ppp-thing.deviceいるサービスのステータスを検査できます。

その他の例と詳細については、このブログ投稿も参照してください。


6

現在、udevはcgroupを使用して、生成されたタスクをシークアンドデストロイします。1つの解決策は、「現時点」または「バッチ」を使用することです。別の解決策は、ダブルフォークを実行して、別のcgroupに「再配置」することです。これはpythonコードの例です(同様のコードは任意の言語で記述できます)。

os.closerange(0, 65535)  # just in case
pid = os.fork()
if not pid:
  pid = os.fork()  # fork again so the child would adopted by init
  if not pid:
    # relocate this process to another cgroup
    with open("/sys/fs/cgroup/cpu/tasks", "a+") as fd:
      fd.write(str(os.getpid()))
    sleep(3)  # defer execution by XX seconds
    # YOUR CODE GOES HERE
sleep(0.1)  # get forked process chance to change cgroup

デバッグ出力は、syslogなどに送信できます。


1
なぜudevは、生成されたプロセスを破壊するためにそのような長さを必要とするのでしょうか?
user30747 2018年

これは、udevによって起動されたプログラムがデーモンをブロックするためだと思います(たとえば、外部ディスプレイのプラグインに接続されたudevルールを使用すると、長時間実行されるプログラムにより、新しいディスプレイが実際に使用されなくなります)。それには独自の技術的根拠があるはずですが、生成されたプロセスがシステムの主要な部分を保持し、強制終了する必要があることを意味します。
2019

2

シェルにはバックグラウンドでコマンドを実行する機能があります。

(

lots of code

) &

アンパーサンドで中括弧でグループ化されたコマンドは、サブシェルで非同期に実行されます。これを使用して、USBモデムを挿入して切り替えたときに自動接続します。約20秒かかり、udevで正常に動作します。


このような状況では、stderr、stdout、およびstderrをリダイレクトすることができます。
mdpc 2013

@mdpcうーん...なぜ?私はこのシナリオでusb_modeswitchがストリームを閉じるのを見ました:exec 1 <&-2 <&-5 <&-7 <&
user42295

1

私はそれをsetsidで動作させるようにしました。udevルールのRUN部分:

RUN+="/bin/bash script.sh"

その後、スクリプトで:

#!/bin/bash
if [ "$1" != "fo_real" ]; then
  /usr/bin/setsid $(/usr/bin/dirname $0)/$(/usr/bin/basename $0) fo_real &
  exit
fi

Rest of script is here....

スクリプトの最初の呼び出しは終了ステータス0で戻りますが、スクリプトの2番目の呼び出しはPPID = 1で実行され続けます。


0

おそらく、その親プロセスが終了し、終了シグナルがその子に伝播し、子プロセスがブロックされないためです(子プロセスがブロックSIGKILLできない場合でも)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.