この節では、リアルタイムプロセスでの入出力について説明します。SunOS では、高速で非同期的な入出力操作を実行するために、インタフェースと呼び出しの 2 つのセットをライブラリで提供しています。POSIX 非同期入出力インタフェースは最新の標準です。SunOS 環境は、情報の消失やデータの不一致を防止するために、ファイルおよびメモリー内の同期操作とモードを提供します。
標準の UNIX 入出力は、アプリケーションのプログラマと同期します。read(2) または write(2) を呼び出すアプリケーションは、通常はシステムコールが終了するまで待ちます。
リアルタイムアプリケーションは、入出力に非同期でバインドされた特性を必要とします。非同期入出力呼び出しを発行したプロセスは、入出力操作の完了を待たずに先に進むことができます。呼び出し側は、入出力操作が終了すると通知されます。
非同期入出力は、任意の SunOS ファイルで使用できます。ファイルは同期的に開かれますが、特別なフラグ設定は必要ありません。非同期入出力転送には、 呼び出し、要求、操作の 3 つの要素があります。アプリケーションは非同期入出力インタフェースを呼び出し、入出力要求は待ち行列に置かれ、呼び出しはすぐに戻ります。ある時点で、システムは要求を待ち行列から取り出し、入出力操作を開始します。
非同期入出力要求と標準入出力要求は、任意のファイル記述子で混在させることができます。システムは、読み取り要求と書き込み要求の特定の順序を維持しません。システムは、保留状態にあるすべての読み取り要求と書き込み要求の順序を任意に並べ替えます。特定の順序を必要とするアプリケーションは、前の操作の完了を確認してから従属する要求を発行しなければなりません。
POSIX 非同期入出力は、aiocb 構造体を使用して行います。aiocb 制御ブロックは、各非同期入出力要求を識別し、すべての制御情報を持っています。制御ブロックを使用できる要求は一度に 1 つだけです。その要求が完了すると、制御ブロックはまた使用できるようになります。
一般的な POSIX 非同期入出力操作は、aio_read(3RT) または aio_write(3RT) 呼び出しによって開始します。ポーリングまたはシグナルを使用すると、操作の完了を判断できます。操作の完了にシグナルを使用する場合は、各操作に一意のタグを付けることができます。このタグは生成されたシグナルの si_value 構成要素に戻されます。siginfo(3HEAD) のマニュアルページを参照してください。
aio_read(3RT) は、読み取り操作の開始のために非同期入出力制御ブロックを使用して呼び出します。
aio_write(3RT) は、書き込み操作の開始のために非同期入出力制御ブロックを指定して呼び出します。
aio_return(3RT) および aio_error(3RT) はそれぞれ、操作が完了していると判明したあとに、戻り値とエラー値を取得するために呼び出します。
aio_cancel(3RT) は、保留状態の操作を取り消すために非同期入出力制御ブロックを指定して呼び出します。aio_cancel は、制御ブロックによって要求が指定されている場合、指定された要求を取り消します。aio_cancel はまた、制御ブロックによって指定されたファイル記述子に対して保留されているすべての要求を取り消します。
aio_fsync(3RT) は、指定されたファイル上で保留されているすべての入出力操作に対する非同期的な fsync(3C) または fdatasync(3RT) 要求を待ち行列に入れます。
aio_suspend(3RT) は、1 つ以上の先行する非同期入出力要求が同期的に行われるかのように呼び出し側を一時停止します。
この節では、Solaris オペレーティング環境における非同期入出力について説明します。
非同期入出力呼び出しが正常に返ったとき、入出力操作は単に待ち行列に入って、実行が行われるのを待ちます。実際の操作は、戻り値と潜在的なエラー識別子を持っています。呼び出しが同期的に行われた場合、この戻り値と潜在的なエラー識別子は呼び出し側に戻されます。入出力が終了すると、戻り値とエラー値は両方とも、ユーザーが要求時に aio_result_t へのポインタとして指定した位置に格納されます。aio_result_t 構造体は、<sys/asynch.h> に次のように定義されています。
typedef struct aio_result_t { ssize_t aio_return; /* return value of read or write */ int aio_errno; /* errno generated by the IO */ } aio_result_t;
aio_result_t が変更されると、入出力要求を行なったプロセスに SIGIO シグナルが配信されます。
2 つ以上の非同期入出力操作を保留しているプロセスは、SIGIO シグナルの原因を特定できません。SIGIO を受け取ったプロセスは、SIGIO を生じた原因となる条件をすべて確認する必要があります。
aioread(3AIO) ルーチンは read(2) の非同期バージョンです。通常の読み取り引数に加えて、aioread(3AIO) はファイルの位置を指定する引数と aio_result_t 構造体のアドレスを指定する引数を取ります。aio_result_t 構造体には、操作の結果情報が格納されます。ファイル位置には、操作の前にファイル内で行うシークを指定します。aioread(3AIO) 呼び出しが成功したか失敗したかに関係なく、ファイルポインタは更新されます。
aiowrite(3AIO) ルーチンは write(2) の非同期バージョンです。通常の書き込み引数に加えて、aiowrite(3AIO) はファイルの位置を指定する引数と aio_result_t 構造体のアドレスを指定する引数を取ります。aio_result_t 構造体には、操作の結果情報が格納されます。
ファイル位置は、この操作が行われる前に、ファイル内でシーク操作が実行されることを指定します。aiowrite(3AIO) 呼び出しが成功すると、ファイルポインタはシークと書き込みが成功した場合の位置に変更されます。ファイルポインタは書き込みを行なったあと、以降の書き込みができなくなった場合も変更されます。
aiocancel(3AIO) ルーチンは、aio_result_t 構造体を引数として指定した非同期要求を取り消そうとします。aiocancel(3AIO) 呼び出しは、要求がまだ待ち行列にある場合にのみ成功します。操作がすでに進行している場合、aiocancel(3AIO) は失敗します。
aiowait(3AIO) を呼び出すと、少なくとも 1 つの未処理の非同期入出力操作が完了するまで、呼び出し側プロセスはブロックされます。タイムアウトパラメータは、入出力の完了を待つ最大インターバルを指します。0 のタイムアウト値は、待つ必要がないことを指定します。aiowait(3AIO) は、完了した操作の aio_result_t 構造体へのポインタを返します。
非同期入出力イベントの完了を同期的に決定するには、SIGIO 割り込みに依存するのではなく、poll(2) を使用します。ポーリングを使用すると、SIGIO 割り込みの原因を調べることもできます。
あまり多くのファイルで poll(2) を使用すると、処理が遅くなります。この問題は、poll(7d) で解決します。
/dev/poll を使用すると、多数のファイル記述子のポーリングを高いスケーラビリティーで行うことができます。このスケーラビリティーは、新しい API のセットと新しいドライバ /dev/poll によって実現されます。/dev/poll API は poll(2) を置き換えるものではなく、どちらかを選択して使用するものです。poll(7d) を使用すると、/dev/poll API の詳細と例を提供できます。適切に使用すると、/dev/poll API は poll(2) よりも高いスケーラビリティーを提供します。この API は、特に、次の条件を満たすアプリケーションに適します。
多数のファイル記述子のポーリングを繰り返し行うアプリケーション
ポーリングが行われたファイル記述子が比較的安定している、つまりひんぱんに開閉が行われない
ポーリングイベントの総数に比較して、保留が少ないファイル記述子のセット
ファイルを閉じるには、close(2) を呼び出します。close(2) を呼び出すと、未処理の非同期入出力要求のうち、閉じることができるものを取り消します。close(2) は、取り消せない操作の完了を待ちます。詳細は、「aiocancel の使用法」を参照してください。close(2) 呼び出しが戻ると、そのファイル記述子について保留状態にある非同期入出力要求はなくなります。ファイルが閉じられると、取り消されるのは指定したファイル記述子に対する待ち行列内にある非同期入出力要求だけです。ほかのファイル記述子について、保留状態にある入出力要求は取り消されません。
アプリケーションは、情報が安定した記憶領域に書き込まれたことや、ファイル変更が特定の順序で行われることを保証する必要がある場合があります。同期入出力は、このような場合のために用意されています。
SunOS では、データが書き込み操作用としてファイルに正常に転送されるには、システムがファイルを開いたときには、以前に書き込まれたデータを読み取ることができることを保証している必要があります。この確認は、物理的な記憶媒体に障害がないことを想定しています。また、データが読み取り操作用として正常に転送されるには、要求側プロセスが物理記憶媒体上にあるデータのイメージを利用できる必要があります。入出力操作は、関連付けられているデータが正しく転送されたか、操作が失敗と診断された場合に完了します。
入出力操作は、次の場合に同期入出力データの整合性を保証します。
読み取りの場合、操作は完了するか、失敗して原因究明されます。読み取りが完了するのは、データのイメージが要求側のプロセスに正しく転送された場合だけです。同期読み取り操作が要求されたとき、読み取るべきデータに保留状態の書き込み要求が影響を与える場合、この書き込み要求はデータを読み取る前に正常に終了します。
書き込みの場合も、操作は完了するか、失敗して原因究明されます。書き込みが正常に終了するのは、書き込み要求で指定されたデータが正しく転送され、さらに、そのデータを取得するために必要なファイルシステム情報がすべて正しく転送された場合だけです。
データの取り出しに必要のないファイル属性は、呼び出し側プロセスに戻る前に正しく転送されているわけではありません。
同期入出力ファイルの整合性の保証は、呼び出し側プロセスに戻る前に、入出力操作に関連するすべてのファイル属性が正常に転送されている必要があります。さもないと、同期入出力ファイルの整合性の保証は、同期入出力データの整合性の保証と同等です。
fsync(3C) および fdatasync(3RT) は明示的にファイルと二次記憶領域の同期をとります。
fsync(3C) ルーチンは、入出力ファイルの整合性の保証レベルでインタフェースの同期をとることを保証します。fdatasync(3RT) は、入出力データの整合性の保証レベルでインタフェースの同期をとることを保証します。
アプリケーションは、操作が完了する前に、各入出力操作の同期をとるように指定できます。open(2) または fcntl(2) を使用して、ファイル記述子に O_DSYNC フラグを設定すると、操作が完了したと見なされる前に、すべての入出力書き込みは入出力データ完了に達します。ファイル記述子に O_SYNC フラグを設定すると、操作が完了したと見なされる前に、すべての入出力書き込みは入出力ファイル完了に達します。ファイル記述子に O_RSYNC フラグを設定すると、すべての入出力読み取り (read(2) と aio_read(3RT)) はファイル記述子に設定したのと同じ完了レベルに達します。ファイル記述子に設定するのは、O_DSYNC または O_SYNC のどちらでもかまいません。