Go to main content
Oracle® Solaris 11.3 デバイスドライバの記述

印刷ビューの終了

更新: 2016 年 11 月
 
 

ファイル記述子に対する入出力の多重化

スレッドは、時には複数のファイル記述子に対する入出力を処理することが必要になります。1 つの例として、温度検知デバイスから温度を読み取ったあと、その温度を対話型ディスプレイに報告する必要があるアプリケーションプログラムがあります。使用可能なデータがない状態で読み取り要求を行うプログラムは、ユーザーとふたたび対話する前の、温度の待機中にブロックされるべきではありません。

poll(2) システムコールはユーザーに、開かれたファイルを参照する一連のファイル記述子に対する入出力を多重化するためのメカニズムを提供します。poll(2) は、プログラムがブロックを使用せずにデータを送受信できるファイル記述子、または特定のイベントが発生したファイル記述子を識別します。

プログラムが文字ドライバをポーリングできるようにするには、そのドライバが chpoll(9E) エントリポイントを実装する必要があります。システムは、ユーザープロセスが、デバイスに関連付けられたファイル記述子に対する poll(2) システムコールを発行したときに chpoll(9E) を呼び出します。 chpoll(9E) エントリポイントのルーチンは、ポーリングをサポートする必要のある、STREAMS 以外の文字デバイスドライバによって使用されます。

chpoll(9E) 関数は、次の構文を使用します。

int xxchpoll(dev_t dev, short events, int anyyet, short *reventsp,
     struct pollhead **phpp);

chpoll(9E) エントリポイントでは、ドライバは次の規則に従う必要があります。

  • chpoll(9E) エントリポイントが呼び出されるときは、次のアルゴリズムを実装します。

    if ( /* events are satisfied now */ ) {
        *reventsp = mask_of_satisfied_events
    } else {
        *reventsp = 0;
        if (!anyyet)
            *phpp = &local_pollhead_structure;
    }
    return (0);

    チェックするイベントの説明については、chpoll(9E) のマニュアルページを参照してください。chpoll (9E) エントリポイントはこのとき、*reventsp に戻りイベントを設定することによって、満たされたイベントのマスクを返します。

    イベントが発生していない場合、そのイベントの戻りフィールドはクリアされます。anyyet フィールドが設定されていない場合、ドライバは pollhead 構造体のインスタンスを返す必要があります。pollhead 構造体は通常、状態構造体内に割り当てられます。この pollhead 構造体は、ドライバによって不透明として扱われます。pollhead のどのフィールドも参照するべきではありません。

  • 使用例 78 に示されているタイプ events のデバイス条件が発生した場合は常に、pollwakeup(9F) を呼び出します。この関数は、一度に 1 つのイベントでのみ呼び出されます。条件が発生した場合は、割り込みルーチンで pollwakeup(9F) を呼び出すことができます。

使用例 78使用例 79 は、ポーリング手法の実装方法および pollwakeup (9F) の使用方法を示しています。

次の例は、POLLIN イベントと POLLERR イベントを処理する方法を示しています。ドライバはまず、デバイスの現在のステータスを判定するために、ステータスレジスタを読み取ります。パラメータ events は、ドライバがチェックする条件を指定します。該当する条件が発生した場合、ドライバは *reventsp 内のそのビットを設定します。どの条件も発生せず、かつ anyyet が設定されていない場合は、pollhead 構造体のアドレスが *phpp で返されます。

使用例 78  chpoll (9E) ルーチン
static int
xxchpoll(dev_t dev, short events, int anyyet,
    short *reventsp, struct pollhead **phpp)
{
     uint8_t status;
     short revent;
     struct xxstate *xsp;

     xsp = ddi_get_soft_state(statep, getminor(dev));
     if (xsp == NULL)
         return (ENXIO);
     revent = 0;
     /*
      * Valid events are:
      * POLLIN | POLLOUT | POLLPRI | POLLHUP | POLLERR
      * This example checks only for POLLIN and POLLERR.
      */
     status = ddi_get8(xsp->data_access_handle, &xsp->regp->csr);
     if ((events & POLLIN) && data available to read) {
        revent |= POLLIN;
     }
     if (status & DEVICE_ERROR) {
        revent |= POLLERR;
     }
     /* if nothing has occurred */
     if (revent == 0) {
        if (!anyyet) {
        *phpp = &xsp->pollhead;
        }
     }
       *reventsp = revent;
     return (0);
}

次の例は、pollwakeup(9F) 関数の使用方法を示しています。 pollwakeup(9F) 関数は通常、サポートされている条件が発生したときに割り込みルーチンで呼び出されます。割り込みルーチンはステータスレジスタからステータスを読み取り、これらの条件をチェックします。次に、ポーリングスレッドにもう一度チェックすることを通知するために、イベントごとに pollwakeup(9F) を呼び出します。何らかのロックが保持された状態で pollwakeup (9F) を呼び出すと、別のルーチンが chpoll(9E) に入り、同じロックをつかもうとしてデッドロックが発生する可能性があるため、これを行うべきではありません。

使用例 79   chpoll(9E) をサポートしている割り込みルーチン
static u_int
xxintr(caddr_t arg)
{
     struct xxstate *xsp = (struct xxstate *)arg;
     uint8_t    status;
     /* normal interrupt processing */
     /* ... */
     status = ddi_get8(xsp->data_access_handle, &xsp->regp->csr);
     if (status & DEVICE_ERROR) {
        pollwakeup(&xsp->pollhead, POLLERR);
     }
     if ( /* just completed a read */ ) {
        pollwakeup(&xsp->pollhead, POLLIN);
     }
     /* ... */
     return (DDI_INTR_CLAIMED);
}