landで見えるtimerは時刻の取得やsiginfoとか、epollといったselect系など関数でのtimeoutの設定で用いられるが、kernel側でのtimerの利用はこれとは大きく異なる1。本記事ではkernel上でのtimer全般についてまとめている。SLEEPING)がかなり詳しい。interruptも含まれるので、interrupt自体を知っている必要があるが、今回はinterruptについて幹の部分だけ追った上で、timerに関係するコードを追いたいとおもう。interruptを先取りする理由は、一般論から話すよりも具体例を先に見ていったほうが良さそうという思惑から。timerの部分は定数が多く出てくるので、用語だけでなく、数値の確認も行う。linux2.6.11をベースに扱っているので本記事でもそれに沿う。rdtscでcounterを取得できる。Timer)があるが、linux2.6.11ではdefaultで使用しないことになっているので、省略。interrupt(IRQ0)を周期的に(1msごとに)発生させるために用いる。周波数は、1193182[Hz]。APICでredirectするcpuを決める。Routine)として呼ばれる。interruptを発する(が、interrupt発生装置としては未使用)。timerで各cpuに一つづつある。Registerがあるので、そちらで設定する(他にもLVT内のentryを設定する必要がある)。signal*16回ごとにcounterがdecreaseするようになっている。Timerも出てくるが、TSCの場合のみに絞る3。Glosaryを参考のこと。timerの設定を順に行う。timerは最初に設定されたPITをもとにセットされる)今回は概要だけ述べてとりあえず、timerに関する全体像を把握したいと考えている。timerのcalibrationの実装はくせがある(けど、結構面白い)ので、またの機会にまとめたい。setup_pit_timerでLATCH(=1193)をi8254にセットする。calibrate_tscでTSCの設定(クロック周波数は機種によって異なるため、動的に決める。interruptを発生するようにさせる。timerのinterruptについて述べる。numberを結びつける必要がある。numberとそのcallbackのヒモ付(IDTの設定)も必要となる。&irq0);で設定される。Tableに設定を書き込む。IOREDTBL[23:0]を見ればよい。Maskをdisableするだけだ。setup_IO_APIC_irqsで行っている。*)&entry)+0));として、書き込む。Routine)を実行するためのglobal変数irq_desc[idx=0]に必要な情報を詰める。null};が引数として渡ってくる。Routine)はtimer_interruptである。SA_INTERRUPTはISRの突入時にeflags.IFがdisableのママであることを要請するflagである。ここあたりは、interruptやpreemptの回で紹介できればと思う。IDTの設定こちらもちょっと複雑だ。handlerのindexiが対応しているが、(Symmetric)MultiProcessorの場合は、更にこの設定が上書きされるようだ。interrupt[0]);で定義されているようだ。assign_irq_vector(0);の処理から、FIRST_DEVICE_VECTOR»0x31になるっぽい。interrupts.と有り、古い規格(ISA)で遅いので、使われていないようだ[^timer_isa]。interruptが1[ms]ごとにIRQ0が発生するように設定しているのだった。個別のcpuで済むものはsmp_local_timer_interruptに処理を移譲する。interruptで出てくるので、次章で述べる。deviceを結ぶ線)はない。APIC側での設定(LVTの設定)は必要である。加えて、IDTでの設定も見る。APICのregisterたちのRead/Writeができるtableのことだった。register(320H)にLOCAL_TIMER_VECTOR(0xef=237)を紐付ける。init_IRQで初期化されたもの(vector[LOCAL_TIMER_VECTOR])をそのまま使う。switchingなどを行う役割を担っている。interruptを発生するようにさせるのだった。timerのinterruptが生じた直後から簡単に見ていく。interruptが生じると、IDTのLOCAL_TIMER_VECTOR番のentryのapic_timer_interruptから、smp_apic_timer_interrptをcall6し、以下のように遷移する。条件を満たせばdo_softirqが実行されるprocessの起動時間を更新したり、processのtime_slice(schedulerのためのprocessの持ち時間)の更新をしている。optionalでprofiling(kernelのボトルネックがどこか探すために有効に)してたりする。各CPUで定期的に確認したいことを実行している。raise_softirq_irqoffでsoftirqをpendingにする(今回は、TIMER_SOFTIRQのbitをONにする)。do_softirq)を実行することが多い。do_softirqにて、irq_stat[smp_processor_id()].__softirq_pendingのbitが立っている場合、softirqのactionが実行される。(pending);具体的には、pendingは以下のいずれかで、HI_SOFTIRQのbitが立っていたらaction(tasklet_hi_action)が実行され、次にTIMER_SOFTIRQのbitが立っていたら、action(run_timer_softirq)が実行され,...と続き、最後にTASKLET_SOFTIRQのbitが立っていたら、action(tasklet_action)となる。timersを管理し、timeoutが来たものに関しては、callbackを実行する関数だ。Timersが詳しいので、そちらに譲る。re-schedule(TIF_NEED_RESCHED)が絡み合っているので、これよりも更に考えることがある。それについては、今後一つ一つ的を絞って考察していけば良いかな、と感じた。一本の糸を解きほぐせたかなぁ。次回は、interruptか各種timerのcalibrationの実装詳細をみていきたい。Callを参照のこと。clockが使用されている。include/asm-i386/mc146818rtc.hを参照のこと。Hz)と書いてあるので、上記の数字であっていそう。CLONE_SIGHAND);で駆動する。↩ここのコードの追い方がわかりにくいが、include/asm-i386/mach-default/entry_arch.hのBUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR)のマクロが効いてる。こちらもinterruptの記事でまとめられたらなとおもう。callの内部実装の違い(xv6を例に)月別アーカイブはてなブログをはじめよう!knknkn11626さんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。