ide.c void ideintr(void)

トップページ
jupiteroak.hatenablog.com


ide.c
https://github.com/mit-pdos/xv6-public/blob/master/ide.c#L103

void ideintr(void)
{
  struct buf *b;

  // First queued buffer is the active request.
  acquire(&idelock);

  if((b = idequeue) == 0){
    release(&idelock);
    return;
  }
  idequeue = b->qnext;

  // Read data if needed.
  if(!(b->flags & B_DIRTY) && idewait(1) >= 0)
    insl(0x1f0, b->data, BSIZE/4);

  // Wake process waiting for this buf.
  b->flags |= B_VALID;
  b->flags &= ~B_DIRTY;
  wakeup(b);

  // Start disk on next buf in queue.
  if(idequeue != 0)
    idestart(idequeue);

  release(&idelock);
}

ideintr関数は、ハードディスクからバッファへデータを保存する処理や、ハードディスクへの書き出しが終わったバッファの状態を変更する処理を行います。


処理の内容

クリティカルセクションの入口を定める

acquire(&idelock);

ハードディスクの読み込み処理・書き出し処理を排他制御するために、acquire関数を呼び出してロックを取得し、クリティカルセクションの入口とします。

IDEキューの先頭バッファのアドレスを保存する

 if((b = idequeue) == 0){
    release(&idelock);
    return;
  }

IDEキュー(ハードディスクからの読み込み処理やハードディスクへの書き出し処理がなされるのを保留してあるバッファのリスト)の先頭バッファ(buf構造体変数)を指定するアドレスを、buf構造体へのポインタbに保存します。(b = idequeue) == 0 が真となる場合→IDEキューにバッファがない場合は、release関数を呼び出して取得していたロックを解放し、リターンします。

IDEキューの先頭を更新する

idequeue = b->qnext;

IDEキューの先頭バッファbが参照しているバッファを、IDEキューの新しい先頭バッファにします。

読み込みコマンドを発行後の場合はハードディスクのセクタから読み込んだデータ(512バイト)をバッファに保存する

if(!(b->flags & B_DIRTY) && idewait(1) >= 0)
    insl(0x1f0, b->data, BSIZE/4);

buf構造体へのポインタbに保存しておいた、IDEキューの以前の先頭バッファについての処理です。
idestart関数内でバッファbについての読み込みコマンド、または、書き出しコマンドがハードディスクドライブへ発行され、ハードディスクドライブ側の読み込み処理、または、書き出し処理が完了し、割り込みが発生した後に、ideintr関数が呼び出され、今に至っています。
!(b->flags & B_DIRTY) && idewait(1) >= 0 が真となる場合→バッファbのflagsメンバbit2の値が0、かつ、idewait関数の戻り値が0の場合→バッファbが保存しているデータをハードディスクへ書き出す必要がない状態、かつ、ハードディスクドライブ側でエラーが検出されていない場合は、insl関数を呼び出します。
insl命令(ポート出力命令)でI/Oポートアドレス0x1F0を指定することにより、ATAホストコントローラが持つData Registerから、バッファb(先頭アドレスがb->data・サイズがBSIZE/4×4のメモリ領域)にデータを保存します。

バッファの状態を示すフラグを変更する

b->flags |= B_VALID;
b->flags &= ~B_DIRTY;

この時点で、ハードディスクからバッファbへデータの読み込みが完了しているので、バッファbのflagsメンバの値を変更します。
B_VALID(#define B_VALID 0x2)をビット和代入することで、flagsメンバのbit1のみを1に設定します。バッファbのflagsメンバのbit1が1の時、バッファbがハードディスクから読み込んだデータを保存している状態であることを示しています。
また、ideintr関数が呼び出された時点で、バッファbからハードディスクへデータの書き出しが完了しているので、バッファbのflagsメンバの値を変更します。
~B_DIRTY(#define B_DIRTY 0x4)をビット積代入することで、flagsメンバのbit2のみを0に設定します。バッファbのflagsメンバのbit2が0の時、バッファbが保存しているデータをハードディスクへ書き出す必要がない状態であることを示しています。

ハードディスクの読み込み・書き出し処理が完了するまで休止状態だったプロセスを実行可能状態にする

wakeup(b);

wakeup関数を呼び出して、ハードディスクの読み込み処理・書き出し処理が完了するまでsleep状態(p->state = SLEEPING;)になっていたプロセス(iderw関数内でsleep関数を呼び出したプロセス)を、実行可能状態(p->state = RUNNABLE)にします。

IDEキュー内にバッファがある場合はidestart関数を呼び出す

 if(idequeue != 0)
    idestart(idequeue);

IDEキュー内にバッファが残っている場合は、idestart関数を呼び出します。

クリティカルセクションの出口を定める

release(&idelock);

release関数を呼び出してロックを取得し、クリティカルセクションの出口とします。