セット、クリア、テストができる)MachineクラスメモMachineで利用されるOP_xxxという定数は、MIPSのオペコードそのものではなく、変換テーブルを使って変換した後の定数値。システムコールは例外を発生させることで処理されるが、Halt以外の処理は実装されていない。exception.ccのExceptionHandlerが呼び出される。threadsディレクトリを読むNachosのエントリポイントはthreads/main.ccのmain関数。OSとしての処理の中心はthreadsディレクトリ内のファイルで実装されているようなので、このあたりから見ていく。Thread("main")なども)する。コマンドラインオプションに応じたテストの類も行う。Cleanup関数を呼び出してその中のExit(0)で終了する。machineState[MachineStateSize]メンバは場所を変えるなと書かれている。あと、スタックの容量にも気をつける。Threadクラスのpublicメソッドコンストラクタはデバッグ用の名前を引数にとり、nameに設定する。statusをJUST_CREATEDにする以外は、NULLに設定する。currentThreadの場合はスタックの解放が行えないため不正である。スタックの解放にはDeallocBoundedArray関数を用いる。Forkメソッドは引数にとった関数をスレッドで走らせる。callerとcalleeが同時に動作実行される事を許す。scheduler->ReadyToRun(this)でスケジューラーに登録する。Yieldメソッドは他に実行可能なスレッドがあれば、CPUを放棄させる。その場合はscheduler->ReadyToRunメソッドで実行可能プロセスのリストにCPUを放棄したスレッドを追加する。Sleepメソッドはスレッドを眠らせ、CPUを放棄させる。Yieldと異なり、スレッドはブロック状態になるので実行可能リストには追加されない。他に実行可能スレッドが無い場合はInterrupt::Idleメソッドを呼び出し続ける。Finishメソッドはスレッドの実行を終了する。ThreadRootから処理終了時に呼ばれる。threadToBeDestroyedにスレッドをセットしSleepする。実際にスレッドが解放されるのは次回のscheduler->Run()中である。CheckOverflowメソッドはスタックがオーバーフローしているか確認する。stackの値がStackAllocateメソッドでセットしたSTACK_FENCEPOSTか確認することでオーバーフローが起きたかどうかをチェックする。setStatusメソッドはスレッドの状態を設定する。getNameメソッドはデバッグ用のスレッドの名前(コンストラクタで設定)を返す。Printメソッドはスレッドの名前を表示する。SaveUserStateメソッドはユーザプログラムを動作させているmachineのレジスタを保存する。machine->ReadRegister(i)RestoreUserStateメソッドはユーザプログラムを動作させているmachineのレジスタを復元する。スタックの底.mainスレッド(Initializeで作られるスレッドか)はNULL。state(カーネルコード実行中とユーザコード実行中は別に保存するため)ThreadクラスprivateメソッドStackAllocateメソッドはForkメソッド内部で使われ、スタックの確保と初期設定を行う。スタックはAllocBoundedArray関数によって確保される。AllocBoundedArrayはスタックの前後に1ページサイズ(getpagesizeの返り値)ずつ余分に領域を確保する。4とされているが、-4は大事をとってるだけらしい。スタックにはSWITCH()でThreadRootを呼び出すための値を積んでいる。machineStateに呼び出す関数やその引数などを設定する。ThreadRootはアセンブラルーチン。StartupPc,InitialPc,WhenDonePcレジスタの指す関数を順に実行する。WhenDonePCでthread->Finish()が呼び出されるはずなので、そのあとに処理は続かない。i386ではInitialPCはESI,InitialArgはEDX,WhenDonePCはEDI,StartupPCはECXである。ThreadRootが呼び出された時点でこれらのレジスタにはStackAllocateで設定した値がセットされている。SWITCHでスレッド先頭のmachineStateから読み込まれるのだろう。machineState[InitialPC]はESI(%thread)というイメージ。stackTopの分(4バイト)の差だろう。ECX=12.Schedulerクラススケジューラー。スレッドの切り替えはswitch.sのSWITCH手続きで行う。SchedulerクラスpublicメソッドコンストラクタはreadyListを初期化する。デストラクタはreadyListを解放する。ReadyToRunメソッドはスレッドを実行可能状態にし、実行可能スレッドのリストに追加する。thread->setStatusでREADYをセットし、readyList->Append(thread)で最後尾にスレッドを追加する(エンキュー)。FindNextToRunメソッドは次に実行すべきスレッドを返す。実行可能なスレッドが無ければNULLを返す。readyList->Remove()の返り値を返している(デキュー)。Runメソッドは引数に指定したスレッドを操作させる。切り替わる前のスレッドの状態はRunメソッドが呼び出される前にBLOCKEDかREADYになっているものとみなす。currentThreadが変更されるのはこのメソッドの内部である。threadToBeDestroyedがセットされていればスレッドの切り替え後にそのスレッドを解放する。PrintメソッドはreadyListの内容を表示する。実行中で無いが実行可能なスレッドを保持するリスト。newThread)となっている。コンテキストスイッチを行うアセンブラルーチンで、CPUに依存する。switch.sのうち必要な分だけ抜き出されてswtch.sになってる・・・っぽい。ThreadRoot手続きもswtch.s(switch.s)にある。EAXに引数の値(スレッドへのポインタ)をセットして使うので、EAX自体の値は_eax_saveという領域に一時保存して保存、復元する。リターンアドレスを4(%esp)にセットするのはなぜだろう。0(%esp)がSWITCHからのリターンアドレスだと思うのだが。SemaphoreクラスSemaphoreクラスpublicメソッドコンストラクタはセマフォの値の初期値を引数にとる。キューの初期化をする。デストラクタはキューを解放する。Pメソッドはdown操作である。value==0ならばスレッドをスリープする。valueを1減少させる。Vメソッドはup操作である。セマフォを待っているスレッドがあれば1つ起こす。valueを1増加させる。常に0以上Lockクラス実装が不完全Conditionクラス実装が不完全。OScl-dotでお絵描きcl-dotはGraphvizというツール群を使ってグラフを書くためのCommonLispライブラリ。日本語は出力できないらしい。デバイスの階層っぽい図を書いてみた。クラス階層なんかも同じ要領で書けそう。libraryを利用するためのライブラリ、cl-gdを使って遊んでみる。cl-gdのディレクトリにあるcl-gd-glue.cからcl-gd-glue.soを作る必要がある。Makefileがあるが、libiconvがいらないっぽいのでそこだけ修正してmakeする。絵心はないので、図形を書いてみた。以下はシェルピンスキーの三角形(?)を書くコード。CommonLisp2010年2月8日月曜日SBCL1.0.35のlispobjSBCLのsrc/runtimeディレクトリのC言語で記述された箇所を読む努力をしてみる。脳みそのスペックと英語力と注意力が無いので多々憶測を含む。lispobjは名前のとおりlispのオブジェクトを表すものだと思われるが、こいつがどのように利用されているか見ていく。32とする(genesis/config.h)。runtime.hやgenesis/constants.hあたりにタグなどの定義がある。0xFFFFFFFFL)LOWTAGLOWTAG_MASKはconstants.h(自動生成される)で7と定義されている。lispobjの下位3ビットを利用したタグ。タグの値:定義されている定数の名前0:EVEN_FIXNUM_LOWTAG1:INSTANCE_POINTER_LOWTAG2:OTHER_IMMEDIATE_0_LOWTAG3:LIST_POINTER_LOWTAG4:ODD_FIXNUM_LOWTAG5:FUN_POINTER_LOWTAG6:OTHER_IMMEDIATE_1_LOWTAG7:OTHER_POINTER_LOWTAGビット0が立っていれば何らかのポインタである。整数をN_FIXNUM_TAG_BITS(2)左にシフトすることで偶数ならEVEN_FIXNUM_LOWTAGが、奇数ならODD_FIXNUM_LOWTAGがLOWTAGにセットされる。fixnumが表現できるのは29ビット30ビット。OTHER_IMMEDIATE_x_LOWTAGはWIDETAGで何を示すのかを表すっぽい。WIDETAGWIDETAG_MASKが255と定義されているので、lispobjの下位8ビットがWIDETAG。OTHER_IMMEDIATE_x_LOWTAGのときはWIDETAGで値の種類を判別するのだと思う。メモlispobjとはとくに関係ないけど、runtime.hのQSHOW_SIGNALSを真にすると実行中にいろいろメッセージを吐くようになる。make.shを実行すると、runtimeディレクトリにsbclという実行ファイルが作られる。--core引数をつけずに実行すると、search_for_core関数でコアファイルを探そうとする。__attribute__((noreturn))]であるlose関数を呼び出す。loseはわりといろんなところから呼ばれている。処理を続行できないエラーの場合に呼び出しているのだろう。load_core_fileは最初に実行すべき関数のlispobjを返す。main関数の終わり付近でcreate_initial_thread関数の引数として利用する。(2010/02/06)今日は。鶴見の総持寺を見に行った。帰りがけに鶴見駅前の酒屋「和泉屋」で日本酒を購入した。(石川[金沢]/福光屋)さっそく飲むかと思いきや、先に前に買っておいた名誉冠大吟醸(京都/山本本家)を飲むことにした。酒McCLIMでライフゲームMcCLIMでライフゲームをやってみた。いうそれっぽいのが見つかった。wiht-output-bufferedを使った。LispのGUIライブラリといえばMcCLIMがある。日本語資料の少なさとか他のGUIライブラリとの差異とかはご愛嬌というやつでしょう。このMcCLIM、ユーザインターフェースを作るときは良いけれど、一定時間ごとに再描画したい、というようなユーザの動作が絡まないときの処理をどう書けば良いかよくわからない。一定時間ごとにイベントを発生させられれば良いのだけど、よくわからないので他にスレッドを作ってそちらに任せることで解決しようとしてみた。'clock-frame)));;(run)paneの:display-timeあたりをどうにかするとうまいことできたりするのだろうか。McCLIM2010年2月4日木曜日cl-ppcreでマッチした文字列に$1などとしてアクセスするcl-ppcreで正規表現にマッチした文字列を自動的に変数に代入してしまおうというネタ。多くの人が一度はやったことあるに違いない。やる価値を感じていないか。register-groups-bindのほうがどう考えても便利だけど、見た目で他の言語のユーザを引きつける事が出来る・・・かも。nil);;;mkstr,symbはOnLispのもの。reg-end-array)))以下、使用例。$0)に対して行われること。letなどでレキシカル変数を使っていると意図した挙動にならないかもしれない。"jklmnopqr")・・・ってあれ、なんで$0だけこうなるんだろう。defparameterのせいだ。