scsh
Table of Contents
reinstall OpenBSD 7.4
前回WSL2を導入したら、VirtulBoxに入れていたOpenBSDが起動途中にハングす る様になった。VBに見切りをつけて、VMWare Playerに再インストールする事 にした。
bsd.mp
インストール時にうっかりしてて、シングルCPU構成でおこなってしまった。 後でそれに気がついて、どうやってマルチCPUにするんだと悩む。再度インス トールかな? まて、bsd.mpを入れれば、どうにかなるか? /etc/rcあたりに、 切り替え用のスイッチでも用意されてる? どちらも外れ馬券。
/usr/src/distrib/miniroot/install.sub
chmod og-rwx /mnt/bsd{,.mp,.rd} 2>/dev/null if [[ -f /mnt/bsd.mp ]] && ((NCPU > 1)); then _kernel=$_kernel.MP echo "Multiprocessor machine; using bsd.mp instead of bsd." mv /mnt/bsd /mnt/bsd.sp 2>/dev/null mv /mnt/bsd.mp /mnt/bsd fi
と言う事で、手動でやったよ。これで無事にマルチCPUになった。
reorder libc
起動中に、libc,crypt,sshd等の再配置が実行されている。これにより、boot時間が 延長される。何とかしたいぞ。そうだ、/etc/rcを見ればいいんだ。
# Re-link libraries, placing the objects in a random order. reorder_libs() { local _error=false _dkdev _liba _libas _mp _ro_list _tmpdir local _relink=/usr/share/relink [[ $library_aslr == NO ]] && return ; } # Read output of reorder_libs co-process and output on console. wait_reorder_libs() { local _line [[ $library_aslr == NO ]] && return while IFS= read -p _line; do echo -n "$_line" done echo } reorder_libs 2>&1 |& sh /etc/netstart start_daemon unwind >/dev/null 2>&1 random_seed wait_reorder_libs :
こんな具合に、並列実行する様に改良されてた。少しはsystemdみたいになっ たな。夢々、systemdなんてのは導入しないで下さい。
で、これを禁止するには、/etc/rc.conf.localに、libraryaslr="NO" を追加 しておくと良い。デフォは
ob$ grep YES /etc/rc.conf # set the following to "YES" to turn them on pf=YES # Packet filter / NAT check_quotas=YES # NO may be desirable in some YP environments library_aslr=YES # set to NO to disable library randomization
coprocess
上で出てきたcoprocessの動作が良く理解できなかったので、実験コードを作 成してみた。reorderは仮に重い処理として4秒の時間浪費。main動作として、 2秒を指定。最後の1秒は、その他の雑多な処理。
#! /bin/sh reorder_libs() { echo start reorder sleep 4 echo end reorder } wait_reorder_libs() { local _line echo start wait while dmy= read -p _line; do echo "$_line" done echo end wait } reorder_libs ### 2>&1 |& echo main work sleep 2 echo main work end wait_reorder_libs sleep 1 echo all done
最初は、rcを模して並行動作(コメント無し)。
ob$ time ./rc.sh main work main work end start wait start reorder end reorder end wait all done 0m05.15s real 0m00.00s user 0m00.10s system
こちらは、コメントを有効にした。並行実行無し。
ob$ time ./rc.sh start reorder end reorder main work main work end start wait ./rc.sh[25]: read: -p: no coprocess end wait all done 0m07.22s real 0m00.00s user 0m00.17s system
折角エラー・メッセージを出してくれているんで、その現場をチェック。
ob$ pwd /usr/src/bin/ksh ob$ fgrep 'no coprocess' * io.c: *emsgp = "no coprocess"; ob$ grep emsgp * io.c:check_fd(char *name, int mode, const char **emsgp) io.c: if (emsgp) io.c: *emsgp = "bad file descriptor"; io.c: if (emsgp) io.c: *emsgp = (fl == O_WRONLY) ? io.c: return coproc_getfd(mode, emsgp); io.c: if (emsgp) io.c: *emsgp = "illegal file descriptor name"; io.c:coproc_getfd(int mode, const char **emsgp) io.c: if (emsgp) io.c: *emsgp = "no coprocess";
man sh じゃなくて、man ksh したら、しっかりと説明されてた。ほぼOpenBSD 固有の機能かな。
Co-processes A co-process, which is a pipeline created with the `|&' operator, is an asynchronous process that the shell can both write to (using print -p) and read from (using read -p). The input and output of the co-process can also be manipulated using >&p and <&p redirections, respectively. :
serial
安心の為に、シリアル接続できる様にしておく。だって、VMWareのコンソールっ て窓がとっても小さいから。
VMWareの編集からシリアルを追加。名前付きパイプ \\.\pipe\mypipename
この端末はサーバーです。接続先はアプリです。起動時に接続をONにする。
対する端末は、TeraTermです。シリアル接続がパイプからって、願ってもない
機能がサポートされてるからね。代替えの端末って存在するのだろうか? 肩
身の狭い世の中だのう。
OpenBSD側は、FAQになってた。ほかの機能も要点が良くまとめられていて好感。
ielm vs eshell
eshellって便利。たとえば、emacs –help とか ruby –help なんてやると、ズラッとヘルプが 表示される(man emacsなんてのは時代遅れなんだな)。前の方を見たいなら、今迄なら、tmuxとかの画面戻るぞを使った りしてたんだ。
それが、eshell上なら、かまわず、emacs –helpしちゃえ。やおら、C-c v し て、view modeに変更しちゃう。そしたら、space/backspace と言う特大 key(英語配列ですけど)で、前進したり後退したりが自在。view modeの解除は、 もう一度 C-c vするだけ。
(global-set-key "\M-," 'pop-tag-mark) ;; replace M-* (define-key mode-specific-map "c" 'compile) ;; C-c c to compile (define-key mode-specific-map "v" 'view-mode) ;; C-c v to toggle view-mode (define-key mode-specific-map "g" 'goto-line) ;; goto line
その他、こんなキーマップを割り当てている。
もう一つ便利なのが、cat fact.el とかして、内容を表示。それをコピペ出来 ちゃう事(勿論、M-w C-yの定番キー操作ね)。後はRETすれば、S式が評価され る。eshellと言いつつ、emacs専用のREPLである、ielm を兼ねているよ。
んな訳で、今日からは、eshellを多用すべし。幸いにも、ielmの遅いモードを 脱却できている(下記の比較(以前やったベンチマーク)を参照)。
(11.260014140000001 125 7.600907907) ;; on ielm (2.605592303 4 0.178970314) ;; on eshell (2.522473842 3 0.133453492) ;; on ksh
scsh
eshellでelispを走らせる事が分かった。ならば、schemeでも出来るはず。そ んなのgoshとかでいいじゃん。まて、それ用にチューニングしたアプリが有っ たはず。
ワーニング多数、エラーが2箇所を乗り越えて起動。
ob$ ./go Welcome to scsh 0.6.6 (King Conan) Type ,? for help. > (define hello "Hello world") > hello "Hello world" > (date) '#{%date} > (time) 1704869327 > (date->string (date)) "Wed Jan 10 15:49:59 2024" > (pid) 99083 > (cwd) "/tmp/scsh-0.6.6"
で、goの正体は?
ob$ cat go #!/bin/sh lib=/tmp/scsh-0.6.6 exec $lib/scshvm -o $lib/scshvm -i $lib/scsh/scsh.image "$@"
scshvmがイメージを動作させるって塩梅なのか。これ、コンパイルした時の チェック用。インストールすれば、scshで利用できる正式版になる。
ああ、そそっかしい事に版が古かったので、最新版で確認。
ob$ ./go Welcome to scsh 0.6.7 (R6RS) Type ,? for help. > (pid) 11619 > (cwd) "/tmp/scsh-0.6.7"
schemeが一つ欲しいと思っていたので、/opt/bin/scshに鎮座させた。
scheme48
scshの土台は、 Scheme48 だ。広告には、
Scheme 48 is an implementation of the Scheme programming language as described in the Revised^5 Report on the Algorithmic Language Scheme. It is based on a compiler and interpreter for a virtual Scheme machine. The name derives from our desire to have an implementation that is simple and lucid enough that it looks as if it were written in just 48 hours. We don't claim to have reached that stage yet; much more simplification is necessary. Scheme 48 is an implementation of the Scheme programming language as described in the Revised5 Report on the Algorithmic Language Scheme [6]. It is based on a compiler and interpreter for a virtual Scheme machine. Scheme 48 tries to be faithful to the Revised5 Scheme Report, providing neither more nor less in the initial user environment. (This is not to say that more isn't available in other environments; see below.)
頑張って48時間で書いたからねってのが由来のようだ。組み込み用にeclって 言うCommonLispが有って、その上にmaximaと言う数式処理システムが構築され てるのと、同じ構図だな。小さいのは良い事だ。隅々まで目がいくからね。
マニュアルをチラ見してたら、楽しいコマンドを発見
> ,dis cons cons 0 (protocol 2) 2 (pop) 3 (make-stored-object 2 pair) 6 (return) > ,dis car car 0 (protocol 1) 2 (pop) 3 (stored-object-ref pair 0) 6 (return) > ,dis list list 0 (protocol 0 +) 4 (make-env 1) 7 (local0 1) 9 (return)
なんとなくVMの作りが想像できる。楽しいシステムだな。 そして、Mixing Scheme 48 and C こんなのもある。 emacsだと、前回だからに、ダイナミック・モジュールに相応するのかな。 憧れの The Scheme (by cisco) にも、同様な物が公開されてた。
Access to POSIX こんなのも有って、scshの基礎になってるんだな。 後は、scheme48にデコレーション(regex とか awk機能、更にnetworking機能)すれば、いいだけ。
核心は、/opt/src/scsh-0.6.7/scheme/vm/arch.scm
scheme48 on ArchLinux
ふと思いたって、64Bitでも動くか確認。いきなりのgdbって所がアレゲです が。。
[sakae@arch scheme48-1.9.2]$ gdb -q scheme48vm Reading symbols from scheme48vm... (gdb) b main Breakpoint 1 at 0xb770: file ./c/main.c, line 15. (gdb) r -i scheme48.image Starting program: /tmp/scheme48-1.9.2/scheme48vm -i scheme48.image [Thread debugging using libthread_db enabled] Using host libthread_db library "/usr/lib/libthread_db.so.1". Breakpoint 1, main (argc=3, argv=0x7fffffffe988) at ./c/main.c:15 15 return_value = s48_initialize(&argc, &argv);
goなんて動かないので、分解してバーチャル・マシンをgdbの餌食にします。 餌はイメージ・ファイル。
(gdb) s s48_initialize (argcp=argcp@entry=0x7fffffffe86c, argv=argv@entry=0x7fffffffe860) at c/init.c:62 62 int argc = *argcp; (gdb) finish Run till exit from #0 s48_initialize (argcp=argcp@entry=0x7fffffffe86c, argv=argv@entry=0x7fffffffe860) at c/init.c:62 main (argc=<optimized out>, argv=<optimized out>) at ./c/main.c:17 17 if (return_value != 0) Value returned is $1 = 0 (gdb) l 12 { 13 long return_value; 14 15 return_value = s48_initialize(&argc, &argv); 16 17 if (return_value != 0) 18 return return_value; 19 else 20 return s48_call_startup_procedure(argv, argc); 21 }
メインはさっぱりしたものです。
(gdb) c Continuing. Welcome to Scheme 48 1.9.2 (made by sakae on 2024-01-14) See http://s48.org/ for more information. Please report bugs to scheme-48-bugs@s48.org. Get more information at http://www.s48.org/. Type ,? (comma question-mark) for help. > Exit Scheme 48 (y/n)? y [Inferior 1 (process 20834) exited with code 01] (gdb) q [sakae@arch scheme48-1.9.2]$ fgrep 'Exit Scheme 48' -r . fgrep: warning: fgrep is obsolescent; using grep -F ./scheme/env/command.scm: ((y-or-n? "Exit Scheme 48" #t)
動いたな。で、終了の問い合わせについて、問い合わせ。徹底的にscmになっ てるんですねぇ。ならばTAGSファイルを作成できるかな。
[sakae@arch scheme48-1.9.2]$ make tags find . -name "*.scm" -o -name "*.c" -o -name "*.h" | etags -
やや、gdbinitが有るぞ。
# # Commands useful for debugging the Scheme48 VM. # #Set a breakpoint at label "raise". #Obtain the proper line number using "egrep -n raise: scheme48vm.c". break scheme48vm.c:5227 display/i $pc :
raise: に網を貼っておくといいよ、と読めるんだけど、家捜ししてもそんな 語句はヒットせず。このファイル自体が、かなり昔のもので、その後のメンテ ナンスがされていないな。これは、作者さんからの挑戦状かしらん。
32bitなOpenBSDに舞台を移して、挑戦してみようかしらん。
make log
scheme48の実行環境が作成されるまでのログ・ファイルあらまし。
: fake/glue.o c/fake/glue.c rm -f c/libscheme48.a; \ ar cq c/libscheme48.a c/scheme48vm-32.o c/extension.o c/free.o c/double_to_stri\ ng.o c/bignum.o c/ffi.o c/external.o c/external-lib.o c/external-init.o c/init.\ o c/scheme48-bibop-heap-32.o c/bibop/page_alloc.o c/bibop/memory_map.o c/bibop/\ areas.o c/bibop/generation_gc.o c/bibop/find_all.o c/bibop/check_heap.o c/bibop\ /utils.o c/bibop/area_roots.o c/bibop/remset.o c/unix/misc.o c/unix/io.o c/unix\ /fd-io.o c/unix/event.o c/unix/time.o c/net/socket.o c/net/address.o c/net/net\ .o c/unix/socket.o c/unix/dynlink.o c/unix/sysexits.o c/fake/glue.o ranlib c/libscheme48.a gcc -rdynamic -pthread -g -O2 -pthread -o scheme48vm c/main.o c/libscheme48.a\ -lnsl -ldl -lm ./build/build-usual-image . \ "`(cd . && pwd)`/scheme" "`pwd`/c" 'scheme48.image' './scheme48vm' \ './build/initial.image-32' ./scheme/env/init-defpackage.scm #{Unspecific} ./scheme/packages.scm ./scheme/more-interfaces.scm : [display-conditions ./scheme/env/dispcond.scm] [command-levels ./scheme/env/user.scm ./scheme/env/command-level.scm] [disclosers ./scheme/env/disclosers.scm] : [usual-features] #{Unspecific} Reading ./build/initial.debug #{Unspecific} #{Unspecific} #{Unspecific} Writing scheme48.image : gcc -o c/srfi-27.so c/srfi-27.o -shared -rdynamic gcc -o c/ffi-test.so c/ffi-test/ffi-test.o -shared -rdynamic gcc -o c/r6rs.so c/r6rs/ieee_bytevect.o c/r6rs/r6rs_externals.o -shared -rdyn\ amic
build/build-usual-image (shell script)
srcdir=$1 share=$2 lib=$3 image=$4 vm=$5 initial=$6 USER=${USER-`logname 2>/dev/null || echo '*GOK*'`} $vm -i $initial -a batch <<EOF ,load $srcdir/scheme/env/init-defpackage.scm ((*structure-ref filenames 'set-global-translation!) "=scheme48/" "$srcdir/scheme/") ,load =scheme48/packages.scm ,load =scheme48/more-interfaces.scm : (set-global-translation! "=scheme48external/" "$lib/") ,user ,build ((*structure-ref package-commands-internal 'new-command-processor) "(made by $USER on $date)" usual-commands built-in-structures more-structures) $image EOF
debug emacs -batch
バッチモードなら、楽しく観察できるに違いない。
emacs -batch -l /tmp/mytest.el
(gdb) bt #0 command_loop () at keyboard.c:1111 #1 0x0057ca34 in recursive_edit_1 () at keyboard.c:744 #2 0x0057cc06 in Frecursive_edit () at keyboard.c:827 #3 0x00578f71 in main (argc=4, argv=0xbffff584) at emacs.c:2625
相変わらず、闇は深いな。
ArchLinux X11
前回の遊び WSL2で、WSLg が、後遺症を残していないか心配。そこで、 OpenBSDのgnuplotでWindows10側にちゃんとグラフを表示してくれるか、確認 する。 自前でgnuplotをコンパイルするのも、かったるいので、pkgから入れた。 ちゃんと描画した。
ArchLinuxはどうか? やはりエラーだ。新ためてぐぐったら、mesaが悪いなんて話が出てた。ならば、改良版 が出てないか? pacman -Syu したら、 mesa-1:23.3.2-2 が、含まれていた。
かくして、ちゃんと動くようになった。基幹の奴でも大チョンボする事が有る のね(だって、人間だもの)。