ぶていのログでぶログ

思い出したが吉日

reddish-shell v0.5.0 開発進捗

前回のアップデートからかなり時間が空いてしまったので、最近またちょいちょい触り始めている。 ある程度変更が溜まった、というかブログを書いたほうがモチベーションが上がりそうなのでバージョンをあげてみた。 今後も、ある程度変更が溜まったらバージョンをあげてブログ書くみたいなやり方で当分やってみよとおもう。

前回からのコミット

プロセスグループを使うようにした

前回の記事で少し書いたプロセスグループを実装した。 プロセスグループとはプロセスをグルーピングする機能で、Linuxにおいてはこのプロセスループに対してシグナルを飛ばすことでグループに所属しているすべてのプロセスに透過的にシグナルを送ることができる。 プロセスグループは、 ps xao pid,pgid,comm とかすると確認することができる。 プロセスグループはグループの中で最初に起動したプロセスのPIDにするのが一般的のようだ。 例えば A | B | C みたいなコマンドラインにおいては、AのPIDがプロセスグループID(PGID)になり、BとCもそのPGIDに所属することになる。

プロセスグループに所属させるためにはsetpgid(2)を叩く必要があるのだが、CRubyではProcess#setpgidがあるのだがmrubyにおいてはなかったので実装した。 https://github.com/buty4649/reddish-shell/tree/master/mrbgems/mruby-process-pgrp/src

プロセスグループを使うようにしたのだが、ここでも問題が発生した。 プロセスグループに所属するためには、所属したいPGIDが存在していないといけないのだが、A | B | C というコマンドラインにおいてBやCが起動してsetpgidする前にAの実行が終わってしまうとエラーになるということがあった。 これを回避するためにbashでは、どうもAのプロセスを起動してからAに渡すpipeをreadし続けて、Bが起動したらそのpipeを閉じてreadを終了させるみたいな手法を取っているように見えた。 https://github.com/bminor/bash/blob/76404c85d492c001f59f2644074333ffb7608532/jobs.c#L5089-L5108 これを真似したかったのだが、mrubyにおいてスレッドを使うのはかなり難しいので断念した。

次にkshの実装をみた。こちらはSIGTTINをAに送って、Aを一時停止して各プロセスの起動が終わったら復帰させるみたいな処理になっているように見えた。 https://github.com/ksh2020/ksh/blob/8cf92b281a8d5da075b28e4421ec7ec0ab0de1ce/src/cmd/ksh93/sh/jobs.c#L524-L537

結局、reddishではどうしたかというと・・・忘れた。 実装当時は覚えていたのだけど、この記事を書いている現在ではすっかり忘れてしまってどうしたのかは思い出せない。。 コードを見た感じ、bashやkshのようなことはやっておらずどうしたんだっけかなぁ・・・という感じになっている。 もう少しコードが複雑になってきたりしたら、もしかしたらここらへんバグるかもしれない…。

SIGINTをトラップするスレッドを起動するmgemを作った

前回まではmruby-single-threadを使ってトラップしてたのだが、SEGVしてしまうのでオミットしたと書いた。 これを復活させるために新たにmrb-signal-trapというmgemを作った。 かなりシンプルな作りで、スレッドを起動してsigwaitを呼び出しSIGINTを待ち続けて、SIGINTが飛んできたらプロセスグループに対してkillを送るという作りになっている。 プロセスグループの実装と、mrb-signal-trapの実装で正しくプロセスをCtrl+Cできるようになった。

murby-2.1.2にアップデートした

今までmruby-2.1.0でビルドしていたのだけど、これを2.1.2に上げた。 2.1.2にあげたことでひたすら壊れたとか、大幅な修正もなくてよかった。 アップデートによりmruby-io周りが変更されたようで、mrb_io_filenoの戻り値がintになったり、存在しないfiledescriptorをIO.newするとEBADFになるようになったのでIO.dup2してからIO.newするように変更した。

ジョブコントールのbintestを見直した

起動したプロセスにCtrl+Cを送って停止するかを確認するbintestがある。 今までは、forkして reddish -c signaltest みたいなコマンドを実行してその後にSIGINTを送っていた。 しかしこの方法ではうまく動かなかった。 そこで、PTYモジュールを使ってPTYをreddishに割り当てて操作するように変更した。 ただし、PTYモジュールに変更しただけではうまく動かなかったので、linenoiseを使わないようにするオプション(-i)を追加した。

存在しないコマンドを実行したときにスタックする問題を解決した

このバグいつからあったんだろうなぁ…。