ディレクトリ構成

/
└─ usr
    ├─ include(stdio.h等のヘッダ)
    │  └─ w32api(windows.h等のwindowsヘッダ)
    │            (windowsのランライムライブラリ用のcファイル)
    │
    ├─ bin(cygwin1.dll等)
    │      (gcc,x86_64-pc-cygwin-gcc,x86_64-w64-mingw32-gcc,i686-w64-mingw32-gcc)
    │
    ├─ lib(crt0.o、libc.a、libcygwin.a等の静的ライブラリ)
    │  ├─ gcc
    │  │  ├─ x86_64-pc-cygwin
    │  │  │  └─ 5.4.0(cc1,collect2等のバイナリ、crtbegin.o,crtend.o、libgcc.a、libssp.a等の静的ライブラリ,libssp.dll.a等のインポートライブラリ)
    │  │  │        └─ include(stddef.h等のヘッダ)
    │  │  │
    │  │  ├─ x86_64-w64-mingw32
    │  │  │  └─ 5.4.0(cc1,collect2等のバイナリ、crtbegin.o,crtend.o、libgcc.a、libssp.a等の静的ライブラリ,libssp.dll.a等のインポートライブラリ)
    │  │  │        └─ include(stddef.h等のヘッダ)
    │  │  │
    │  │  └─ i686-w64-mingw32
    │  │      └─ 5.4.0(cc1,collect2等のバイナリ、crtbegin.o,crtend.o、libgcc.a、libssp.a等の静的ライブラリ,libssp.dll.a等のインポートライブラリ)
    │  │          └─ include(stddef.h等のヘッダ)
    │  │
    │  └─ w32api(libuser32.a等のwindowsの静的ライブラリ)
    │
    ├─ x86_64-w64-mingw32
    │  └─ sys-root
    │      └─ mingw
    │          └─ bin(gccのDLL(libssp,dllなど))
    │
    └─ i686-w64-mingw32
        └─ sys-root
            └─ mingw
                └─ bin(gccのDLL(libssp,dllなど))



フォント

使用するフォント

ReactOSの日本語のフォントはDroid Sans Fallbackが標準になっているようですが、svnからダウンロードしたReactOSのソースには、Droid Sans Fallbackは含まれていないようです。
そのため、Droid Sans Fallbackのフォントを入れてみたのですが、設定の方法がきちんと理解できていないこともあり、フォントをちゃんと設定することができませんでした(半角がすべて□になってしまいました。)。

そのため、Drroid Sans Fallbackの導入については、あまり追及するのをやめ、非公式ReactOS日本語版パッケージ配布所でも使われていた、梅フォントで設定することにしました。

フォントのインストール方法

フォントのファイルをダブルクリックすると、インストールボタンが表示されるので、インストールボタンを押すことで、フォントがインストールできます。

レジストリ

FontLinkが動作していないようなので、レジストリのうち、tahoma関係を書き換えます。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes\

Helv REG_SZ Ume Gothic
MS Sans Serif REG_SZ Ume Gothic
MS Shell Dlg REG_SZ Ume UI Gothic
MS Shell Dlg 2 REG_SZ Ume UI Gothic
MS UI Gothic REG_SZ Ume UI Gothic
MS UI Gothic 2 REG_SZ Ume UI Gothic
Tahoma REG_SZ Ume Gothic

フォントの初期設定

コントロールパネルの上級者向け設定にある、非UNICODEプログラムの言語バージョンをJapanease以外からJapaneseにすると、初期設定のままでは、使うフォントがDrid Sans FallBackとなりますが、Droid Sans FallBackをインストールしていない場合には、文字化け(文字が□になる。)が起こります。

これは、レジストリが、font.infで初期化されるためですので、fonts.inf(c:\ReactOS\inf\font.inf ソースの場合には、reactos/media/inf/font.inf)に正しい初期値を設定します。
Font.CJK.Regをもとに、「Droid Sans Fallback」を「Ume Gothic」等のお好みのフォント名に置き換えたFont.Japan.Regを作ります。

[Font.Japan.Reg]
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Arial",0x00000000,"Liberation Sans"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Courier",0x00000000,"FreeMono"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Courier New",0x00000000,"FreeMono"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Fixedsys",0x00000000,"Fixedsys Excelsior 3.01-L2"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Helv",0x00000000,"Ume Gothic"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Helvetica",0x00000000,"Liberation Sans"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Lucida Console",0x00000000,"DejaVu Sans Mono"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","MS Sans Serif",0x00000000,"Ume Gothic"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","MS Shell Dlg",0x00000000,"Ume UI Gothic"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","MS Shell Dlg 2",0x00000000,"Ume UI Gothic"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","MS UI Gothic",0x00000000,"Ume UI Gothic"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","MS UI Gothic 2",0x00000000,"Ume UI Gothic"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Tahoma",0x00000000,"Ume Gothic"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Terminal",0x00000000,"DejaVu Sans Mono"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Times",0x00000000,"Liberation Serif"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Times New Roman",0x00000000,"Liberation Serif"
HKLM,"SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontSubstitutes","Tms Rmn",0x00000000,"Liberation Serif"

cp932(Shift-JIS)の参照先を、Font.CJK.Regから上で作ったFont.Japan.Regに変更します。)

; cp932/cp932 Japanese
[Font.CP932.96]
AddReg = Font.Reg.96
AddReg = Font.Japan.Reg

[Font.CP932.120]
AddReg = Font.Reg.120
AddReg = Font.Japan.Reg

注意

SJISのソフトウェアは、非UNICODE向けの言語バージョンをJapaneseにする前にインストールすると、スタートメニューなどが文字化けしまいます。
Japaneseにする前にインストールしたソフトウェアのスタートメニューは、後から非UNICODE向けの言語バージョンをJapaneseにしても直らないようです。

ime探検(2)タスクトレイ

タスクトレイの表示

windows2000
キーボード ステータスアイコン 選択表示
英語キーボード EN (アイコンあり)English(United States)
MS-IME MS-IMEのアイコン (アイコンあり)Microsoft IME 2000(Japanese)
MZ-IME MZ-IMEのアイコン (アイコンあり)MZ-IME日本語入力 0.0
ReactOS
キーボード ステータスアイコン 選択表示
英語キーボード EN (アイコンなし)米国
日本語キーボード JA (アイコンなし)日本語
MZ-IME ?? (アイコンなし)mz-ime

英語キーボードや日本語キーボードが違うのはわかるとして、MZ-IMEの表示が全然違うのが気になる。
タスクトレイの表示は、kbswitch.exeが担当。

kbswitch.cのCreateTrayIcon(LPTSTR szLCID)では、

lId = (LANGID)_tcstoul(szLCID, NULL, 16);
if (GetLocaleInfo(lId,
                       LOCALE_SISO639LANGNAME,
                       szBuf,
                       ARRAYSIZE(szBuf)) == 0)
     {
         StringCchCopy(szBuf, ARRAYSIZE(szBuf), _T("??"));
     }

となっていて、LCIDがISO639LANGUAGENAMEで取得できなければ、"??"としてアイコンを作ることになっている。
これを、imeからアイコンを取得できるように修正すればいいのかな。

ime探検(1)調べものなど

問題

MZ-IMEをインストールしたが、コントロールパネルに出てこないので、選択できない。

対策など

レジストリに直接登録すると、コントロールパネルに出てくるようになり、選択できるようになる。
タスクトレイにも出てくるようになるが、windows2000とは、アイコン表示が異なる。

レジストリ

0411部分は、ロケールID(jaは0x0411)と思われる
ロケール ID (LCID) の一覧
頭4桁はなんでしょう?

windows10(x64_86)

MZ-IMEはインストールできたが、動作せず。

デフォルトの日本語キーボード
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Keyboard Layouts\00000411\

Layout Display Name REG_EXPAND_SZ @%SystemRoot%\system32\input.dll,-5061
Layout File REG_SZ KBDJPN.DLL
Layout Text REG_SZ Japanese

KBDJPN.DLLは、\Windows\system32にある。

MS-IME
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Keyboard Layouts\e0200411\

Ime File REG_SZ imjp14.ime
Layout Display Name REG_SZ Microsoft Office IME 2010
Layout File REG_SZ kbdjpn.dll
Layout Text REG_SZ Microsoft Office IME 2010

KBDJPN.DLL、IMJP14.IMEは、\Windows\system32にある。

MZ-IME
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Keyboard Layouts\E0120411\

IME file REG_SZ MZIMEJA.IME
layout file REG_SZ kbdjpn.dll
layout text REG_SZ 日本語(MZ-IME)

KBDJPN.DLLは、\Windows\system32にある。
mzimeja.imeは、\Windows\SysWOW64にある。

windows2000

デフォルトの日本語キーボード
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Keyboard Layouts\00000411\

Layout File REG_SZ KBDJPN.DLL
Layout Text REG_SZ Japanese

kbdjpn.dllは、\WINNT\system32にある。

MS-IME
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Keyboard Layouts\E00100411\

Ime File REG_SZ imejp.ime
Layout File REG_SZ Kbdjpn.dll
Layout Text REG_SZ Japanese Input System(MS-IME2000)

kbdjpn.dll、imejp.imeは、\WINNT\system32にある。

MZ-IME
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Keyboard Layouts\E0120411\

IME file REG_SZ MZIMEJA.IME
layout file REG_SZ kbdjpn.dll
layout text REG_SZ 日本語(MZ-IME)

kbdjpn.dll、mzimeja.imeは、\WINNT\system32にある。

ReactOS

デフォルトの日本語キーボード
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Keyboard Layouts\00000411\

Layout Display Name REG_SZ @%SystemRoot%\system32\input.dll,-5061
Layout File REG_SZ kbdja.dll
Layout ID REG_SZ 0001
Layout Text REG_SZ Japanese

kbdja.dllは、\ReactOS\system32にある。
Layout Display NameはREG_EXPAND_SZが正しいのかも
Layout IDは、謎

MZ-IME
レジストリには登録されていない。mzimeja.imeは、\ReactOS\system32にある。

ReactOS対策

windows2000を参考に、以下を作成する。
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Keyboard Layouts\E0120411\

Ime File REG_SZ mzimeja.ime
Layout File REG_SZ kbdja.dll
Layout Text REG_SZ mz-ime

kbdja.dll、mzimeja.imeは、\ReactOS\system32にある。
コントロールパネルにmz-imeが出てきて、選べるようになる。
また、タスクトレイのステータスアイコンを左クリックしても、選べるようになる。
入力は、日本語キーボードのレイアウト。ただし、半角/全角キーを押しても無反応。
また、デフォルトに設定することも可能だが、起動直後は英語キーボードの設定になってしまう。
再度、MZ-IMEに切り替えなおすと、日本語キーボードのレイアウトで入力できる。

しかし、ステータスアイコンを右クリックすると、英語キーボードの選択になってしまう。
MZ-IMEの呼び出しに失敗している模様

kalloc.c

// Physical memory allocator, intended to allocate
// memory for user processes, kernel stacks, page table pages,
// and pipe buffers. Allocates 4096-byte pages.

#include "types.h"
#include "defs.h"
#include "param.h"
#include "memlayout.h"
#include "mmu.h"
#include "spinlock.h"

void freerange(void *vstart, void *vend);
extern char end[]; // first address after kernel loaded from ELF file

struct run {
  struct run *next;
};

struct {
  struct spinlock lock;
  int use_lock;
  struct run *freelist;
} kmem;

// Initialization happens in two phases.
// 1. main() calls kinit1() while still using entrypgdir to place just
// the pages mapped by entrypgdir on free list.
// 2. main() calls kinit2() with the rest of the physical pages
// after installing a full page table that maps them on all cores.
void
kinit1(void *vstart, void *vend)
{
  initlock(&kmem.lock, "kmem");
  kmem.use_lock = 0;
  freerange(vstart, vend);
}

void
kinit2(void *vstart, void *vend)
{
  freerange(vstart, vend);
  kmem.use_lock = 1;
}

void
freerange(void *vstart, void *vend)
{
  char *p;
  p = (char*)PGROUNDUP((uint)vstart);
  for(; p + PGSIZE <= (char*)vend; p += PGSIZE)
    kfree(p);
}

//PAGEBREAK: 21
// Free the page of physical memory pointed at by v,
// which normally should have been returned by a
// call to kalloc().  (The exception is when
// initializing the allocator; see kinit above.)
void
kfree(char *v)
{
  struct run *r;

  if((uint)v % PGSIZE || v < end || V2P(v) >= PHYSTOP)
    panic("kfree");

  // Fill with junk to catch dangling refs.
  memset(v, 1, PGSIZE);

  if(kmem.use_lock)
    acquire(&kmem.lock);
  r = (struct run*)v;
  r->next = kmem.freelist;
  kmem.freelist = r;
  if(kmem.use_lock)
    release(&kmem.lock);
}

// Allocate one 4096-byte page of physical memory.
// Returns a pointer that the kernel can use.
// Returns 0 if the memory cannot be allocated.
char*
kalloc(void)
{
  struct run *r;

  if(kmem.use_lock)
    acquire(&kmem.lock);
  r = kmem.freelist;
  if(r)
    kmem.freelist = r->next;
  if(kmem.use_lock)
    release(&kmem.lock);
  return (char*)r;
}

swtch.S

# Context switch
#
#   void swtch(struct context **old, struct context *new);
# 
# Save current register context in old
# and then load register context from new.

.globl swtch
swtch:
  movl 4(%esp), %eax
  movl 8(%esp), %edx

  # Save old callee-save registers
  pushl %ebp
  pushl %ebx
  pushl %esi
  pushl %edi

  # Switch stacks
  movl %esp, (%eax)
  movl %edx, %esp

  # Load new callee-save registers
  popl %edi
  popl %esi
  popl %ebx
  popl %ebp
  ret

proc.c

#include "types.h"
#include "defs.h"
#include "param.h"
#include "memlayout.h"
#include "mmu.h"
#include "x86.h"
#include "proc.h"
#include "spinlock.h"

struct {
  struct spinlock lock;
  struct proc proc[NPROC];
} ptable;

static struct proc *initproc;

int nextpid = 1;
extern void forkret(void);
extern void trapret(void);

static void wakeup1(void *chan);

void
pinit(void)
{
  initlock(&ptable.lock, "ptable");
}

//PAGEBREAK: 32
// Look in the process table for an UNUSED proc.
// If found, change state to EMBRYO and initialize
// state required to run in the kernel.
// Otherwise return 0.
static struct proc*
allocproc(void)
{
  struct proc *p;
  char *sp;

  acquire(&ptable.lock);

  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
    if(p->state == UNUSED)
      goto found;

  release(&ptable.lock);
  return 0;

found:
  p->state = EMBRYO;
  p->pid = nextpid++;

  release(&ptable.lock);

  // Allocate kernel stack.
  if((p->kstack = kalloc()) == 0){
    p->state = UNUSED;
    return 0;
  }
  sp = p->kstack + KSTACKSIZE;

  // Leave room for trap frame.
  sp -= sizeof *p->tf;
  p->tf = (struct trapframe*)sp;

  // Set up new context to start executing at forkret,
  // which returns to trapret.
  sp -= 4;
  *(uint*)sp = (uint)trapret;

  sp -= sizeof *p->context;
  p->context = (struct context*)sp;
  memset(p->context, 0, sizeof *p->context);
  p->context->eip = (uint)forkret;

  return p;
}

//PAGEBREAK: 32
// Set up first user process.
void
userinit(void)
{
  struct proc *p;
  extern char _binary_initcode_start[], _binary_initcode_size[];

  p = allocproc();
  
  initproc = p;
  if((p->pgdir = setupkvm()) == 0)
    panic("userinit: out of memory?");
  inituvm(p->pgdir, _binary_initcode_start, (int)_binary_initcode_size);
  p->sz = PGSIZE;
  memset(p->tf, 0, sizeof(*p->tf));
  p->tf->cs = (SEG_UCODE << 3) | DPL_USER;
  p->tf->ds = (SEG_UDATA << 3) | DPL_USER;
  p->tf->es = p->tf->ds;
  p->tf->ss = p->tf->ds;
  p->tf->eflags = FL_IF;
  p->tf->esp = PGSIZE;
  p->tf->eip = 0;  // beginning of initcode.S

  safestrcpy(p->name, "initcode", sizeof(p->name));
  p->cwd = namei("/");

  // this assignment to p->state lets other cores
  // run this process. the acquire forces the above
  // writes to be visible, and the lock is also needed
  // because the assignment might not be atomic.
  acquire(&ptable.lock);

  p->state = RUNNABLE;

  release(&ptable.lock);
}

// Grow current process's memory by n bytes.
// Return 0 on success, -1 on failure.
int
growproc(int n)
{
  uint sz;

  sz = proc->sz;
  if(n > 0){
    if((sz = allocuvm(proc->pgdir, sz, sz + n)) == 0)
      return -1;
  } else if(n < 0){
    if((sz = deallocuvm(proc->pgdir, sz, sz + n)) == 0)
      return -1;
  }
  proc->sz = sz;
  switchuvm(proc);
  return 0;
}

// Create a new process copying p as the parent.
// Sets up stack to return as if from system call.
// Caller must set state of returned proc to RUNNABLE.
int
fork(void)
{
  int i, pid;
  struct proc *np;

  // Allocate process.
  if((np = allocproc()) == 0){
    return -1;
  }

  // Copy process state from p.
  if((np->pgdir = copyuvm(proc->pgdir, proc->sz)) == 0){
    kfree(np->kstack);
    np->kstack = 0;
    np->state = UNUSED;
    return -1;
  }
  np->sz = proc->sz;
  np->parent = proc;
  *np->tf = *proc->tf;

  // Clear %eax so that fork returns 0 in the child.
  np->tf->eax = 0;

  for(i = 0; i < NOFILE; i++)
    if(proc->ofile[i])
      np->ofile[i] = filedup(proc->ofile[i]);
  np->cwd = idup(proc->cwd);

  safestrcpy(np->name, proc->name, sizeof(proc->name));

  pid = np->pid;

  acquire(&ptable.lock);

  np->state = RUNNABLE;

  release(&ptable.lock);

  return pid;
}

// Exit the current process.  Does not return.
// An exited process remains in the zombie state
// until its parent calls wait() to find out it exited.
void
exit(void)
{
  struct proc *p;
  int fd;

  if(proc == initproc)
    panic("init exiting");

  // Close all open files.
  for(fd = 0; fd < NOFILE; fd++){
    if(proc->ofile[fd]){
      fileclose(proc->ofile[fd]);
      proc->ofile[fd] = 0;
    }
  }

  begin_op();
  iput(proc->cwd);
  end_op();
  proc->cwd = 0;

  acquire(&ptable.lock);

  // Parent might be sleeping in wait().
  wakeup1(proc->parent);

  // Pass abandoned children to init.
  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
    if(p->parent == proc){
      p->parent = initproc;
      if(p->state == ZOMBIE)
        wakeup1(initproc);
    }
  }

  // Jump into the scheduler, never to return.
  proc->state = ZOMBIE;
  sched();
  panic("zombie exit");
}

// Wait for a child process to exit and return its pid.
// Return -1 if this process has no children.
int
wait(void)
{
  struct proc *p;
  int havekids, pid;

  acquire(&ptable.lock);
  for(;;){
    // Scan through table looking for exited children.
    havekids = 0;
    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
      if(p->parent != proc)
        continue;
      havekids = 1;
      if(p->state == ZOMBIE){
        // Found one.
        pid = p->pid;
        kfree(p->kstack);
        p->kstack = 0;
        freevm(p->pgdir);
        p->pid = 0;
        p->parent = 0;
        p->name[0] = 0;
        p->killed = 0;
        p->state = UNUSED;
        release(&ptable.lock);
        return pid;
      }
    }

    // No point waiting if we don't have any children.
    if(!havekids || proc->killed){
      release(&ptable.lock);
      return -1;
    }

    // Wait for children to exit.  (See wakeup1 call in proc_exit.)
    sleep(proc, &ptable.lock);  //DOC: wait-sleep
  }
}

//PAGEBREAK: 42
// Per-CPU process scheduler.
// Each CPU calls scheduler() after setting itself up.
// Scheduler never returns.  It loops, doing:
//  - choose a process to run
//  - swtch to start running that process
//  - eventually that process transfers control
//      via swtch back to the scheduler.
void
scheduler(void)
{
  struct proc *p;

  for(;;){
    // Enable interrupts on this processor.
    sti();

    // Loop over process table looking for process to run.
    acquire(&ptable.lock);
    for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
      if(p->state != RUNNABLE)
        continue;

      // Switch to chosen process.  It is the process's job
      // to release ptable.lock and then reacquire it
      // before jumping back to us.
      proc = p;
      switchuvm(p);
      p->state = RUNNING;
      swtch(&cpu->scheduler, p->context);
      switchkvm();

      // Process is done running for now.
      // It should have changed its p->state before coming back.
      proc = 0;
    }
    release(&ptable.lock);

  }
}

// Enter scheduler.  Must hold only ptable.lock
// and have changed proc->state. Saves and restores
// intena because intena is a property of this
// kernel thread, not this CPU. It should
// be proc->intena and proc->ncli, but that would
// break in the few places where a lock is held but
// there's no process.
void
sched(void)
{
  int intena;

  if(!holding(&ptable.lock))
    panic("sched ptable.lock");
  if(cpu->ncli != 1)
    panic("sched locks");
  if(proc->state == RUNNING)
    panic("sched running");
  if(readeflags()&FL_IF)
    panic("sched interruptible");
  intena = cpu->intena;
  swtch(&proc->context, cpu->scheduler);
  cpu->intena = intena;
}

// Give up the CPU for one scheduling round.
void
yield(void)
{
  acquire(&ptable.lock);  //DOC: yieldlock
  proc->state = RUNNABLE;
  sched();
  release(&ptable.lock);
}

// A fork child's very first scheduling by scheduler()
// will swtch here.  "Return" to user space.
void
forkret(void)
{
  static int first = 1;
  // Still holding ptable.lock from scheduler.
  release(&ptable.lock);

  if (first) {
    // Some initialization functions must be run in the context
    // of a regular process (e.g., they call sleep), and thus cannot
    // be run from main().
    first = 0;
    iinit(ROOTDEV);
    initlog(ROOTDEV);
  }

  // Return to "caller", actually trapret (see allocproc).
}

// Atomically release lock and sleep on chan.
// Reacquires lock when awakened.
void
sleep(void *chan, struct spinlock *lk)
{
  if(proc == 0)
    panic("sleep");

  if(lk == 0)
    panic("sleep without lk");

  // Must acquire ptable.lock in order to
  // change p->state and then call sched.
  // Once we hold ptable.lock, we can be
  // guaranteed that we won't miss any wakeup
  // (wakeup runs with ptable.lock locked),
  // so it's okay to release lk.
  if(lk != &ptable.lock){  //DOC: sleeplock0
    acquire(&ptable.lock);  //DOC: sleeplock1
    release(lk);
  }

  // Go to sleep.
  proc->chan = chan;
  proc->state = SLEEPING;
  sched();

  // Tidy up.
  proc->chan = 0;

  // Reacquire original lock.
  if(lk != &ptable.lock){  //DOC: sleeplock2
    release(&ptable.lock);
    acquire(lk);
  }
}

//PAGEBREAK!
// Wake up all processes sleeping on chan.
// The ptable lock must be held.
static void
wakeup1(void *chan)
{
  struct proc *p;

  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++)
    if(p->state == SLEEPING && p->chan == chan)
      p->state = RUNNABLE;
}

// Wake up all processes sleeping on chan.
void
wakeup(void *chan)
{
  acquire(&ptable.lock);
  wakeup1(chan);
  release(&ptable.lock);
}

// Kill the process with the given pid.
// Process won't exit until it returns
// to user space (see trap in trap.c).
int
kill(int pid)
{
  struct proc *p;

  acquire(&ptable.lock);
  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
    if(p->pid == pid){
      p->killed = 1;
      // Wake process from sleep if necessary.
      if(p->state == SLEEPING)
        p->state = RUNNABLE;
      release(&ptable.lock);
      return 0;
    }
  }
  release(&ptable.lock);
  return -1;
}

//PAGEBREAK: 36
// Print a process listing to console.  For debugging.
// Runs when user types ^P on console.
// No lock to avoid wedging a stuck machine further.
void
procdump(void)
{
  static char *states[] = {
  [UNUSED]    "unused",
  [EMBRYO]    "embryo",
  [SLEEPING]  "sleep ",
  [RUNNABLE]  "runble",
  [RUNNING]   "run   ",
  [ZOMBIE]    "zombie"
  };
  int i;
  struct proc *p;
  char *state;
  uint pc[10];

  for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
    if(p->state == UNUSED)
      continue;
    if(p->state >= 0 && p->state < NELEM(states) && states[p->state])
      state = states[p->state];
    else
      state = "???";
    cprintf("%d %s %s", p->pid, state, p->name);
    if(p->state == SLEEPING){
      getcallerpcs((uint*)p->context->ebp+2, pc);
      for(i=0; i<10 && pc[i] != 0; i++)
        cprintf(" %p", pc[i]);
    }
    cprintf("\n");
  }
}