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("Ane1"); // "Ane1"はアセット名、つまりコンテンツ追加時に付けた(自動で付いた)名前
などとしてオブジェクト変数に読み込み、適切なオブジェクトと関連付ける。


「テクスチャ・マッピングの利用」

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

ぜったいにどこかにもっとマシなまとめがあるであろうTipsシリーズ


Ctrl-X テキストを選択していない時、カーソル行のカット
Ctrl-C テキストを選択していない時、カーソル行のコピー
Ctrl-V カットした行のペースト

Ctrl-E, C
Ctrl-K, Ctrl-C
選択行のコメントアウト
Ctrl-E, U
Ctrl-K, Ctrl-U
選択行のコメントイン

条件なしの禁止について

プログラミング言語で、ある記述が可能なときに、そう書いてもよい例外条件の明示なしに、「そう書いてはいけない」と禁止するのは、ちびっこの手足を縛るだけなんじゃないだろうか。過保護なんじゃないだろうか。

おいさんも昔は相当悪かったからね。カサカサカサカサーっつって。

おまけ

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

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	}