XNA4.0でテクスチャ・マッピング
(XNA4.0 => Game Studio (Express) XNA GS 4.0)
Primitives3D
http://create.msdn.com/ja-JP/education/catalog/sample/primitives_3d
を参考に、コピペでたたき台を作りこれを改造(テクスチャ・マッピングを追加)する過程でXNAコードの基本構造の習得を試みた。
基本構造
public class Game1 : Microsoft.Xna.Framework.Game
のように基底Gameクラスを継承して、以下のメソッドに処理を実装していく。
protected override void Draw(GameTime gameTime) // 描画。フレームごとに呼び出される。背景、前景、その他。
protected override void Update(GameTime gameTime) // ワールドの更新など、ゲームのアップデートロジックを置く。
protected override void UnloadContent() // アンロードの処理を置くが、通常はあえて書くほどでもないようだ。
protected override void LoadContent() // ゲームごとに最初に?1回?呼び出される。
頂点、インデックス、エフェクトなどの設定を行う。
ちなみにテクスチャとして使用する画像(JPEG, BMPなど)をファイルから読み込むには、下のコンテンツ・プロジェクトへの追加を前提に、
myTexture = Content.Load
などとしてオブジェクト変数に読み込み、適切なオブジェクトと関連付ける。
「テクスチャ・マッピングの利用」
XNA4.0で新規ソリューションを作成すると、
プロジェクトが2つできるのだが、コンテンツ・プロジェクトのほうにコンテンツとして画像を登録することができ、これをテクスチャとして使用した。
方法:コンテンツ プロジェクトへのゲーム アセットの追加
http://msdn.microsoft.com/ja-jp/library/bb313966.aspx
Primitives3Dサンプルは各種図形プリミティブを例示しているが、今回は基本的な図形として立方体(CubePrimitiveクラス)を選び、たたき台とした。
これはGeometricPrimitiveクラスを継承する。このGeometricPrimitiveにフィールドとして
private Texture2D texture;
を持たせ、エフェクトとして利用するようにした。
トラブル解決にDirect3Dデバッグ・ランタイムが役に立つようだが、現在でも通用するのかはまだ試していない。
http://www.atmarkit.co.jp/fdotnet/directxworld/directxworld04/directxworld04_02.html
(本日のソースの状態)https://github.com/sakujyo/XNAStudy1
GitHubとGitGuiのよくわからない
一度Webブラウザでリポジトリを作成してから、WindowsエクスプローラーのコンテキストメニューのGit Init HereでInitしたあと、リモートを追加する手順でやったらできた。
条件なしの禁止について
プログラミング言語で、ある記述が可能なときに、そう書いてもよい例外条件の明示なしに、「そう書いてはいけない」と禁止するのは、ちびっこの手足を縛るだけなんじゃないだろうか。過保護なんじゃないだろうか。
おいさんも昔は相当悪かったからね。カサカサカサカサーっつって。
おまけ
Project Eular Problem 15
分割統治法、再帰と動的計画法、メモ化の組み合わせのパターン
let mutable maxMemo = 256 // 257*257*sizeof(bigint) bigintは可変長 let routeMemo = Array2D.create (maxMemo + 1) (maxMemo + 1) 0I let rec route x y = let a = routeMemo.[x, y] match a = 0I with | false -> a | true -> let ans = match x > 0 with | true -> match y > 0 with | true -> route (x - 1) y + route x (y - 1) | false -> route (x - 1) 0 // 1に決まってるけどw | false -> match y > 0 with | true -> route (y - 1) 0 // まあ1 | false -> 1I routeMemo.[x, y] <- ans ans let solve px py = route px py let run () = solve 20 20
F#での集計(部分集合写像?)パターン
seq [(2M, 1); (2M, 1); (2M, -1); (5M, 1)] |> Seq.groupBy(fun (x, y) -> x) |> Seq.map (お好きなラムダ式)
MINIXのプロセス・スケジューラー…おぼえましたし
主にMINIXのプロセス・スケジューラーを理解するために参考にした
http://www.minix3.org/doc/AppendixB.html
の中の関連部分ソースの抜粋。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/proc.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 05500 #ifndef PROC_H 05501 #define PROC_H 05502 05503 /* Here is the declaration of the process table. It contains all process 05504 * data, including registers, flags, scheduling priority, memory map, 05505 * accounting, message passing (IPC) information, and so on. 05506 * 05507 * Many assembly code routines reference fields in it. The offsets to these 05508 * fields are defined in the assembler include file sconst.h. When changing 05509 * struct proc, be sure to change sconst.h to match. _________________________ Page 699 File: kernel/proc.h _________________________ 05510 */ 05511 #include <minix/com.h> 05512 #include "protect.h" 05513 #include "const.h" 05514 #include "priv.h" 05515 05516 struct proc { 05517 struct stackframe_s p_reg; /* process' registers saved in stack frame */ 05518 reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */ 05519 struct segdesc_s p_ldt[2+NR_REMOTE_SEGS]; /* CS, DS and remote segments */ 05520 05521 proc_nr_t p_nr; /* number of this process (for fast access) */ 05522 struct priv *p_priv; /* system privileges structure */ 05523 char p_rts_flags; /* SENDING, RECEIVING, etc. */ 05524 05525 char p_priority; /* current scheduling priority */ 05526 char p_max_priority; /* maximum scheduling priority */ 05527 char p_ticks_left; /* number of scheduling ticks left */ 05528 char p_quantum_size; /* quantum size in ticks */ 05529 05530 struct mem_map p_memmap[NR_LOCAL_SEGS]; /* memory map (T, D, S) */ 05531 05532 clock_t p_user_time; /* user time in ticks */ 05533 clock_t p_sys_time; /* sys time in ticks */ 05534 05535 struct proc *p_nextready; /* pointer to next ready process */ 05536 struct proc *p_caller_q; /* head of list of procs wishing to send */ 05537 struct proc *p_q_link; /* link to next proc wishing to send */ 05538 message *p_messbuf; /* pointer to passed message buffer */ 05539 proc_nr_t p_getfrom; /* from whom does process want to receive? */ 05540 proc_nr_t p_sendto; /* to whom does process want to send? */ 05541 05542 sigset_t p_pending; /* bit map for pending kernel signals */ 05543 05544 char p_name[P_NAME_LEN]; /* name of the process, including \0 */ 05545 }; 04912 struct boot_image { 04913 proc_nr_t proc_nr; /* process number to use */ 04914 task_t *initial_pc; /* start function for tasks */ _________________________ Page 693 File: kernel/type.h _________________________ 04915 int flags; /* process flags */ 04916 unsigned char quantum; /* quantum (tick count) */ 04917 int priority; /* scheduling priority */ 04918 int stksize; /* stack size for tasks */ 04919 short trap_mask; /* allowed system call traps */ 04920 bitchunk_t ipc_to; /* send mask protection */ 04921 long call_mask; /* system call protection */ 04922 char proc_name[P_NAME_LEN]; /* name in process table */ 04923 }; 04924 04925 struct memory { 04926 phys_clicks base; /* start address of chunk */ 04927 phys_clicks size; /* size of memory chunk */ 04928 }; 01437 typedef long clock_t; /* unit for system accounting */ 05574 #define NIL_PROC ((struct proc *) 0) 05575 #define NIL_SYS_PROC ((struct proc *) 1) プロセス構造体 struct proc 05588 /* The process table and pointers to process table slots. The pointers allow 05589 * faster access because now a process entry can be found by indexing the 05590 * pproc_addr array, while accessing an element i requires a multiplication 05591 * with sizeof(struct proc) to determine the address. 05592 */ 05593 EXTERN struct proc proc[NR_TASKS + NR_PROCS]; /* process table */ 05594 EXTERN struct proc *pproc_addr[NR_TASKS + NR_PROCS]; 05595 EXTERN struct proc *rdy_head[NR_SCHED_QUEUES]; /* ptrs to ready list headers */ 05596 EXTERN struct proc *rdy_tail[NR_SCHED_QUEUES]; /* ptrs to ready list tails */ 05597 05598 #endif /* PROC_H */ 05842 /* Privileges. */ 05843 #define INTR_PRIVILEGE 0 /* kernel and interrupt handlers */ 05844 #define TASK_PRIVILEGE 1 /* kernel tasks */ 05845 #define USER_PRIVILEGE 3 /* servers and user processes */ 06088 /* The system image table lists all programs that are part of the boot image. 06089 * The order of the entries here MUST agree with the order of the programs 06090 * in the boot image and all kernel tasks must come first. 06091 * Each entry provides the process number, flags, quantum size (qs), scheduling 06092 * queue, allowed traps, ipc mask, and a name for the process table. The 06093 * initial program counter and stack size is also provided for kernel tasks. 06094 */ 06095 PUBLIC struct boot_image image[] = { 06096 /* process nr, pc, flags, qs, queue, stack, traps, ipcto, call, name */ 06097 { IDLE, idle_task, IDL_F, 8, IDLE_Q, IDL_S, 0, 0, 0, "IDLE" }, 06098 { CLOCK,clock_task, TSK_F, 64, TASK_Q, TSK_S, TSK_T, 0, 0, "CLOCK" }, 06099 { SYSTEM, sys_task, TSK_F, 64, TASK_Q, TSK_S, TSK_T, 0, 0, "SYSTEM"}, 06100 { HARDWARE, 0, TSK_F, 64, TASK_Q, HRD_S, 0, 0, 0, "KERNEL"}, 06101 { PM_PROC_NR, 0, SRV_F, 32, 3, 0, SRV_T, SRV_M, PM_C, "pm" }, 06102 { FS_PROC_NR, 0, SRV_F, 32, 4, 0, SRV_T, SRV_M, FS_C, "fs" }, 06103 { RS_PROC_NR, 0, SRV_F, 4, 3, 0, SRV_T, SYS_M, RS_C, "rs" }, 06104 { TTY_PROC_NR, 0, SRV_F, 4, 1, 0, SRV_T, SYS_M, DRV_C, "tty" }, 06105 { MEM_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, DRV_M, MEM_C, "memory"}, 06106 { LOG_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, DRV_C, "log" }, 06107 { DRVR_PROC_NR, 0, SRV_F, 4, 2, 0, SRV_T, SYS_M, DRV_C, "driver"}, 06108 { INIT_PROC_NR, 0, USR_F, 8, USER_Q, 0, USR_T, USR_M, 0, "init" }, 06109 }; 06110 06374 .define _divide_error 06375 .define _single_step_exception 06376 .define _nmi 06377 .define _breakpoint_exception 06378 .define _overflow 06379 .define _bounds_check 06380 .define _inval_opcode 06381 .define _copr_not_available 06382 .define _double_fault 06383 .define _copr_seg_overrun 06384 .define _inval_tss 06385 .define _segment_not_present 06386 .define _stack_exception 06387 .define _general_protection 06388 .define _page_fault 06389 .define _copr_error 07127 /*===========================================================================* 07128 * main * 07129 *===========================================================================*/ 07130 PUBLIC void main() 07132 /* Start the ball rolling. */ _________________________ Page 719 File: kernel/main.c _________________________ 07145 07146 /* Clear the process table. Anounce each slot as empty and set up mappings 07147 * for proc_addr() and proc_nr() macros. Do the same for the table with 07148 * privilege structures for the system processes. 07149 */ 07150 for (rp = BEG_PROC_ADDR, i = -NR_TASKS; rp < END_PROC_ADDR; ++rp, ++i) { 07151 rp->p_rts_flags = SLOT_FREE; /* initialize free slot */ 07152 rp->p_nr = i; /* proc number from ptr */ 07153 (pproc_addr + NR_TASKS)[i] = rp; /* proc ptr from number */ 07154 } 05567 #define IDLE_Q 15 /* lowest, only IDLE process goes here * 05563 #define TASK_Q 0 /* highest, used for kernel tasks */ 07161 /* Set up proc table entries for tasks and servers. The stacks of the 07162 * kernel tasks are initialized to an array in data space. The stacks 07163 * of the servers have been added to the data segment by the monitor, so 07164 * the stack pointer is set to the end of the data segment. All the 07165 * processes are in low memory on the 8086. On the 386 only the kernel 07166 * is in low memory, the rest is loaded in extended memory. 07167 */ 07168 07169 /* Task stacks. */ 07170 ktsb = (reg_t) t_stack; 07171 07172 for (i=0; i < NR_BOOT_PROCS; ++i) { 07173 ip = &image[i]; /* process' attributes */ 07174 rp = proc_addr(ip->proc_nr); /* get process pointer */ 07175 rp->p_max_priority = ip->priority; /* max scheduling priority */ 07176 rp->p_priority = ip->priority; /* current priority */ 07177 rp->p_quantum_size = ip->quantum; /* quantum size in ticks */ 07178 rp->p_ticks_left = ip->quantum; /* current credit */ 07179 strncpy(rp->p_name, ip->proc_name, P_NAME_LEN); /* set process name */ 07180 (void) get_priv(rp, (ip->flags & SYS_PROC)); /* assign structure */ 07181 priv(rp)->s_flags = ip->flags; /* process flags */ 07182 priv(rp)->s_trap_mask = ip->trap_mask; /* allowed traps */ 07183 priv(rp)->s_call_mask = ip->call_mask; /* kernel call mask */ 07184 priv(rp)->s_ipc_to.chunk[0] = ip->ipc_to; /* restrict targets */ 07185 if (iskerneln(proc_nr(rp))) { /* part of the kernel? */ 07186 if (ip->stksize > 0) { /* HARDWARE stack size is 0 */ 07187 rp->p_priv->s_stack_guard = (reg_t *) ktsb; 07188 *rp->p_priv->s_stack_guard = STACK_GUARD; 07189 } 07190 ktsb += ip->stksize; /* point to high end of stack */ 07191 rp->p_reg.sp = ktsb; /* this task's initial stack ptr */ 07192 text_base = kinfo.code_base >> CLICK_SHIFT; 07193 /* processes that are in the kernel */ 07194 hdrindex = 0; /* all use the first a.out header */ 07195 } else { 07196 hdrindex = 1 + i-NR_TASKS; /* servers, drivers, INIT */ 07197 } 07198 07199 /* The bootstrap loader created an array of the a.out headers at 07200 * absolute address 'aout'. Get one element to e_hdr. 07201 */ 07202 phys_copy(aout + hdrindex * A_MINHDR, vir2phys(&e_hdr), 07203 (phys_bytes) A_MINHDR); 07204 /* Convert addresses to clicks and build process memory map */ _________________________ Page 720 File: kernel/main.c _________________________ 07205 text_base = e_hdr.a_syms >> CLICK_SHIFT; 07206 text_clicks = (e_hdr.a_text + CLICK_SIZE-1) >> CLICK_SHIFT; 07207 if (!(e_hdr.a_flags & A_SEP)) text_clicks = 0; /* common I&D */ 07208 data_clicks = (e_hdr.a_total + CLICK_SIZE-1) >> CLICK_SHIFT; 07209 rp->p_memmap[T].mem_phys = text_base; 07210 rp->p_memmap[T].mem_len = text_clicks; 07211 rp->p_memmap[D].mem_phys = text_base + text_clicks; 07212 rp->p_memmap[D].mem_len = data_clicks; 07213 rp->p_memmap[S].mem_phys = text_base + text_clicks + data_clicks; 07214 rp->p_memmap[S].mem_vir = data_clicks; /* empty - stack is in data */ 07223 /* Initialize the server stack pointer. Take it down one word 07224 * to give crtso.s something to use as "argc". 07225 */ 07226 if (isusern(proc_nr(rp))) { /* user-space process? */ 07227 rp->p_reg.sp = (rp->p_memmap[S].mem_vir + 07228 rp->p_memmap[S].mem_len) << CLICK_SHIFT; 07229 rp->p_reg.sp -= sizeof(reg_t); 07230 } 07231 07232 /* Set ready. The HARDWARE task is never ready. */ 07233 if (rp->p_nr != HARDWARE) { 07234 rp->p_rts_flags = 0; /* runnable if no flags */ 07235 lock_enqueue(rp); /* add to scheduling queues */ 07236 } else { 07237 rp->p_rts_flags = NO_MAP; /* prevent from running */ 07238 } ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/proc.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 07400 /* This file contains essentially all of the process and message handling. 07401 * Together with "mpx.s" it forms the lowest layer of the MINIX kernel. 07402 * There is one entry point from the outside: 07403 * 07404 * sys_call: a system call, i.e., the kernel is trapped with an INT 07405 * 07406 * As well as several entry points used from the interrupt and task level: 07407 * 07408 * lock_notify: notify a process of a system event 07409 * lock_send: send a message to a process 07410 * lock_enqueue: put a process on one of the scheduling queues 07411 * lock_dequeue: remove a process from the scheduling queues 07412 * 07413 * Changes: 07414 * Aug 19, 2005 rewrote scheduling code (Jorrit N. Herder) 07415 * Jul 25, 2005 rewrote system call handling (Jorrit N. Herder) 07416 * May 26, 2005 rewrote message passing functions (Jorrit N. Herder) 07417 * May 24, 2005 new notification system call (Jorrit N. Herder) 07418 * Oct 28, 2004 nonblocking send and receive calls (Jorrit N. Herder) 07419 * _________________________ Page 723 File: kernel/proc.c _________________________ 07420 * The code here is critical to make everything work and is important for the 07421 * overall performance of the system. A large fraction of the code deals with 07422 * list manipulation. To make this both easy to understand and fast to execute 07423 * pointer pointers are used throughout the code. Pointer pointers prevent 07424 * exceptions for the head or tail of a linked list. 07425 * 07426 * node_t *queue, *new_node; // assume these as global variables 07427 * node_t **xpp = &queue; // get pointer pointer to head of queue 07428 * while (*xpp != NULL) // find last pointer of the linked list 07429 * xpp = &(*xpp)->next; // get pointer to next pointer 07430 * *xpp = new_node; // now replace the end (the NULL pointer) 07431 * new_node->next = NULL; // and mark the new end of the list 07432 * 07433 * For example, when adding a new node to the end of the list, one normally 07434 * makes an exception for an empty list and looks up the end of the list for 07435 * nonempty lists. As shown above, this is not required with pointer pointers. 07436 */ 07477 /*===========================================================================* 07478 * sys_call * 07479 *===========================================================================*/ 07480 PUBLIC int sys_call(call_nr, src_dst, m_ptr) 07481 int call_nr; /* system call number and flags */ 07482 int src_dst; /* src to receive from or dst to send to */ 07483 message *m_ptr; /* pointer to message in the caller's space */ 07484 { 07485 /* System calls are done by trapping to the kernel with an INT instruction. 07486 * The trap is caught and sys_call() is called to send or receive a message 07487 * (or both). The caller is always given by 'proc_ptr'. 07488 */ 05329 EXTERN struct proc *proc_ptr; /* pointer to currentl 07784 /*===========================================================================* 07785 * enqueue * 07786 *===========================================================================*/ 07787 PRIVATE void enqueue(rp) 07788 register struct proc *rp; /* this process is now runnable */ 07789 { 07790 /* Add 'rp' to one of the queues of runnable processes. This function is 07791 * responsible for inserting a process into one of the scheduling queues. 07792 * The mechanism is implemented here. The actual scheduling policy is 07793 * defined in sched() and pick_proc(). 07794 */ 07795 int q; /* scheduling queue to use */ 07796 int front; /* add to front or back */ 07797 07798 /* Determine where to insert to process. */ 07799 sched(rp, &q, &front); 07800 07801 /* Now add the process to the queue. */ 07802 if (rdy_head[q] == NIL_PROC) { /* add to empty queue */ 07803 rdy_head[q] = rdy_tail[q] = rp; /* create a new queue */ 07804 rp->p_nextready = NIL_PROC; /* mark new end */ 07805 } 07806 else if (front) { /* add to head of queue */ 07807 rp->p_nextready = rdy_head[q]; /* chain head of queue */ 07808 rdy_head[q] = rp; /* set new queue head */ 07809 } 07810 else { /* add to tail of queue */ 07811 rdy_tail[q]->p_nextready = rp; /* chain tail of queue */ 07812 rdy_tail[q] = rp; /* set new queue tail */ 07813 rp->p_nextready = NIL_PROC; /* mark new end */ 07814 } 07815 07816 /* Now select the next process to run. */ 07817 pick_proc(); 07818 } sched() 06503 jmp _main ! main() 07820 /*===========================================================================* 07821 * dequeue * 07822 *===========================================================================*/ 07823 PRIVATE void dequeue(rp) 07824 register struct proc *rp; /* this process is no longer runnable */ 07825 { 07826 /* A process must be removed from the scheduling queues, for example, because 07827 * it has blocked. If the currently active process is removed, a new process 07828 * is picked to run by calling pick_proc(). 07829 */ 07830 register int q = rp->p_priority; /* queue to use */ 07831 register struct proc **xpp; /* iterate over queue */ 07832 register struct proc *prev_xp; 07833 07834 /* Side-effect for kernel: check if the task's stack still is ok? */ 07835 if (iskernelp(rp)) { _________________________ Page 730 File: kernel/proc.c _________________________ 07836 if (*priv(rp)->s_stack_guard != STACK_GUARD) 07837 panic("stack overrun by task", proc_nr(rp)); 07838 } 07839 07840 /* Now make sure that the process is not in its ready queue. Remove the 07841 * process if it is found. A process can be made unready even if it is not 07842 * running by being sent a signal that kills it. 07843 */ 07844 prev_xp = NIL_PROC; 07845 for (xpp = &rdy_head[q]; *xpp != NIL_PROC; xpp = &(*xpp)->p_nextready) { 07846 07847 if (*xpp == rp) { /* found process to remove */ 07848 *xpp = (*xpp)->p_nextready; /* replace with next chain */ 07849 if (rp == rdy_tail[q]) /* queue tail removed */ 07850 rdy_tail[q] = prev_xp; /* set new tail */ 07851 if (rp == proc_ptr || rp == next_ptr) /* active process removed */ 07852 pick_proc(); /* pick new process to run */ 07853 break; 07854 } 07855 prev_xp = *xpp; /* save previous in chain */ 07856 } 07857 } 07859 /*===========================================================================* 07860 * sched * 07861 *===========================================================================*/ 07862 PRIVATE void sched(rp, queue, front) 07863 register struct proc *rp; /* process to be scheduled */ 07864 int *queue; /* return: queue to use */ 07865 int *front; /* return: front or back */ 07866 { 07867 /* This function determines the scheduling policy. It is called whenever a 07868 * process must be added to one of the scheduling queues to decide where to 07869 * insert it. As a side-effect the process' priority may be updated. 07870 */ 07871 static struct proc *prev_ptr = NIL_PROC; /* previous without time */ 07872 int time_left = (rp->p_ticks_left > 0); /* quantum fully consumed */ 07873 int penalty = 0; /* change in priority */ 07874 07875 /* Check whether the process has time left. Otherwise give a new quantum 07876 * and possibly raise the priority. Processes using multiple quantums 07877 * in a row get a lower priority to catch infinite loops in high priority 07878 * processes (system servers and drivers). 07879 */ 07880 if ( ! time_left) { /* quantum consumed ? */ 07881 rp->p_ticks_left = rp->p_quantum_size; /* give new quantum */ 07882 if (prev_ptr == rp) penalty ++; /* catch infinite loops */ 07883 else penalty --; /* give slow way back */ 07884 prev_ptr = rp; /* store ptr for next */ 07885 } 07886 07887 /* Determine the new priority of this process. The bounds are determined 07888 * by IDLE's queue and the maximum priority of this process. Kernel tasks 07889 * and the idle process are never changed in priority. 07890 */ 07891 if (penalty != 0 && ! iskernelp(rp)) { 07892 rp->p_priority += penalty; /* update with penalty */ 07893 if (rp->p_priority < rp->p_max_priority) /* check upper bound */ 07894 rp->p_priority=rp->p_max_priority; 07895 else if (rp->p_priority > IDLE_Q-1) /* check lower bound */ _________________________ Page 731 File: kernel/proc.c _________________________ 07896 rp->p_priority = IDLE_Q-1; 07897 } 07898 07899 /* If there is time left, the process is added to the front of its queue, 07900 * so that it can immediately run. The queue to use simply is always the 07901 * process' current priority. 07902 */ 07903 *queue = rp->p_priority; 07904 *front = time_left; 07905 } 07907 /*===========================================================================* 07908 * pick_proc * 07909 *===========================================================================*/ 07910 PRIVATE void pick_proc() 07911 { 07912 /* Decide who to run now. A new process is selected by setting 'next_ptr'. 07913 * When a billable process is selected, record it in 'bill_ptr', so that the 07914 * clock task can tell who to bill for system time. 07915 */ 07916 register struct proc *rp; /* process to run */ 07917 int q; /* iterate over queues */ 07918 07919 /* Check each of the scheduling queues for ready processes. The number of 07920 * queues is defined in proc.h, and priorities are set in the image table. 07921 * The lowest queue contains IDLE, which is always ready. 07922 */ 07923 for (q=0; q < NR_SCHED_QUEUES; q++) { 07924 if ( (rp = rdy_head[q]) != NIL_PROC) { 07925 next_ptr = rp; /* run process 'rp' next */ 07926 if (priv(rp)->s_flags & BILLABLE) 07927 bill_ptr = rp; /* bill for system time */ 07928 return; 07929 } 07930 } 07931 } 07948 /*===========================================================================* 07949 * lock_enqueue * 07950 *===========================================================================*/ 07951 PUBLIC void lock_enqueue(rp) 07952 struct proc *rp; /* this process is now runnable */ 07953 { 07954 /* Safe gateway to enqueue() for tasks. */ 07955 lock(3, "enqueue"); _________________________ Page 732 File: kernel/proc.c _________________________ 07956 enqueue(rp); 07957 unlock(3); 07958 } 07960 /*===========================================================================* 07961 * lock_dequeue * 07962 *===========================================================================*/ 07963 PUBLIC void lock_dequeue(rp) 07964 struct proc *rp; /* this process is no longer runnable */ 07965 { 07966 /* Safe gateway to dequeue() for tasks. */ 07967 lock(4, "dequeue"); 07968 dequeue(rp); 07969 unlock(4); 07970 } ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/klib.s ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 08700 # 08701 ! Chooses between the 8086 and 386 versions of the low level kernel code. 08821 .define _phys_insw ! transfer data from (disk controller) port to memory 08823 .define _phys_outsw ! transfer data from memory to (disk controller) port 08827 .define _phys_copy ! copy data from anywhere to anywhere in memory 08828 .define _phys_memset ! write pattern anywhere in memory 09194 !*===========================================================================* 09195 !* phys_copy * 09196 !*===========================================================================* 09197 ! PUBLIC void phys_copy(phys_bytes source, phys_bytes destination, 09198 ! phys_bytes bytecount); 09199 ! Copy a block of physical memory. 10315 /*===========================================================================* 10316 * do_exec * 10317 *===========================================================================*/ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/clock.c ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 09450 PUBLIC void kprintf(const char *fmt, ...) 10485 case HARD_INT: 10486 result = do_clocktick(&m); /* handle clock tick */ 10489 kprintf("CLOCK: illegal request %d from %d.\n", m.m_type,m.m_source); 10494 /*===========================================================================* 10495 * do_clocktick * 10496 *===========================================================================*/ 10497 PRIVATE int do_clocktick(m_ptr) 10498 message *m_ptr; /* pointer to request message */ 10499 { 10500 /* Despite its name, this routine is not called on every clock tick. It 10501 * is called on those clock ticks when a lot of work needs to be done. 10502 */ 10503 10504 /* A process used up a full quantum. The interrupt handler stored this 10505 * process in 'prev_ptr'. First make sure that the process is not on the 10506 * scheduling queues. Then announce the process ready again. Since it has 10507 * no more time left, it gets a new quantum and is inserted at the right 10508 * place in the queues. As a side-effect a new process will be scheduled. 10509 */ 10510 if (prev_ptr->p_ticks_left <= 0 && priv(prev_ptr)->s_flags & PREEM 10511 lock_dequeue(prev_ptr); /* take it off the queues */ 10512 lock_enqueue(prev_ptr); /* and reinsert it again */ 10513 } 10514 10526 /*===========================================================================* 10527 * init_clock * 10528 *===========================================================================*/ 10529 PRIVATE void init_clock() 10530 { 10531 /* Initialize the CLOCK's interrupt hook. */ 10532 clock_hook.proc_nr = CLOCK; 10533 10534 /* Initialize channel 0 of the 8253A timer to, e.g., 60 Hz. */ 10535 outb(TIMER_MODE, SQUARE_WAVE); /* set timer to run continuously */ 10536 outb(TIMER0, TIMER_COUNT); /* load timer low byte */ 10537 outb(TIMER0, TIMER_COUNT >> 8); /* load timer high byte */ 10538 put_irq_handler(&clock_hook, CLOCK_IRQ, clock_handler);/* register handler */ 10539 enable_irq(&clock_hook); /* ready for clock interrupts */ 10540 } 10553 /*===========================================================================* 10554 * clock_handler * 10555 *===========================================================================*/ 10556 PRIVATE int clock_handler(hook) 10557 irq_hook_t *hook; 10558 { 10559 /* This executes on each clock tick (i.e., every time the timer chip generates 10560 * an interrupt). It does a little bit of work so the clock task does not have 10561 * to be called on every tick. The clock task is called when: 10562 * 10563 * (1) the scheduling quantum of the running process has expired, or 10564 * (2) a timer has expired and the watchdog function should be run. 10565 * 10566 * Many global global and static variables are accessed here. The safety of 10567 * this must be justified. All scheduling and message passing code acquires a 10568 * lock by temporarily disabling interrupts, so no conflicts with calls from 10569 * the task level can occur. Furthermore, interrupts are not reentrant, the 10570 * interrupt handler cannot be bothered by other interrupts. 10571 * 10572 * Variables that are updated in the clock's interrupt handler: 10573 * lost_ticks: 10574 * Clock ticks counted outside the clock task. This for example _________________________ Page 768 File: kernel/clock.c _________________________ 10575 * is used when the boot monitor processes a real mode interrupt. 10576 * realtime: 10577 * The current uptime is incremented with all outstanding ticks. 10578 * proc_ptr, bill_ptr: 10579 * These are used for accounting. It does not matter if proc.c 10580 * is changing them, provided they are always valid pointers, 10581 * since at worst the previous process would be billed. 10582 */ 10583 register unsigned ticks; 10584 10585 /* Acknowledge the PS/2 clock interrupt. */ 10586 if (machine.ps_mca) outb(PORT_B, inb(PORT_B) | CLOCK_ACK_BIT); 10587 10588 /* Get number of ticks and update realtime. */ 10589 ticks = lost_ticks + 1; 10590 lost_ticks = 0; 10591 realtime += ticks; 10592 10593 /* Update user and system accounting times. Charge the current process for 10594 * user time. If the current process is not billable, that is, if a non-user 10595 * process is running, charge the billable process for system time as well. 10596 * Thus the unbillable process' user time is the billable user's system time. 10597 */ 10598 proc_ptr->p_user_time += ticks; 10599 if (priv(proc_ptr)->s_flags & PREEMPTIBLE) { 10600 proc_ptr->p_ticks_left -= ticks; 10601 } 10602 if (! (priv(proc_ptr)->s_flags & BILLABLE)) { 10603 bill_ptr->p_sys_time += ticks; 10604 bill_ptr->p_ticks_left -= ticks; 10605 } 10606 10607 /* Check if do_clocktick() must be called. Done for alarms and scheduling. 10608 * Some processes, such as the kernel tasks, cannot be preempted. 10609 */ 10610 if ((next_timeout <= realtime) || (proc_ptr->p_ticks_left <= 0)) { 10611 prev_ptr = proc_ptr; /* store running process */ 10612 lock_notify(HARDWARE, CLOCK); /* send notification */ 10613 } 10614 return(1); /* reenable interrupts */ 10615 } 11669 /*===========================================================================* 11670 * main * 11671 *===========================================================================*/ 11672 PUBLIC int main(void) 11673 { 11674 /* Main program. Initialize the memory driver and start the main loop. */ 11675 m_init(); 11676 driver_task(&m_dtab); 11677 return(OK); 11678 }