zzz gosh$

警官に捕まった?

先月は、秋の交通安全週間があった。初日は横断歩道の所に、黄色いジャケットを着たおかあさん方が多数たっていて、黄色い旗で誘導。ちょっと大げさすぎて、恥ずかしかったぞ。

数日して、スクールゾーンの所にある横断歩道を渡ろうとしたら、目の前をすっと軽が通り過ぎた。車が途絶えたので横断。そしたら、少し先で、先程の軽が婦人警官により止められていた。

手前の歩道の所に、白いシャツ、短パンの男性がおられましたが、気がつきませんでしたか? それって、モロにオイラーの事じゃん。運転手のねーチャンは、オイラーの所を睨んでいたみたいに感じたので、さっさと歩を進める。

そしたら、今度は男性警察管に呼び止められた。えっ、歩道を渡るときは、指差し確認を伴い、右側よし、左側よし、右側よしと鉄ちゃんの所作を真似るんだったけ? そして横断中は、バンザイしながら。。。そのどれもやっていない違反者を指導したい?

すみません、横断歩道一時停止の指導を実施してまして、その一環として、誰が被害にあわれたか確認してます。よろしかったら、お名前を教えていただけませんか、ですって。 記録簿をチラ見したら、ざっと10名ぐらいの記入があったぞ。

家に帰って、その事を女房に話すと、朝の忙しい通勤時間帯に徘徊するんじゃないよ、ってたしなめられたぞ。まあ、言われてみればそうだわな。

swapは不要?

前回、二世帯住宅改造でスワップエリアを潰した。そしたら思わぬ弊害がでてきたね。 サスペンドとハイバネートの機能説明を見付けた。archLinuxの人達は、なかなか良い記事を提供してくれるなあ。

オイラーは正直、サスペンドやハイパネートする方法を知らないんだ。何時もシステムを止める時は、shutdown -P now してるからね。

だから、全くswapが裏で使われているなんて思いもしなかったよ。それなのにそれなのに、起動時に、勝手にswapデバイスを探しに行って、無駄時間を取るとは、何たる糞設計と思った次第。

大体、swapさせたら負けよと思っている。メモリー不足でswapを使い出すと、swap in/outの嵐になって、さっぱり先に進まない事を身を持って経験してるからね。

今使ってるdual bootのマシンも元を質せばWindows 7が入っていたやつ。丁度amd64が出回り初めた頃のやつ。amd64な石が載った方はi386に比べて高価だった。さあ、amd64を取るかi386にするか? どうせ金を払うなら、メモリーたっぷりな方が価値あるって判断をしたのさ。

尤も、Windowsの使い道なんて、オイラーの場合は限られているからね。ネットサーフィン(死語だな)するか、仮想PCでリナなりBSDを動かすしかなかった。もう一つ有った、emacsを使ってのWeb用原稿を執筆する事。そうなると、後者の使い方から、メモリーたっぷりは必須要求ってなる訳。

そんなだから、OSインストール時に使いもしないswap領域が取られるのは、なんだかなあって感がある。そういう分っている人も居る訳だから、swapを持っていないシステムも最初から存在する事を折り込んでおいて欲かったぞ。

現に今のi386なマシンでは、メモリーを持て余している。まだ、一度もswapが使われてはいない。DeskTopなんて使っていないからかも知れないけど。

zzz

リナでサスペンドさせるコマンドは知らないけど、FreeBSDなら知ってるぞ。zzzてやつだ。よく外国の漫画で、寝てる人の口からの吹き出しに、zzzて書かれている。いびきをかいている図だな。

パソコンもそうしましょって時は、zzz 分かりやすい。昔はここまで止まりだったけど、今なら、そのコマンドがどう実現されてるか分け入るのだな。

なんと、shellスクリプトでした。

ACPI_SUSPEND_STATE=hw.acpi.suspend_state

if sysctl $ACPI_SUSPEND_STATE >/dev/null 2>&1; then
              exec acpiconf -s $SUSPEND_STATE
elif sysctl $APM_SUSPEND_DELAY >/dev/null 2>&1; then
        exec apm -z

ソースもいいけど、その前にmanするのが原則だろう。仕様書を見てから現物に当たれ、そうじゃないと、ソースの海で溺れるぞ。

man繋がりで、acpi(4)

DESCRIPTION
     The acpi driver provides support for the Intel/Microsoft/Compaq/Toshiba
     ACPI standard.  This support includes platform hardware discovery
     (superseding the PnP and PCI BIOS), as well as power management
     (superseding APM) and other features.  ACPI core support is provided by
     the ACPI CA reference implementation from Intel.

     hw.acpi.supported_sleep_state
             Suspend states (S1–S5) supported by the BIOS.

             S3      Suspend to RAM.  Most devices are powered off, and the
                     system stops running except for memory refresh.

             S4      Suspend to disk.  All devices are powered off, and the
                     system stops running.  When resuming, the system starts
                     as if from a cold power on.  Not yet supported by FreeBSD
                     unless S4BIOS is available.

             S5      System shuts down cleanly and powers off.

どんなモードをサポートしてる?

[sakae@fb /usr/src/usr.sbin/zzz]$ sysctl -n hw.acpi.suspend_state
S3
[sakae@fb /usr/src/usr.sbin/zzz]$ sysctl -n hw.acpi.supported_sleep_state
S3 S4 S5

余計な機能を見付けてしまった。墓標のような名前が出て来たな。バッテリー情報ね。

[sakae@fb /etc]$ acpiconf -i 0
Design capacity:        31680 mWh
Last full capacity:     2210 mWh
 :
Type:                   LION
OEM info:               SANYO

acpiconfの肝は、 acpi_sleep っぽいので探してみる。

[sakae@fb /usr/src]$ grep acpi_sleep -rIl .
./usr.sbin/acpi/acpiconf/acpiconf.c
./share/man/man9/EVENTHANDLER.9
./sys/contrib/dev/acpica/include/actypes.h
./sys/dev/acpica/acpi_lid.c
./sys/dev/acpica/acpi.c
./sys/dev/acpica/acpivar.h
./sys/x86/acpica/acpi_wakeup.c
./sys/compat/linuxkpi/common/src/linux_acpi.c
./sys/xen/interface/platform.h
./sys/arm64/acpica/acpi_wakeup.c

man firstの原則で、唯一引掛ったのを見る。

Kernel Event Handlers
  The following event handlers are present in the kernel:

  acpi_sleep_event
          Callbacks invoked when the system is being sent to sleep.

  acpi_wakeup_event
          Callbacks invoked when the system is being woken up.

acpiって、ハードを制御するやつなんだな。OS屋のマイクロソフト、石屋兼BIOS屋のインテル、パソコンメーカーが数社集って、共通仕様を策定したとな。だから、易しい事も複雑に定義してある。

元ハード屋が考えると、acpiの定義S3なんて、そういう信号が送られてきたら、DRAMの制御と他わずかな制御回路を除いて、通電停止。S4の場合はLANの制御回路を除いて通電停止。S5の場合は、完全に電源遮断。ハードの制御だな。

DRAMの内容をDISKに退避するなんてのは、完全にOS側の仕事だ。ユーザー(とOS)の立場になって、ハイパネートをどう実現したらよいか想像してみる。

zzzでもいいし、決められたボタンを押してもいいけど、ハイパネート要求が発せられた。OSはswap in相当すなわち、メモリーの内容をDISKのswap領域へ退避。なんだか、core dumpを想像しちゃうぞ。そして、おもむろにS4トリガーを発出。これで、パソコンは眠りにつく。

冬眠から目覚める時(レジュームね)は、いわゆるコールドスタートの処理になるな。OSがメモリーに読み込まれていない。だから、DISKに退避してるメモリー状態を復帰するのは、いわゆるローダーが担当する事になろう。

動いていたOSの状態を復帰するだけで済むので、いちいちOSがハードを調べて必要なドライバーをロードするって言う無駄を省ける。ユーザーからしたら、パソコンの蓋を開くだけで、即仕事が出来て、万万歳である。

この便利極まりないacpiも時代の変遷と共に古い仕様になりつつあるらしい。 企業で使われている Windows デバイスの半数以上が Windows 11 のシステム要件を満たさない こんな記事もあるように、ウィンテルの力を持って、世の中のパソコンを陳腐化させ、新しい物に買い換えさせようと言う魂胆が進行中です(それが資本主義ってやつ)。

ただね、余りにも強力にやっちゃうと、滅びるぞ。ウィルスは段々と弱毒化すると言う。余り強力にしちゃうと、宿主が死んでしまって、拡散出来無くなるためらしい。ウィンテルもウィルスを見習えばいいのにね。

memory rich

メモリーたっぷりが嬉しい事例が出てきたので、改めてクリーンな状態のOSで実行してみる。

2G 109908個のFreeBSDソース群を全文検索し、メモリーの使われ方をみてみます。下記は実行前のtopの報告の一部

Mem: 33M Active, 3304K Inact, 137M Wired, 66M Buf, 3637M Free
Swap: 4096M Total, 4096M Free

初めての実行

[sakae@fb /usr/src]$ time grep acpi_sleep -rIl .
  :
real    2m4.382s
user    0m10.964s
sys     0m6.279s

たっぷり有った自由エリアがごっそり使われています。2G程減っているので、読み込んだデータが一時保管されてるのでしょう。

Mem: 33M Active, 2023M Inact, 271M Wired, 85M Buf, 1484M Free
Swap: 4096M Total, 4096M Free

二回目の実行

[sakae@fb /usr/src]$ time grep acpi_sleep -rIl .
  :
real    0m15.349s
user    0m10.514s
sys     0m4.747s

DISKから読み込むよりメモリーからの読込みの方が圧倒的に速い。

[sakae@fb /usr/src]$ time find . -type f | xargs grep -l acpi_sleep
  :
real    0m16.351s
user    0m10.866s
sys     0m5.025s

昔、好んで使ってた、パイプ接続でもやってみた。単独でやるより若干遅いな。 これ以上速く実行するには、専用のMakefileを作って、make -j 4 とか必要です。勿論、i386なマシンでは駄目だけどね。まて、amd64でも駄目だぞ。そんなググルの真似事は簡単に出来無いっしょ。

try zzz

ここまでzzzの仕組みが分かったら、試してみたい。人生初かな。

sync   ;; for me
sync   ;; for you
sync   ;; for God
zzz

もしもの為のお守り呪文を唱えてから、お休みモードに突入。画面がブラックアウトした。電源ボタンがフラッシュしてる。ラップトップの脇の三日月インジケータが点灯した。どうやら成功。

復帰は、電源ボタンを一度軽く押すだけだな。あれれ、復帰しないぞ。。ってんで、少々長押ししたら、電源が本当に切れちゃった。しょうがないので、再起動。

ガーン、シングルユーザモードに落ちた。DISKが壊れているんで、run fsck しなさいですって。呪文は効かなかった訳ね。fsckしてから、安全の為に再起動。でも、まだDISKが壊れているって。こうなったら、パソコンと自分の頭も冷やそう。カッカするな。

翌日に再起動するも、やっぱりDISK壊れてるのつれない表示。でもよく見たら、壊れているのは、FreeBSDが入っている方じゃなくて、前回の二世帯住宅改装でやった、ext2の方。

なんだって事で、debianを起動して、ext2のデバイスをunmount。そしてfsckを実施。ちょびっと壊れていて、直ぐに修復は終わった。

思い込みって怖いね。てっきりFreeBSDのDISKがおかしくなってるって先入観で見てた。それから、心の片隅にext2はfsck出来ないっていう前回の最後に書いた事例のすり込があったんだろうね。

兎も角、復旧して何よりだった。昔の事をふと思い出した。Windows7が入っていた時、サスペンドを試した事があった。復帰が出来なくて、やはり電源ボタンを長押し。再起動時に、Windowsがセーフモードで起動した事をね。

どうも、サスペンド/レジュームは、オイラーにとって鬼門の操作であるな。多少起動時間が伸びても、そんなの誤差のうちって鷹揚に構える事にしよう。

ああ、/etc/rc.suppendなんてスクリプトを見ると

/usr/bin/logger -t $subsystem suspend at `/bin/date +'%Y%m%d %H:%M:%S'`
/bin/sync && /bin/sync && /bin/sync
/bin/sleep 3

/bin/rm -f /var/run/rc.suspend.pid

ってな具合に、今だにおまじないが生きていて、思わず にやりとしてしまったぞ。それから、3秒待つのもBSD的だなあ。

gosh$

久し振りにgaucheのheadを入れてみた。

sakae@deb:/tmp$ gosh -V
Gauche scheme shell, version 0.9.11_pre1 [utf-8,pthreads], i686-pc-linux-gnu
(version "0.9.11_pre1")
(command "gosh")
(scheme.id gauche)
(languages scheme r5rs r7rs)
(encodings utf-8)
(website "https://practical-scheme.net/gauche")
(build.platform "i686-pc-linux-gnu")
(build.configure "--prefix=/home/sakae/MINE" "--enable-multibyte=utf-8")
(scheme.path "/home/sakae/MINE/share/gauche-0.98/site/lib" "/home/sakae/MINE/share/gauche-0.98/0.9.11_pre1/lib")
(gauche.threads pthreads)
(gauche.net.tls axtls)

着々と次の版の準備が進んでいますなあ。それより、気になるのが、Gauche scheme shell, って宣言。昔の版でもこうだったけど、今迄気付かなかった。

sakae@deb:/tmp$ gosh
gosh$ (cons 1 2)
(1 . 2)
gosh$ (exit)
(1 . 2)
sakae@deb:/tmp$

で、実感として、いやがおうでも気付いたよ(promptがgosh$)。今後、gaucheをlogin shellにしてもいいよって、さりげなく訴えている。

gosh$ , sh ls
config.log        Makefile     mine.gpd   minelib.stub  mine.so        test.scm
configure         Makefile.in  mine.h     mine.o        package.scm    VERSION
configure-compat  mine.c       minelib.o  mine.scm      test-mypid.sh
gosh$ ,sh ls | wc
config.log     17      17     172

ちょっとごみが出てくる場合が有るなあ。使ってる端末との兼ね合いなのかな。ああ、原因判明、rlwrapと併用すると、こういう症状になるのね。

sakae@deb:~$ /home/sakae/MINE/bin/gosh
gosh$ (cons 1 2)
(1 . 2)
gosh$ (exit)
sakae@deb:~$ rlwrap /home/sakae/MINE/bin/gosh
gosh$ (cons 1 2)
(1 . 2)
(1 . 2)
                         ;; (exit) したけど、消えてる
sakae@deb:~$

0.9.10な版でも確認

sakae@deb:~$ rlwrap /usr/bin/gosh
(cons 1 2)
(1 . 2)
(exit)
sakae@deb:~$

プロンプトが消えるな。昔からこうだっけ?

sakae@deb:~$ rlwrap -v
rlwrap 0.43

Debian 11にした時、版が上って挙動が変った? こういう時はFreeBSDでも確認してみる。

[sakae@fb ~]$ rlwrap -v
rlwrap 0.45.2
[sakae@fb ~]$ rlwrap gosh
gosh> (cons 1 2)
(1 . 2)
gosh> (exit)

[sakae@fb ~]$

これが正しい挙動と思う。まるで、小姑だな、いやみな奴だな。

gosh with gdb

自前でインストールしたんで、ちゃんとgdbにもかかるはず

sakae@deb:/tmp/mine$ gdb -q gosh
Reading symbols from gosh...
(gdb) b resf
Function "resf" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (resf) pending.
(gdb) r
Starting program: /home/sakae/MINE/bin/gosh
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
gosh$ (use mine)
gosh$ (resf 1e-6 500e-12)

Breakpoint 1, resf (l=9.9999999999999995e-07, c=5.0000000000000003e-10)
    at ./mine.c:9
9         double tmp =  6.283185307179586 * sqrt(l * c);

呼出の履歴確認

(gdb) bt
#0  resf (l=9.9999999999999995e-07, c=5.0000000000000003e-10) at ./mine.c:9
#1  0xb714d3b3 in minelib_resf (SCM_FP=0x95178, SCM_ARGCNT=2, data_=0x0)
    at ./minelib.stub:9
#2  0xb7bb2b86 in run_loop () at ./vmcall.c:192
#3  0xb7bc68e5 in user_eval_inner (
    program=program@entry=0xb7e4a5c0 <internal_apply_compiled_code>,
    codevec=codevec@entry=0xbffff3d8) at vm.c:1580
#4  0xb7bc76df in apply_rec (nargs=<optimized out>, proc=0xb72352d0,
    vm=<optimized out>) at vm.c:1699
#5  Scm_ApplyRec (proc=0xb72352d0, args=args@entry=0x20b) at vm.c:1719
#6  0xb7bc7d4f in safe_eval_wrap (kind=kind@entry=1, arg0=arg0@entry=0xb,
    args=args@entry=0xb, cstr=0x4052c2 "(read-eval-print-loop)",
    env=0xb7f31180 <userModule>, result=0x0) at vm.c:1852
#7  0xb7bc7e34 in Scm_EvalCString (
    expr=expr@entry=0x4052c2 "(read-eval-print-loop)",
    env=0xb7f31180 <userModule>, packet=packet@entry=0x0) at vm.c:1885
#8  0x004043c5 in enter_repl () at main.c:753
#9  0x00402da5 in main (ac=1, av=0xubffff644) at main.c:896

少し上に登ってみる

(gdb) up
#2  0xb7bb2b86 in run_loop () at ./vmcall.c:192
192             VAL0 = SCM_SUBR(VAL0)->func(ARGP, argc, SCM_SUBR(VAL0)->data);
(gdb) l
187                 for (; i<argc; i++, ap++) SCM_FLONUM_ENSURE_MEM(*ap);
188             }
189     #endif
190
191             SCM_PROF_COUNT_CALL(vm, VAL0);
192             VAL0 = SCM_SUBR(VAL0)->func(ARGP, argc, SCM_SUBR(VAL0)->data);
193             /* the subr may have substituted pc, so we need to check
194                if we can pop the continuation immediately. */
195             if (TAIL_POS()) RETURN_OP();
196             CHECK_INTR;
(gdb) c
Continuing.
7117625.434171771
gosh$ resf
#<subr (resf l c)>

モジュールに定義した手続もgaucheを成す手続と同等の扱いでした。昔のrubyで拡張を作る時に比べたら、簡単になってる。まて、GCの扱いがどうのこうのとrubyの時は蘊蓄を垂れる人が沢山いたけど、gaucheの場合はどうよ。

gosh$ vs. gosh>

今迄の伝統的プロンプトが変った。その仕組みがどうなってるか追ったら、interactive.scmに

;; The variable *read-edit* is #t by default, #f if env var
;; GAUCHE_NO_READ_EDIT is set.  It is also controlled by -fread-edit or
;; -fno-read-edit flag.
(define-values (%prompter %reader %line-edit-ctx)
  (receive (r rl skipper ctx)
      (if (with-module gauche.internal *read-edit*)
        (make-editable-reader (^[] (default-prompt-string "$"))
                              (get-history-filename))
        (values #f #f #f #f))

こんな具合に定義されてた。コメント通りに試してみると、確かにそのようになる。

sakae@deb:~$ MINE/bin/gosh -fno-read-edit
gosh> (exit)
sakae@deb:~$ MINE/bin/gosh
gosh$ (exit)

-vの説明では

read-edit
                enable input-editing mode, if terminal supports it.
no-read-edit
                disable input-editing mode.

ターミナルのサポートってncursesぐらいなのかな? Windowsの腐った端末を使ってる人向けの注意事項?

sakae@deb:~$ MINE/bin/gosh -fno-read-edit
gosh> (cdr
  '(a b c))^P

(cdr で、書き始めたけど、気が変って、cadr にしようとしたけど、出来無い。

gosh$ (car (cdr
......'(a b c)))
b

それに対して、一行戻って、冒頭にcarを追加してから、S式を完成させるなんて事が、お手軽に出来た。

この機能が追加されたんで、rlwrapとの相性が悪くなったのね。ってか、rlwrapは引退勧告か。まて、補完はいつ入るのだろう? rlwrapで補完を使ってるから、これはまずい事になったな。当分の間、-fno-read-edit を付けて、昔に戻っておこうかな。

早くchez schemeみたいに補完を組み込んで欲しいぞと。

--------------------------------------------------------------------------------
open-input-file         open-input-output-file  open-input-string
--------------------------------------------------------------------------------
> (open-input-

当然、schemeは、S式の編集がgaucheみたいに出来るようになってる。

gosh$ ,a prompt
%prompter                      (*gauche.interactive)
:prompt                        (keyword)
default-prompt-string          (*gauche.interactive)
gosh$ (default-prompt-string)
 *** ERROR: unbound variable: default-prompt-string
Stack Trace:
_______________________________________
  0  (default-prompt-string)
        at "(input string port)":1
  1  (eval expr env)
        at "/home/sakae/MINE/share/gauche-0.98/0.9.11_pre1/lib/gauche/interactive.scm":336

これは、綴り間違い? それともオイラーが根本的な間違いをしてる?

ふと考えたら、,a は、モジュールからの非輸出品も、包み隠さずに見せてくれてるんだろうね。それに気がつかないオイラーは阿呆。%xxx とか、*yyy みたいのを見て察しなさいよ。

,a read-eval
read-eval-print-loop           (gauche)
read-eval-print-loop           (gauche.interactive)

同じ手続が2つのモジュールに有るな。どちらが使われる? それは兎も角、gauche.interactiveの頭に * がついていないので、正規の輸出品だな。大手を振って使えるぞ。

そういえば、最近面白い本を読んだ。紅茶スパイってやつ。中国は昔、茶の産地。緑茶や紅茶の原料になる苗木や種、製法は門外不出。おかげで、東インド会社は、多額の費用を払って、輸入する必要があった。

そこで、東インド会社は、プラント・ハンターを雇って、茶の苗木等を、中国から不正に盗み出す計画をたてた。英国人は高級官史に変装して、中国の奧深くへ潜入。

最初は、緑茶を狙った。でも、製法を見てびっくり。色鮮やかにする為、添加品が使わていた。 この添加物も盗み出し、パリ万博に出品した所、緑茶の人気は急低下。同時に送った苗木も、輸送のまずさから、ほとんど枯れてしまった。

再挑戦、今度は紅茶に的を絞る。なんとか種とかも盗み出す事に成功。長い航海での輸送に耐えられるように、携帯用の温室箱を発明。それで上手く、インドのダージリン地方に移送成功。同時に、中国人の職人も何とか、出稼ぎに連れ出す事に成功。

かくして、英国は、緑茶の国ではなく、紅茶の国になりましたとさ。そんな歴史があったなんて、初めて知ったよ。


This year's Index

Home