2011.09.18 v7から始めるunix まとめ

1,155 views

Published on

まだぐだぐだです。もう少し追記します。

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,155
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

2011.09.18 v7から始めるunix まとめ

  1. 1. V7から始めるUNIX まとめ予備知識であるCPUアーキテクチャのほん のさわりを説明したあと、本題に入ります
  2. 2. 予備知識• コンピュータ・アーキテクチャについて – 低レイヤのプログラムの理解に欠かせない – 理想を言えば、網羅的に知っておくことが好ましい • ハードとソフトは両輪だから – ただし、技術の範囲が広大すぎて、とてもここでは扱いき れない – 疑問が出た都度、身近な専門家に声をかけて聞くと、きっ と親切に教えてくれる!←学校か職場の専門家が誰か、 把握しておこう! • 私も知っている範囲で答えます – ここではCPUの基本構成、マシン語から演算器で実行さ れる手順にフォーカスして、次ページ以降で少しだけさわ る 2
  3. 3. CPUの基本構成、超ざっくり• 参考情報※の本文が、非 常に素晴らしいので、そち らに詳細の解説はゆずり ます – CPUは大きく、演算部と制 御部から構成されます – CPUにはメモリが接続され ています – ROMには、コンパイラに よってプログラムから変換 され、CPUが実行可能な マシン語に変換されたデー タが入っています※参考:http://homepage2.nifty.com/ttoyoshima/Computer/Config.htm 3
  4. 4. マシン語• プログラム言語はコンパイラによってCPUが直接理 解し実行できるマシン語に変換される• マシン語は、CPUで処理される(命令パイプライン)• マシン語の例参考情報http://www.geocities.jp/mori_imms/asmDetail.htmlhttp://msyk.net/keio/JavaBook/ch1.html 4
  5. 5. 命令パイプライン(1/2)• 汎用パイプラインについて説明する• 次ページの図は、一般化した次のような4段のパイプライン を示している。• フェッチ (Fetch):メモリから機械語を取り出してくる動作• デコード (Decode):機械語を解読し、制御信号を送る• 実行 (Execute):実行する• ライトバック (Write-back):実行結果をファイルかメモリに書き 込む• 次ページの図の上にある灰色の矩形には実行を待っている 命令が並んでいる。下の灰色の矩形には実行が完了した命 令が並んでいる。真ん中の矩形がパイプラインを表している。• 実行は次ページのようになる。参考:Wikipedia 5
  6. 6. 命令パイプライン(2/2) 説明0 4つの命令が実行されるのを待っている。1 緑の命令をメモリからフェッチする。 緑の命令をデコードする。2 紫の命令をメモリからフェッチする。 緑の命令を実行する(実際の命令処理を行う)3 紫の命令をデコードする。 青の命令をフェッチする。 緑の命令の結果をレジスタファイルかメモリに書き込む 紫の命令を実行する。4 青の命令をデコードする。 赤の命令をフェッチする。 緑の命令は完了した。 紫の命令の結果を書き込む。5 青の命令を実行する。 赤の命令をデコードする。 紫の命令は完了した。6 青の命令の結果を書き込む。 赤の命令を実行する。 青の命令は完了した。7 赤の命令の結果を書き込む。8 赤の命令は完了した。9 全命令を実行した。 6
  7. 7. • 示した例は、一般的な例です• 実際はもっと複雑で、いろいろ工夫されています• 例えば – http://www.slideshare.net/schnee_rosa/20110611- v7unixb• 気に入っている、または気になるチップのアーキ テクチャを調べていくと、楽しいです – チップメーカーは大抵、開発者向けのホワイトペー パーを出しています – わからない専門用語は、専門家に聞こう! • 私も知っている範囲で答えます 7
  8. 8. V7の理解(1/4)• 現在のLinuxの原点はV7 – V7→BSD→Linux• V7を読み解くことで、原理の理解を進めることを 目的とする• 今回は、V7の理解の一環として、まず root/h/user.hとroot/sys/slp.cの実装を読み解い ていく – slp.cはスワッピングについて記載されており、プロセ ス制御の基本です 参照したソースコード: http://www.tamacom.com/tour/kernel/unix/ 8
  9. 9. V7の理解(2/4)• V7ではハードが限定されていたため、可搬性に ついて考慮していない – DECのPDP-11などで動作した• しかしC言語で書かれているため、移植性は高 い• 歴史についての参考資料 http://ja.wikipedia.org/wiki/Version_7_Unix• ソースコードは簡単シンプル、注釈が丁寧で読 みやすいです… – ただしK&Rで書かれているっぽい – マジックナンバーがあればそれは8進数 9
  10. 10. 全体の超概略(推測入ってるところ/未確認は V7の理解(3/4) 黄色でハッチ。習ってるところは赤ハッチ)ソースファイル 役割 代表的な関数acct.c プロセスがCPUを使用した状況をファイルに記載するためのもの? acct,sysacctalloc.c メモリディスク?の割りあて、解放を行う alloc,freeclock.c ?(現在の役割と一緒か否か?) clock,timeoutfakemx.c ユーザ定義関数か何かのような気がするfio.c ファイルに定義されている関数をロードするためのもの? getfiget.c ファイル操作を行うため、パス名をinodeに変換する。 igetmachdep.c ブートストラップを行う startupmain.c システムの初期化を行う mainmalloc.c 現在と定義が変わっていないだろうか? malloc,mfreenami.c inodeのパス名をポインタに変換。iget.cとペアか? nameipipe.c パイプを行う pipeprf.c 標準出力を行う(なぜにパニックがここに) printfprim.c 今の標準関数と同じなら、キャラクタリスト=文字列のgetとput getc,putcrdwri.c inodeポインタに対する読み書き readi,writeisig.c シグナル。割り込みに使う。tty.cから呼ばれる signalslp.c 資源を排他的に利用するため、カーネル内の同期を実現 sleep,wakeupsubr.c inodeのポインタに読み書き可能なブロックを割り当てる? bmapsys1.c プロセス操作系システムコール exec,fork等sys2.c ファイル操作系システムコール read,write等sys3.c ファイルの状態(どこのデバイスか、所有者、アクセス権)を取得するシステムコール fstatsys4.c 上記以外のシステムコール いろいろtext.c プロセスのスワップアウトを行う xswaptrap.c シグナルを補足し、指定の処理を行う trapureg.c これよくわからない… sureg 10
  11. 11. V7の理解(4/4)ヘッダファイル 役割 構造体acct.h プロセスのアカウント情報をファイルに書き出せるようにする acctbuf.h リングバッファ?ブロックデバイスのバッファ bufcallo.h クロックから中断されコールアウトする? calloconf.h ブロックデバイス、キャラクタデバイスのスイッチングを宣言する cdevsw,bdevswdir.h ディレクトリ情報管理用? diectfblk.h ? fblkfile.h inodeのファイル管理用構造体? filefilsys.h fileを束ねたもの? filsysino.h disk block上でのinode用構造体 dinodeinode.h inode構造体 inodemap.h メモリマップの構造体、coreとswapの2つ mapmount.h マウント用構造体(デバイスのか?) mountmpx.h これちょっとわからないmx.h これもちょっとわからないpack.h これもマジわからない packpk.h 上のpack.hと同じ構造体が入ってる?? pack?proc.h プロセスの状態や管理情報を保持 procpwd.h ?全体の文脈からしてパスワードの変更ではなさそうな気が passwdstat.h inodeの状態を知る? statsystem.h システムエントリテーブルの定義(何か実行させたいときここを参照する) sysenttext.h スワップの際のディスクアドレスなどを格納 texttimeb.h ftimeシステムコールの戻り値(gettimeofdayの代わり?) timebtty.h キャラクタ端末制御用? tty 11user.h プロセスが扱うプログラムやデータを保持 user
  12. 12. user.h(1/5) 冒頭の注釈 (注釈のまんま) ↓左端の数値は行番号 ・user構造体を定義している ・プロセスあたり1つ持つ 1 /* ・1プロセスあたりの全データであ 2 * The user structure. る 3 * One allocated per process. ・プロセスがスワップしている間は、 4 * Contains all per process data 参照しなくてよい ・ユーザのブロック長はUSIZE×64 5 * that doesnt need to be referenced でこれはスタックポインタ用に使わ 6 * while the process is swapped. れる 7 * The user block is USIZE*64 bytes ・仮想カーネルのデータ長は 8 * long; resides at virtual kernel 140000 (ユーザ毎のシステムス 9 * loc 140000; contains the system タック含む)10 * stack per user; is cross referenced・同じプロセスの中では、proc構造 と相互参照の関係にある11 * with the proc structure for the12 * same process.13 */ 12
  13. 13. 1415 #define EXCLOSE 01 user.h(2/5) 1617 struct user18 {19 label_t u_rsav; /* save info when exchanging stacks */20 int u_fper; /* FP error register */ 退避時にスタックポインタを格納21 int u_fpsaved; /* FP regs saved for this proc */22 struct {23 int u_fpsr; /* FP status register */24 double u_fpregs[6]; /* FP registers */ ファイルI/O用の変数25 } u_fps;26 char u_segflg; /* IO flag: 0:user D; 1:system; 2:user I */ファイルI/Oの属性等27 char u_error; /* return error code */ Dはデータ、I、は命令28 short u_uid; /* effective user id */ systemはカーネルに相当29 short u_gid; /* effective group id */ userはプロセスユーザと同義30 short u_ruid; /* real user id */31 short u_rgid; /* real group id */ proc構造体ポインタ32 struct proc *u_procp; /* pointer to proc structure */33 int *u_ap; /* pointer to arglist */ システムコールの引数リスト34 union { /* syscall return values */35 struct {36 int r_val1; システムコールの戻り値37 int r_val2; 例えばLinuxのコマンド38 }; ls –laとかで得られる39 off_t r_off; 一覧のデータを格納40 time_t r_time; 1341 } u_r; しておく
  14. 14. user.h(3/5)42 caddr_t u_base; /* base address for IO */ プロセスユーザのI/Oの開始ア43 unsigned int u_count; /* bytes remaining for IO */44 off_t u_offset; ドレス、オフセット、どこのディ /* offset in file for IO */45 struct inode *u_cdir; レクトリにあるか、パス名(この /* pointer to inode of current directory */46 struct inode *u_rdir; ころは物理アドレス空間を直 /* root directory of current process */47 char u_dbuf[DIRSIZ]; 接扱っていた?) /* current pathname component */48 caddr_t u_dirp; /* pathname pointer */49 struct direct u_dent; /* current directory entry */50 struct inode *u_pdir; /* inode of parent directory of dirp */51 int u_uisa[16]; /* prototype of segmentation addresses */52 int u_uisd[16]; ファイルI/O /* prototype of segmentation descriptors */53 struct file *u_ofile[NOFILE]; /* pointers to file structures of open files * (ちょっと詳細がわからない)54 char u_pofile[NOFILE]; /* per-process flags of open files */55 int u_arg[5]; /* arguments to current system call */56 unsigned u_tsize; /* text size (clicks) */57 unsigned u_dsize; /* data size (clicks) */ 現在のシステムコール戻り値58 unsigned u_ssize; /* stack size (clicks) */ テキスト(プログラム)、データ59 label_t u_qsav; /* label variable for quits and interrupts */60 label_t u_ssav; /* label variable for swapping */ (固定値)、スタック(call時のP61 int u_signal[NSIG]; /* disposition of signals */ C値の格納等)のサイズ、ス62 time_t u_utime; /* this process user time */ ワップや退避時のラベル値63 time_t u_stime; /* this process system time */64 time_t u_cutime; /* sum of childs utimes */ システムコールの戻り値65 time_t u_cstime; /* sum of childs stimes */ プロセスおよび子プロセスの66 int *u_ar0; /* address of users saved R0 */ CPU使用時間など 14
  15. 15. user.h(4/5)75 struct tty *u_ttyp; /* controlling ttytty(キャラクタ端末)制御用ポイ pointer */76 dev_t u_ttyd; /* controlling tty ンタとデバイス制御用情報 dev */77 struct { /* header of executable file */78 int ux_mag; /* magic number */79 unsigned ux_tsize; /* text size */80 unsigned ux_dsize; /* data size */ これはわからない…81 unsigned ux_bsize; /* bss size */82 unsigned ux_ssize; /* symbol table size */ 実行するプログラムの83 unsigned ux_entloc; /* entry location */ 情報(予備?)か何かか84 unsigned ux_unused;85 unsigned ux_relflg;86 } u_exdata;87 char u_comm[DIRSIZ];88 time_t u_start;89 char u_acflag;90 short u_fpflag; /* unused now, will be later */ 予備用(互換性を取るため?)91 short u_cmask; /* mask for file creation */92 int u_stack[1];93 /* kernel stack per user94 * extends from u + USIZE*6495 * backward not to reach here96 */97 }; 98 15
  16. 16. user.h(5/5) エラーコードの定義101 /* u_error codes */ 118 #define EEXIST 17102 #define EPERM 1 119 #define EXDEV 18103 #define ENOENT 2 120 #define ENODEV 19104 #define ESRCH 3 121 #define ENOTDIR 20105 #define EINTR 4 122 #define EISDIR 21106 #define EIO 5 123 #define EINVAL 22107 #define ENXIO 6 124 #define ENFILE 23108 #define E2BIG 7 125 #define EMFILE 24109 #define ENOEXEC 8 126 #define ENOTTY 25110 #define EBADF 9 127 #define ETXTBSY 26111 #define ECHILD 10 128 #define EFBIG 27112 #define EAGAIN 11 129 #define ENOSPC 28113 #define ENOMEM 12 130 #define ESPIPE 29114 #define EACCES 13 131 #define EROFS 30115 #define EFAULT 14 132 #define EMLINK 31116 #define ENOTBLK 15 133 #define EPIPE 32117 #define EBUSY 16 134 #define EDOM 33 135 #define ERANGE 34 16
  17. 17. 1 /*2 * One structure allocated per active3 * process. It contains all data needed proc.h(1/3)4 * about the process while the5 * process may be swapped out. アクティブなプロセス毎に割り当てられる6 * Other per process data (user.h) 構造体7 * is swapped with the process. アクティブ=実行待ちと実行中のプロセス8 */ running=実行中のプロセス9 struct proc { 状態をあらわす で理解はあっているか?10 char p_stat;11 char p_flag; ようだが詳細不明 スワップアウトしても退避せず保持する?12 char p_pri; /* priority, negative is high */13 char p_time; /* resident time for scheduling */14 char p_cpu; /* cpu usage for scheduling */15 char p_nice; /* nice for cpu usage */16 short p_sig; /* signals pending to this process */17 short p_uid; /* user id, used to direct tty signals */18 short p_pgrp; /* name of process group leader */19 short p_pid; /* unique process id */20 short p_ppid; /* process id of parent */21 short p_addr; /* address of swappable image */22 short p_size; /* size of swappable image (clicks) */23 caddr_t p_wchan; /* event process is awaiting */24 struct text *p_textp; /* pointer to text structure */25 struct proc *p_link; /* linked list of running processes */26 int p_clktim; /* time to alarm clock signal */ 1727 };
  18. 18. proc.h(2/3) プロセスの状態をあらわすマクロ定数 29 extern struct proc proc[]; /* the proc table itself */ 30 31 /* stat codes */ 32 #define SSLEEP 1 /* awaiting an event */ 33 #define SWAIT 2 /* (abandoned state) */ 34 #define SRUN 3 /* running */ 35 #define SIDL 4 /* intermediate state in process creation */ 36 #define SZOMB 5 /* intermediate state in process termination*/ 37 #define SSTOP 6 /* process being traced */ 38 39 /* flag codes */ 40 #define SLOAD 01 /* in core */ 41 #define SSYS 02 /* scheduling process */ 42 #define SLOCK 04 /* process cannot be swapped */ 43 #define SSWAP 010 /* process is being swapped out */ 44 #define STRC 020 /* process is being traced */ 45 #define SWTED 040 /* another tracing flag */ 46 #define SULOCK 0100 /* user settable lock in core */ 47 18
  19. 19. proc.h(3/3)49 * parallel proc structure50 * to replace part with times51 * to be passed to parent process52 * in ZOMBIE state.53 */54 struct xproc { ゾンビ(実行終了中)プロセス用構造体55 char xp_stat; なぜわざわざ用意するのだろうか?56 char xp_flag;57 char xp_pri; /* priority, negative is high */58 char xp_time; /* resident time for scheduling */59 char xp_cpu; /* cpu usage for scheduling */60 char xp_nice; /* nice for cpu usage */61 short xp_sig; /* signals pending to this process */62 short xp_uid; /* user id, used to direct tty signals */63 short xp_pgrp; /* name of process group leader */64 short xp_pid; /* unique process id */65 short xp_ppid; /* process id of parent */66 short xp_xstat; /* Exit status for wait */67 time_t xp_utime; /* user time, this proc */68 time_t xp_stime; /* system time, this proc */69 }; 19
  20. 20. slp.c• プロセスの制御を行う関数群(スリープと起動)• 以下の関数について定義している(★は注目すべき関数) – ★sleep:プロセスの実行を中断し、プロセッサを明け渡す – ★wakeup:sleep中のプロセスを起こす – setrun:プロセスが実行できるようにする(スワップインできるよ うにする) – setpri:プロセスユーザの優先度をセットする関数 – sched:スワッピングのメイン関数 – swapin:プロセスをスワップインさせる関数 – qswitch:プロセスキューの設定を行う関数 – switch:CPUのリスケジュール(資源の再割り当て)を行う場合 に呼び出す – newproc:新しいプロセスを立ち上げる(fork?) – expand:データとスタックのサイズを変える – setrq: 20
  21. 21. 27 sleep(chan, pri) /* */28 caddr_t chan; sleep(1/2)29 { 12 #define SQSIZE 0100 /* Must be power of 2 */30 register struct proc *rp; 13 #define HASH(x) (( (int) x >> 5) & (SQSIZE-1))31 register s, h; 14 struct proc *slpque[SQSIZE]; 1532 16 /*33 rp = u.u_procp; 17 * Give up the processor till a wakeup occurs プライオリティを上げて34 s = spl6(); 18 * on chan, at which time the process35 if (chan==0) 割り込みを禁止する 19 * enters the scheduling queue at priority pri. 20 * The most important effect of pri is that when36 panic("zero wchan"); 21 * pri<=PZERO a signal cannot disturb the sleep;37 rp->p_stat = SSLEEP; 22 * if pri>PZERO signals will be processed. 23 * Callers of this routine must be prepared for38 rp->p_wchan = chan; 24 * premature return, and check that the reason for39 if (chan==0) 25 * sleeping has gone away.40 panic("Sleeping on wchan 0"); 26 */41 rp->p_pri = pri;42 h = HASH(chan); ここでいうハッシュは、5ビットシフトとマスク43 rp->p_link = slpque[h]; プライオリティが低く44 slpque[h] = rp; シグナルを受けている(??)時は次ページに飛んで45 if(pri > PZERO) { sleepのためにリジュームする46 if(issig()) {47 rp->p_wchan = 0;48 rp->p_stat = SRUN;49 slpque[h] = rp->p_link;50 spl0();51 goto psig; 2152 }
  22. 22. 53 spl0();5455 if(runin != 0) { runin = 0; sleep(2/2)56 wakeup((caddr_t)&runin); 走れるプロセスがあれば起こす57 }58 swtch();59 if(issig())60 goto psig; シグナルを受けていればリジュームする61 } else {62 spl0();63 swtch();64 }65 splx(s); プライオリティを元に戻す66 return;6768 /*69 * If priority was low (>PZERO) and 以降は、まだなぞの動作70 * there has been a signal,71 * execute non-local goto to72 * the qsav location.73 * (see trap1/trap.c)74 */75 psig:76 resume(u.u_procp->p_addr, u.u_qsav);77 } 22
  23. 23. 82 wakeup(chan) /* */83 register caddr_t chan;84 {85 register struct proc *p, *q; wakeup(1/1)86 register i;87 int s;8889 s = spl6();90 i = HASH(chan);91 p = slpque[i];92 q = NULL;93 while(p != NULL) {94 if(p->p_wchan==chan && p->p_stat!=SZOMB) {95 struct proc *sp;96 スリープキューに貯まっている97 if (q == NULL) プロセスを検出する(ゾンビ以外)98 sp = slpque[i] = p->p_link;99 else100 sp = q->p_link = p->p_link;101 p->p_wchan = 0;102 setrun(p); ここでプロセスを起こしている?103 p = sp;104 continue;105 }106 q = p;107 p = p->p_link;108 }109 splx(s);110 } 23
  24. 24. 136 /*137 * Set the process running;138139140 * arrange for it to be swapped in if necessary. */ setrun(p) setrun(1/1)141 register struct proc *p;142 {143 register caddr_t w;144145 if (p->p_stat==0 || p->p_stat==SZOMB)146 panic("Running a dead proc");147 /*148 * The assignment to w is necessary because of149 * race conditions. (Interrupt between test and use)150 */151 if (w = p->p_wchan) {152 wakeup(w); ここでプロセスを起こしている153 return;154 }155 p->p_stat = SRUN;156 setrq(p); プロセスを起こさない場合。157 if(p->p_pri < curpri)158 runrun++;159 if(runout != 0 && (p->p_flag&SLOAD) == 0) {160 runout = 0;161 wakeup((caddr_t)&runout);162 } 24163 }
  25. 25. 165166 /* * Set user priority. setpri167 * The rescheduling flag (runrun)168 * is set if the priority is better169 * than the currently running process.170 */171 setpri(pp)172 register struct proc *pp;173 {174 register p; 数値が8進であることに注意!175 ユーザプロセスの優先度を設定する176 p = (pp->p_cpu & 0377)/16;177 p += PUSER + pp->p_nice - NZERO;178 if(p > 127)179 p = 127;180 if(p < curpri)181 runrun++;182 pp->p_pri = p;183 return(p);184 }185 25
  26. 26. 202 sched()203 {204 register struct proc *rp, *p; sched(1/3)205 register outage, inage; ところどころに出てくる、206207 int maxsize; プロセスのスワップをする関数。spl*の*が208 /* 大きいほど優先度が高く、6が最高。209 * find user to swap in;210 * of users ready, select one out longest 他から割りこみが入って状態が211 */ 変わらないようにしたい場合にこうする。212213 loop: ここでは最高優先度まで上げて以降の214 spl6(); 操作を行っている215 outage = -20000;216 for (rp = &proc[0]; rp < &proc[NPROC]; rp++)217 if (rp->p_stat==SRUN && (rp->p_flag&SLOAD)==0 && プロセスの状態を総なめして218 rp->p_time - (rp->p_nice-NZERO)*8 > outage) {219 p = rp; ステータスが実行可能状態で220 outage = rp->p_time - (rp->p_nice-NZERO)*8; 優先度が一番高いものを検出221 }222 /* (スワップイン候補を探す)223 * If there is no one there, wait.224 */225 if (outage == -20000) {226 runout++; 上記条件にあうプロセスが検出できなけれ227 sleep((caddr_t)&runout, PSWP);228 goto loop; ば、sleepを呼び出して待つ229 }230 spl0();231232 /* 優先度を最低に戻す233 * See if there is core for that process;234 * if so, swap it in.235 */236237 if (swapin(p)) プロセスに割り当てられる資源(メモリなど)238 goto loop; があればスワップインする 26
  27. 27. 240 /* sched(2/3)241 * none found.242 * look around for core.243 * Select the largest of those sleeping244 * at bad priority; if none, select the oldest.245 */246247 spl6();248 p = NULL;249 maxsize = -1;250 inage = -1;251 for (rp = &proc[0]; rp < &proc[NPROC]; rp++) {252 if (rp->p_stat==SZOMB253 || (rp->p_flag&(SSYS|SLOCK|SULOCK|SLOAD))!=SLOAD)254 continue; CPUに割り当255 if (rp->p_textp && rp->p_textp->x_flag&XLOCK)256 continue; てる候補と資257 if (rp->p_stat==SSLEEP&&rp->p_pri>=PZERO || rp->p_stat==SSTOP) { 源がない状258 if (maxsize < rp->p_size) {259 p = rp; 態。一番最初260 maxsize = rp->p_size; にsleepしたプ261 }262 } else if (maxsize<0 && (rp->p_stat==SRUN||rp->p_stat==SSLEEP)) { ロセスを総な263 if (rp->p_time+rp->p_nice-NZERO > inage) { めして検出す264 p = rp;265 inage = rp->p_time+rp->p_nice-NZERO; る(優先的に266 } スワップさせ267 }268 } るため)269 spl0();270 /* 27
  28. 28. sched(3/3)270 /*271 * Swap found user out if sleeping at bad pri,272 * or if he has spent at least 2 seconds in core and273 * the swapped-out process has spent at least 3 seconds out.274 * Otherwise wait a bit and try again.275 */276 if (maxsize>=0 || (outage>=3 && inage>=2)) { CPUに割り当てられていた277 p->p_flag &= ~SLOAD;278 xswap(p, 1, 0); 時間が2秒以上、または279 goto loop; 低い優先度でsleepしていれば280 } スワップを行う281 spl6();282 runin++;283 sleep((caddr_t)&runin, PSWP);284 goto loop;285 }286 28
  29. 29. 292 swapin(p)293 register struct proc *p;294 { swapin295 register struct text *xp;296 register int a;297 int x;298299 if ((a = malloc(coremap, p->p_size)) == NULL)300 return(0);301 if (xp = p->p_textp) {302 xlock(xp);303 if (xp->x_ccount==0) {304 if ((x = malloc(coremap, xp->x_size)) == NULL) {305 xunlock(xp);306 mfree(coremap, p->p_size, a);307 return(0);308 }309 xp->x_caddr = x;310 if ((xp->x_flag&XLOAD)==0)311 swap(xp->x_daddr,x,xp->x_size,B_READ);312 }313 xp->x_ccount++; スワップアウトしたプロセスを314 xunlock(xp); スワップインさせている315 }316 swap(p->p_addr, a, p->p_size, B_READ); coremap,swapmapとは何か?317 mfree(swapmap, ctod(p->p_size), p->p_addr);318 p->p_addr = a;319 p->p_flag |= SLOAD;320 p->p_time = 0;321 return(1); 29
  30. 30. qswitch324 /*325 * put the current process on326 * the Q of running processes and327 * call the scheduler.328 */329 qswtch()330 {331332 setrq(u.u_procp); プロセスをキューに放り込む?333 swtch();334 }335 30
  31. 31. 347 swtch()348 {349350352 register n; register struct proc *p, *q, *pp, *pq; /* switch(1/2)353 * If not the idle process, resume the idle process.354 */355 if (u.u_procp != &proc[0]) {356 if (save(u.u_rsav)) {357 sureg();358 return;359 }360 if (u.u_fpsaved==0) {361 savfp(&u.u_fps); プロセスを切り替える。362 u.u_fpsaved = 1; これは、最初に、sched()で呼ば363 } れたswitchがproc0をresumeす364 resume(proc[0].p_addr, u.u_qsav);365 } る場合のルーチン366 /*367 * The first save returns nonzero when proc 0 is resumed368 * by another process (above); then the second is not done369 * and the process-search loop is entered.370 *371 * The first save returns 0 when swtch is called in proc 0372 * from sched(). The second save returns 0 immediately, so373 * in this case too the process-search loop is entered.374 * Thus when proc 0 is awakened by being made runnable, it will375 * find itself and resume itself at rsav, and return to sched().376 */377 if (save(u.u_qsav)==0 && save(u.u_rsav)) 31378 return;
  32. 32. 379 loop:380 spl6();381 runrun = 0; switch(2/2)382 pp = NULL;383 q = NULL;384 n = 128;385 /*386 * Search for highest-priority runnable process387 */388 for(p=runq; p!=NULL; p=p->p_link) {389 if((p->p_stat==SRUN) && (p->p_flag&SLOAD)) {390 if(p->p_pri < n) {391 pp = p;392 pq = q;393 n = p->p_pri;394 } 順次プロセスの状態を調べ395 }396 q = p; て実行可能かつ最も優先397398 } /* 度が高いプロセスを選択し399 * If no process is runnable, idle. ている400 */401 p = pp; 該当がない場合、いったん402403 if(p == NULL) { idle(); idle()してまたループする404 goto loop;405 }406 q = pq;407 if(q == NULL)408 runq = p->p_link;409 else410 q->p_link = p->p_link;411 curpri = n;412 spl0();413 /*414 * The rsav (ssav) contents are interpreted in the new address space415 */416 n = p->p_flag&SSWAP;417 p->p_flag &= ~SSWAP;418 resume(p->p_addr, n? u.u_ssav: u.u_rsav);419 } 32
  33. 33. 421 /*422 * Create a new process-- the internal version of423 * sys fork.424 * It returns 1 in the new process, 0 in the old. newproc(1/4)425 */426 newproc()427 {428 int a1, a2;429 struct proc *p, *up;430 register struct proc *rpp, *rip;431 register n;432433 p = NULL;434 /*435 * First, just locate a slot for a process436 * and copy the useful info from this process into it.437 * The panic "cannot happen" because fork has already438 * checked for the existence of a slot.439 */440 retry:441 mpid++;442 if(mpid >= 30000) { 30000の数字の意味が不明443 mpid = 0;444 goto retry;445 }446 for(rpp = &proc[0]; rpp < &proc[NPROC]; rpp++) {447 if(rpp->p_stat == NULL && p==NULL)448 p = rpp;449 if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)450 goto retry;451 } 新しいプロセスが割り当てられるか452 if ((rpp = p)==NULL) pidを調べている 33453 panic("no procs");
  34. 34. 455 /*456 * make proc entry for new proc457458 */ newproc(2/4)459 rip = u.u_procp;460 up = rip;461 rpp->p_stat = SRUN;462 rpp->p_clktim = 0;463 rpp->p_flag = SLOAD;464 rpp->p_uid = rip->p_uid; 新しいプロセスの割りあて 資源などの情報は465 rpp->p_pgrp = rip->p_pgrp; 親プロセスのをコピーしている466 rpp->p_nice = rip->p_nice; forkのことか?467 rpp->p_textp = rip->p_textp;468 rpp->p_pid = mpid;469 rpp->p_ppid = rip->p_pid;470 rpp->p_time = 0;471 rpp->p_cpu = 0;472473 /*474 * make duplicate entries475 * where needed476 */ 34477
  35. 35. 478 for(n=0; n<NOFILE; n++)479 if(u.u_ofile[n] != NULL)480 u.u_ofile[n]->f_count++;481 if(up->p_textp != NULL) {482483 up->p_textp->x_count++; up->p_textp->x_ccount++; newproc(3/4)484 }485 u.u_cdir->i_count++;486 if (u.u_rdir)487 u.u_rdir->i_count++;488 /*489 * Partially simulate the environment490 * of the new process so that when it is actually491 * created (by copying) it will look right.492 */493 rpp = p;494 u.u_procp = rpp;495 rip = up; ちょっとここ謎の動作496 n = rip->p_size;497 a1 = rip->p_addr;498 rpp->p_size = n; 35
  36. 36. 499 /*500 * When the resume is executed for the new process,501 * heres where it will resume.502 */503 if (save(u.u_ssav)) {504505 sureg(); return(1); newproc(4/4)506 }507 a2 = malloc(coremap, n);508 /*509 * If there is not enough core for the510 * new process, swap out the current process to generate the511 * copy.512 */513 if(a2 == NULL) {514 rip->p_stat = SIDL;515 rpp->p_addr = a1;516 xswap(rpp, 0, 0);517 rip->p_stat = SRUN; 資源が足りなければ、518 } else { 子プロセスの処理をするために519 /* 親側をいったんスワップアウトする?520 * There is core, so just copy.521 */522 rpp->p_addr = a2;523 while(n--)524 copyseg(a1++, a2++);525 }526 u.u_procp = rip;527 setrq(rpp);528 rpp->p_flag |= SSWAP;529 return(0); 36530 }
  37. 37. 545 expand(newsize) 532 /* 533 * Change the size of the data+stack regions of the process.546 { 534 * If the size is shrinking, its easy-- just release the extra core.547 register i, n; 535 * If its growing, and there is core, just allocate it 536 * and copy the image, taking care to reset registers to account548 register struct proc *p; 537 * for the fact that the systems stack has moved.549 register a1, a2; 538 * If there is no core, arrange for the process to be swapped 539 * out after adjusting the size requirement-- when it comes550 540 * in, enough core will be allocated.551 p = u.u_procp; 541 *552 n = p->p_size; 542 * After the expansion, the caller will take care of copying 543 * the users stack towards or away from the data area.553 p->p_size = newsize; 544 */554 a1 = p->p_addr;555 if(n >= newsize) {556 mfree(coremap, n-newsize, a1+newsize);557 return;558 }559 if (save(u.u_ssav)) {560561562 } sureg(); return; expand(1/1)563 a2 = malloc(coremap, newsize);564 if(a2 == NULL) {565 xswap(p, 1, n);566 p->p_flag |= SSWAP; 確保しているメモリ領域(データとスタック)を567 qswtch(); 変更したい時(拡張したいとき)、568 /* no return */ malloc,freeで領域を取り直す569 }570 p->p_addr = a2;571 for(i=0; i<n; i++)572 copyseg(a1+i, a2+i);573 mfree(coremap, n, a1);574 resume(a2, u.u_ssav); 37575 }
  38. 38. 112 /*113 * when you are sure that it114115 * is impossible to get the * proc on q diagnostic, the setrq(1/1)116 * diagnostic loop can be removed.117 */118 setrq(p)119 struct proc *p;120 {121 register struct proc *q;122 register s;123124 s = spl6();125 for(q=runq; q!=NULL; q=q->p_link)126 if(q == p) {127 printf("proc on qn"); すでに起動済みのプロセスかどうか128 goto out;129 } チェックしている?130 p->p_link = runq;131 runq = p;132 out:133 splx(s);134 } 38135
  39. 39. 以降はしばらくお待ちください次に記載するCソースファイルを 選定中… 39

×