日記(2023年11月11日)

Sat Nov 11 09:02:05 JST 2023 (modified: Sat Nov 11 17:36:33 JST 2023)
views: 1880, keywords:日記, 自作シェル この記事は最終更新日が1年以上前のものです。

 査読ばっかりで、あまりにも査読したくなくてこれを記しております。

シェル芸勉強会

12月16日やります!スケジュールと墓穴を開けて待っててください!たぶん都内某所です。

Rustでクレートを使ってシグナルを非同期で受けようとするとファイル記述子を使いやがる

 最近の一番の悩みで、ctrlcを使っても、signal-hookを使っても、非同期処理でパイプやソケットを使ってしまうため、本来ユーザーのために開けておく必要のある3番や4番のファイル記述子を使ってしまいます。シェルを作っているのに、そんな若い番号のファイル記述子を勝手に使ってもらっては困るんですが、ほかによい方法が見つかりません。たぶんmainに入ってすぐに3〜9を使い潰してからスレッドを動かして、3〜9を閉じればなんとかなりそうですが、それでもユーザーの知らないファイル記述子が/proc/$$/fdの下に見えたら嫌なわけで、どうしようかと。Rustだとどうしてもそうしないとだめなんですかね?

 一応、これが連載で作っているシェルをSIGCHLDに非同期で反応できるようにしたバージョンへのリンクです(正確にはmain.rsへのリンクで、ここにSIGCHLDを待っている記述があります。)。なにかピンと来たらご一報を。

追記

 先人が全く同じことで悩まれておりました。後追いで似たことをしてしまっておりいつも恐縮しておりますです。

追記2

 上記の「たぶんmainに入ってすぐに3〜9を使い潰してからスレッドを動かして、3〜9を閉じればなんとかなりそうですが、」をやってみました。

44 fn run_childcare(core: &mut ShellCore) { //SIGCHLDを補足するスレッドを立ち上げる関数
   45     for fd in 3..10 { // FD3〜9を使って塞いでしまう。
   46         unistd::dup2(2, fd).expect("sush(fatal): init error");
   47     }
   48
   49     let jt = Arc::clone(&core.job_table);
   50     thread::spawn(move || {
   51         let mut signals = Signals::new(vec![SIGCHLD])
   52                           .expect("sush(fatal): cannot prepare signal data");
   53
   54         for fd in 3..10 { // 無限ループに入る前にFD3〜9を開放
   55             unistd::close(fd).expect("sush(fatal): init error");
   56         }
   57
   58         loop {
   59             thread::sleep(time::Duration::from_secs(1));
   60             for signal in signals.pending() {
   61                 check_signal(signal, &jt);
   62             }
   63         }
   64     });
   65 }

 できました。signal-hookのファイル記述子が10と11になってます。

🍣 ls -l /proc/112159/fd
   合計 0
   lrwx------ 1 ueda ueda 64 11月 11 17:13 0 -> /dev/pts/2
   lrwx------ 1 ueda ueda 64 11月 11 17:13 1 -> /dev/pts/2
   lrwx------ 1 ueda ueda 64 11月 11 17:13 10 -> 'socket:[1070478]'
   lrwx------ 1 ueda ueda 64 11月 11 17:13 11 -> 'socket:[1070479]'
   lrwx------ 1 ueda ueda 64 11月 11 17:13 2 -> /dev/pts/2
   lrwx------ 1 ueda ueda 64 11月 11 17:13 255 -> /dev/pts/2

しかし、これフォークしたらまずいんじゃなかろうか。ということで検証してみました。自分で作ってるシェルで(sleep 1000)して、他の端末からlsで確認します。

$ ls -l /proc/113809/fd
   合計 0
   lrwx------ 1 ueda ueda 64 11月 11 17:31 0 -> /dev/pts/2
   lrwx------ 1 ueda ueda 64 11月 11 17:31 1 -> /dev/pts/2
   lrwx------ 1 ueda ueda 64 11月 11 17:31 10 -> 'socket:[1083209]'
   lrwx------ 1 ueda ueda 64 11月 11 17:31 11 -> 'socket:[1083210]'
   lrwx------ 1 ueda ueda 64 11月 11 17:31 2 -> /dev/pts/2
   lrwx------ 1 ueda ueda 64 11月 11 17:31 255 -> /dev/pts/2
   $ ls -l /proc/113837/fd
   合計 0
   lrwx------ 1 ueda ueda 64 11月 11 17:31 0 -> /dev/pts/2
   lrwx------ 1 ueda ueda 64 11月 11 17:31 1 -> /dev/pts/2
   lrwx------ 1 ueda ueda 64 11月 11 17:31 10 -> 'socket:[1083209]' #同じID。アカン
   lrwx------ 1 ueda ueda 64 11月 11 17:31 11 -> 'socket:[1083210]'
   lrwx------ 1 ueda ueda 64 11月 11 17:31 2 -> /dev/pts/2
   lrwx------ 1 ueda ueda 64 11月 11 17:31 255 -> /dev/pts/2

だめです。サブシェルがフォークするまえに一度止めないといけません。(そして、サブシェルをつくるときに再びFD3〜9を塞がないといけません。)

 パイプやソケットを使うというのは、あまり良くないアイデアなんじゃないかな〜と。(でも自分で解決しようとすると大変なので、あまり強くも言えず・・・)

ノート   このエントリーをはてなブックマークに追加 
 

prev:Bashのファイル記述子255について next:日記(2023年11月15日)

やり散らかし一覧

記事いろいろ