オペレーティング・システムは,AT&T の System V によって指定された STREAMS フレームワーク,STREAMS のバージョン 4.0 リリースを提供します。 このフレームワークでは,従来の UNIX の文字入出力 (I/O) の代わりに,ユーザは,I/O 関数をモジュール方式でインプリメントできます。 モジュール方式で開発された I/O 関数を使用すると,アプリケーションは,通信サービスを容易に構築したり再構成したりできます。
「STREAMS」はフレームワーク全体を指し,「ストリーム」は,アプリケーション・プログラムが
open
システム・コールを使用して作成したエンティティを指すことに注意してください。
この章では,次の項目について説明します。
STREAMS フレームワークの概要
STREAMS に対するアプリケーション・インタフェース
カーネル・レベル関数
モジュールまたはドライバの構成方法
Tru64 UNIX 同期機構
デバイス特殊ファイルの作成方法
エラーおよびイベントのロギング
STREAMS リファレンス・ページに関する情報
この章では,Tru64 UNIX の STREAMS のインプリメンテーションと,AT&T System V バージョン 4.0 のインプリメンテーションの相違について,詳細に説明します。 Tru64 UNIX のインプリメンテーションが,AT&T のインプリメンテーションと大きく変わらないところについては,AT&T の該当するマニュアルに関する情報を提示します。
この章では,STREAMS フレームワークを使用してプログラムを作成する方法については説明しません。
プログラミング情報についての詳細は,『Programmer's Guide: STREAMS』を参照してください。
5.1 STREAMS フレームワークの概要
STREAMS フレームワークは,次のものから構成されます。
アプリケーション・プログラムが STREAMS フレームワークへのアクセスに使用する,プログラミング・インタフェース,またはシステム・コールのセット。
ストリーム・ヘッドなどのカーネル・リソース,およびストリームが使用するキューのデータ構造体。
ストリームのキュー・スケジューリングやフロー制御,メモリ割り当て,およびエラー・ロギングなどのタスクを処理する,カーネル・ユーティリティ。
図 5-1では,STREAMS フレームワークを強調表示して,ネットワーク・プログラミング環境における位置付けを示しています。
STREAMS を使用して通信するには,アプリケーションでストリームを作成します。 ストリームは,ユーザ・プロセスとデバイス・ドライバの間の全二重の通信パスです。 ストリーム自体はカーネル・デバイスであり,アプリケーションに対しては文字型特殊ファイルとして表されます。 他の文字型特殊ファイルと同様に,ストリームはオープンしなければなりません。 それ以外の場合は,システム・コールによって操作します。
各ストリームの先頭と末尾には,それぞれ 1 つ以上のストリーム・ヘッドとストリーム・エンドがあります。 ストリームを通して引き渡されるデータの処理に必要な場合には,リンクしたキューのペアから構成される追加モジュールを,ストリーム・ヘッドとストリーム・エンドの間に挿入できます。 データは,モジュール間でメッセージを使用して引き渡されます。
この項では,次の STREAMS の構成要素について簡単に説明します。
ストリーム・ヘッド
ストリーム・エンド
モジュール
また,メッセージについて説明するとともに,STREAMS フレームワーク内におけるメッセージの役割についても説明します。
図 5-2
は,一般的なストリームを示しています。
ストリーム・ヘッドからストリーム・エンド (図 5-2
では STREAMS ドライバ) に流れるデータは,ダウンストリーム,または書き込み方向に流れるといいます。
ストリーム・エンドからストリーム・ヘッドに流れるデータは,アップストリーム,または読み取り方向に流れるといいます。
図 5-2: ストリームの例
ストリーム・ヘッドは,カーネル内においてユーザ・プロセスとストリームの間にインタフェースを提供する,ルーチンとデータ構造体のセットです。
アプリケーションが
open
システム・コールを発行すると,ストリームが作成されます。
ストリーム・ヘッドが実行する主なタスクは,次のとおりです。
STREAMS システム・コールの
write
や
putmsg
といった標準サブセットを解釈する。
ユーザ空間からの STREAMS システム・コールを,STREAMS メッセージ (M_PROTO,M_DATA など) の標準の範囲に変換する。
STREAMS メッセージは,データおよび制御情報から構成されます。
メッセージを次のモジュールへダウンストリームに送信する。
メッセージは,最終的にストリーム・エンド,つまりドライバに到達します。
ドライバからアップストリームに送信されたメッセージを受信して,カーネル空間からの STREAMS メッセージを,アプリケーションによって呼び出されるシステム・コール (getmsg,readなど) に適したフォーマットに変換する。
フォーマットは,システム・コールによって異なります。
ストリーム・エンドは,STREAMS モジュールの特殊な形式であり,ハードウェア・デバイス・ドライバまたは擬似デバイス・ドライバのいずれかです。 ハードウェア・デバイス・ドライバの場合,ストリーム・エンドは,カーネルと外部通信デバイスとの間の通信を提供します。 擬似デバイス・ドライバの場合には,ストリーム・エンドはソフトウェアでインプリメントされ,外部デバイスには関連しません。 ハードウェア・デバイス・ドライバ,または擬似デバイス・ドライバのいずれであるかにかかわらず,ストリーム・エンドは,その上のモジュールから送信されたメッセージを受信し,解釈して,要求されたオペレーションを実行します。 次に,ストリーム・ヘッドに向かってアップストリームに送信する適切なメッセージ・タイプのメッセージを作成して,アプリケーションにデータおよび制御情報を返します。
ドライバは,次の点を除いて,他の STREAMS モジュールと同じです。
(必要がなくても) 割り込みを処理できる。
デバイス・ドライバには,1 つ以上の割り込みルーチンがあります。 割り込みルーチンは,後で処理を行うために,読み取り側のサービス・ルーチンに関するデータをキューにいれる必要があります。
複数のストリームに接続できる。
ドライバは,多重化デバイスとしてインプリメントできます。 つまり,アップストリームまたはダウンストリームのいずれかの方向で,複数のストリームに接続できます。 詳細は,『Programmer's Guide: STREAMS』を参照してください。
open
および
close
の各システム・コールによって,初期化および初期化解除される。
他のモジュールは,ioctl
システム・コールの
I_PUSH
コマンドおよび
I_POP
コマンドを使用します。
デバイス・ドライバおよびデバイス・ドライバ・ルーチンについての詳細は,『Writing Device Drivers』 および『Programmer's Guide: STREAMS』を参照してください。
モジュールは,データを,ストリーム・ヘッドからストリーム・エンドに引き渡す際と,戻す際に処理します。 ストリームは,データが要求する処理の量と種類に応じて,ゼロ個以上のモジュールを持つことができます。 ドライバが,データに対して必要なすべての処理を実行できる場合には,追加のモジュールは必要ありません。
モジュールは,データをいれる 1 組のキュー,および各モジュールの役割を定義する他の構造体へのポインタで構成されます。 1 つのキューは,ドライバに向かってダウンストリームに流れるデータを処理し,もう 1 つのキューは,ストリーム・ヘッドおよびアプリケーションに向かってアップストリームに流れるデータを処理します。 ポインタは,各モジュールのダウンストリーム・キューおよびアップストリーム・キューを,次のモジュールのダウンストリーム・キューおよびアップストリーム・キューにリンクします。
処理の必要条件に応じて,アプリケーションは,特定のモジュールをストリームにプッシュするように要求します。 ストリーム・ヘッドは,アプリケーションが要求したモジュールをアセンブルした後,モジュールのパイプラインを通してメッセージの経路指定を行います。
情報は,メッセージを使用して,モジュールからモジュールに引き渡されます。 STREAMS 環境において,さまざまなタイプのメッセージが定義されますが,すべてのメッセージのタイプは,次のカテゴリに分類できます。
通常メッセージ
優先メッセージ
M_DATA および M_IOCTL などの通常メッセージは,受信した順に処理されて,STREAMS フロー制御およびキュー登録機構に従います。 優先メッセージは,ストリームを通して優先的に引き渡されます。
メッセージおよびメッセージ・データ構造体についての詳細は,5.3.2 項を参照してください。
5.1.2 ioctl プロセス
STREAMS では,ユーザ・プロセスは,ストリーム内で
ioctl
を呼び出して,特定のモジュールとドライバを制御することができます。
ユーザ・プロセスが
ioctl
コマンドを実行する際に,STREAMS はプロセスをブロックし,強制的にストリーム・ヘッドがコマンドを処理するようにします。
また,必要に応じてメッセージ (M_IOCTL) を書き込み方向に送信して,特定のモジュールまたはドライバが受信して処理するようにします。
ユーザ・プロセスは,次のいずれかが行われるまでブロックされます。
モジュールまたはドライバが肯定応答 (M_IOCACK) または否定応答 (M_IOCNAK) で応答した場合
要求がタイムアウトした場合 (受信メッセージなし)
ユーザ・プロセスが
ioctl
に割り込んだ場合
エラー条件が発生した場合
STEAMS には,ioctl
を処理するメソッドとして,I_STR と透過の 2 つがあります。
表 5-1
で,その 2 つのメソッドの比較をしています。
表 5-1: ioctl 処理のI_STR メソッドと透過メソッドの比較
| I_STR 処理 | 透過処理 |
| STREAMS ファイルに対して作成されたアプリケーションのみをサポートする。 | STREAMS ファイルか,非 STREAMS ファイルのいずれに対してでも作成されたアプリケーションをサポートする。 |
streamio(7) |
ioctl(2) |
| データ・フォーマットおよびアドレッシングに制限がある。 | データ・フォーマットおよびアドレッシングの制限は
ioctl
に依存する。 |
ioctl
の処理を完了するには,1 対のメッセージが必要である。 |
ioctl の処理を完了するために,複数対のメッセージが必要になることがある。 |
| タイムアウトの値はユーザ定義または省略時の値。 | タイムアウトはしない。 |
| STREAMS 処理を前提とする。 | もっと汎用的。 |
ioctl
処理に対する両方のメソッドについての詳細は,『Programmer's Guide: STREAMS』 を参照してください。
5.2 STREAMS に対するアプリケーション・インタフェース
STREAMS フレームワークに対するアプリケーション・インタフェースによって,STREAMS メッセージは,アプリケーションで送受信できます。
以降の項で,STREAMS ヘッダ・ファイルおよびデータ型へのポインタを含むアプリケーション・インタフェースについて説明するとともに,STREAMS および STREAMS 関連のシステム・コールについても説明します。
5.2.1 ヘッダ・ファイルおよびデータ型
基本的な STREAMS のデータ型の定義は,次のヘッダ・ファイルに含まれています。
<sys/stream.h>
このヘッダ・ファイルは,すべてのモジュールおよびストリーム・アプリケーションにインクルードしなければなりません。
<stropts.h>
このヘッダ・ファイルは,アプリケーションで
ioctl
システム・コールを使用する場合に,インクルードしなければなりません。
<strlog.h>
このヘッダ・ファイルは,アプリケーションで,STREAMS のエラー・ロガーおよびトレース機能を使用する場合に,インクルードしなければなりません。
注意
一般に,ヘッダ・ファイル名は山カッコ (< >) で囲まれています。 ヘッダ・ファイルの絶対パスは,山カッコ内の情報の前に
/usr/include/を付けたものです。<sys/stream.h>の場合,stream.hは/usr/include/sysディレクトリに存在します。
アプリケーションは,次の関数を使用して,STREAMS のカーネル・リソースにアクセスして,操作します。
open
close
read
write
ioctl
mkfifo
pipe
putmsg
および
putpmsg
getmsg
および
getpmsg
poll
isastream
fattach
fdetach
この項では,これらの関数について簡単に説明します。
これらの関数についての詳細は,リファレンス・ページおよび『Programmer's Guide: STREAMS』を参照してください。
5.2.2.1 open 関数
open
関数は,ストリームをオープンするときに使用します。
関数の構文,パラメータ,エラーについては,
open(2)
次の例は,open
関数の使用方法を示しています。
int fd;
fd = open("/dev/streams/echo", O_RDWR);
close
関数は,ストリームをクローズするときに使用します。
関数の構文,パラメータ,エラーについては,
close(2)
ストリームに対する最後の
close
によって,ファイル記述子に関連付けられたストリームが破壊されます。
ストリームの破壊には,ストリーム上のすべてのモジュールのポップ,およびドライバのクローズが含まれます。
5.2.2.3 read 関数
read
関数は,ストリーム・ヘッドで待機中の M_DATA メッセージの内容を受信するときに使用します。
関数の構文,パラメータ,エラーについては,
read(2)
read
関数は,M_DATA 以外のメッセージ・タイプでは失敗し,errno
に EBADMSG がセットされます。
5.2.2.4 write 関数
write
関数は,データ・バッファから 1 つ以上の M_DATA メッセージを作成するときに使用します。
関数の構文,パラメータ,エラーについては,
write(2)5.2.2.5 ioctl 関数
ioctl
関数は,ストリーム上でさまざまな制御機能を実行するときに使用します。
STREAMS
関数の構文,パラメータ,エラーについては,
streamio(7)
次の例は,ioctl
システム・コールの使用方法を示しています。
int fd;
fd = open("/dev/streams/echo", O_RDWR, 0);
ioctl(fd,I_PUSH,"pass");
STREAMS ベースの
mkfifo
関数は,単方向の STREAMS ベースのファイル記述子を作成するときに使用します。
注意
libcライブラリの省略時のmkfifo関数は STREAMS ベースではありません。 STREAMS ベースのmkfifo関数を使用するには,アプリケーションをsys5ライブラリとリンクしなければなりません。 関数の構文,パラメータ,エラーについては,を参照してください。 mkfifo(2)また,
mkfifo関数では,FFM_FS (File on File Mount File System) カーネル・オプションが構成されていなければならないことにも注意してください。 カーネル・オプションの構成についての詳細は,『システム管理ガイド』を参照してください。
STREAMS ベースの
pipe
関数は,双方向の STREAMS ベースの通信チャネルを作成するときに使用します。
STREAMS ベースのパイプと STREAMS ベースでないパイプは,次の点が異なります。
STREAMS ベースでないパイプは単方向である。
streamio
や
putmsg
などの STREAMS のオペレーションは,STREAMS ベースでないパイプでは実行できない。
注意
libcライブラリの省略時のpipe関数は STREAMS ベースではありません。 STREAMS ベースのpipe関数を使用するには,アプリケーションをsys5ライブラリとリンクしなければなりません。 関数の構文,パラメータ,エラーについては,を参照してください。 pipe(2)
putmsg
および
putpmsg
関数は,指定されたバッファからの情報を使用して,STREAMS メッセージ・ブロックを生成するときに使用します。
関数の構文,パラメータ,エラーについては,
putmsg(2)
putpmsg
関数は,優先帯域データをダウンストリームに送信する場合に使用します。
各引数は
putmsg
関数の引数と同じ意味です。
関数の構文,パラメータ,エラーについては,
putpmsg(2)5.2.2.9 getmsg および getpmsg 関数
getmsg
および
getpmsg
関数は,ストリーム・ヘッドの読み取りキューにあるメッセージの内容を検索して,ユーザ指定のバッファにいれるときに使用します。
関数の構文,パラメータ,エラーについては,
getmsg(2)
getpmsg
関数は,優先帯域データをストリームから受信する場合に使用します。
引数は
getmsg
関数の引数と同じ意味です。
関数の構文,パラメータ,エラーについては,
getpmsg(2)5.2.2.10 poll 関数
poll
関数は,ユーザがデータを送受信できるストリームを識別するときに使用します。
関数の構文,パラメータ,エラーについては,
poll(2)5.2.2.11 isastream 関数
isastream
関数は,ファイル記述子が STREAMS ファイルを参照しているかどうかを判断するときに使用します。
次の例は,isastream
関数を使用して,ソケット・ベースのパイプでなく,STREAMS ベースのパイプをオープンしていることを確認する方法を示しています。
int fds[2];
pipe(fds);
if (isastream(fds[0]))
printf("STREAMS based pipe\n");
else
printf("Sockets based pipe\n");
関数の構文,パラメータ,エラーについては,
isastream(3)5.2.2.12 fattach 関数
fattach
関数は,STREAMS ベースのファイル記述子を,ファイル・システムの名前空間にあるオブジェクトにアタッチするときに使用します。
次の例は,fattach
関数を使用して,STREAMS ベースのパイプに名前を付ける方法を示しています。
int fds[2]; pipe(fds); fattach(fd[0], "/tmp/pipe1");
注意
fattach関数を使用するには,FFM_FS カーネル・オプションが構成されている必要があります。 カーネル・オプションの構成については,『システム管理ガイド』を参照してください。
関数の構文,パラメータ,エラーについては,
fattach(3)5.2.2.13 fdetach 関数
fdetach関数は,STREAMS ベースのファイル記述子をファイル名からデタッチするときに使用します。
注意
fdetach関数を使用するには,FFM_FS (File on File Mount File System) カーネル・オプションが構成されている必要があります。 カーネル・オプションの構成については,『システム管理ガイド』を参照してください。
関数の構文,パラメータ,エラーについては,
fdetach(3)
表 5-2
は,STREAMS に関連する情報が記述されているリファレンス・ページについて簡単に説明した一覧です。
詳細については,該当するリファレンス・ページを参照してください。
表 5-2: STREAMS リファレンス・ページ
| リファレンス・ページ | 説明 |
autopush(8) |
システムの自動的にプッシュされた STREAMS モジュールのデータベースを管理するコマンド。 |
clone(7) |
別の STREAMS ドライバで,未使用の主/副デバイスを見つけてオープンする STREAMS ソフトウェア・ドライバ。 |
close(2) |
指定したファイル記述子に関連付けられたファイルをクローズする関数。 |
dlb(7) |
BSD スタイルのデバイス・ドライバと STREAMS プロトコル・スタック間の通信パスを提供する STREAMS 擬似ドライバ。 |
fattach(3) |
STREAMS ベースのファイル記述子をファイル・システムのノードにアタッチするコマンド。 |
fdetach(8) |
STREAMS ベースのファイル記述子をファイル名からデタッチするコマンド。 |
fdetach(3) |
STREAMS ベースのファイル記述子をファイル名からデタッチする関数。 |
getmsg(2)getpmsg(2) |
ストリーム・ヘッドの読み取りキューに入っているメッセージを参照する関数。 |
ifnet(7) |
データ・リンク・プロバイダ・インタフェース (DLPI) に合わせて作成された STREAMS ベースのデバイス・ドライバとソケット間のブリッジを提供する STREAMS ベースのモジュール。 |
isastream(3) |
ファイル記述子が STREAMS ファイルを参照しているかどうかを判断する関数。 |
mkfifo(2) |
単方向の STREAMS ベースのファイル記述子を作成する関数。 |
open(2) |
ファイルとファイル記述子の間に接続を確立する関数。 |
pipe(2) |
双方向の STREAMS ベースのプロセス間通信チャネルを作成する関数。 |
poll(2) |
1 組のファイル記述子に関連する I/O 状態を報告し,指定された 1 つ以上の条件が真になるまで待機する一般的な機能を提供する関数。 |
putmsg(2)putpmsg(2) |
STREAMS メッセージ・ブロックを生成する関数。 |
read(2) |
データをファイルから読み取って指定のバッファにいれる関数。 |
strace(8) |
STREAMS ログ・ドライバから STREAMS のイベント・トレース・メッセージを検出するアプリケーション。 |
strchg(1) |
ストリームの構成を変更するコマンド。 |
strclean(8) |
STREAMS のエラー・ログ・ファイルを削除するコマンド。 |
strconf(1) |
ストリームの構成について照会するコマンド。 |
streamio(7) |
ストリーム上でさまざまな制御関数を実行するコマンド。 |
strerr(3) |
STREAMS ログ・ドライバからエラー・メッセージを受信するデーモン。 |
strlog(7) |
STREAMS のエラー・ロギング・デーモンおよびイベント・トレース・デーモンが使用する,ログ・メッセージを追跡するインタフェース。 |
strsetup(8) |
適切な STREAMS 擬似デバイスを作成し,STREAMS モジュールの設定を表示するコマンド。 |
timod(7) |
トランスポート・インタフェース (TI) をサポートしているトランスポート・ユーザからの
ioctl
呼び出しを,TI をサポートしているトランスポート・プロトコル・プロバイダが使用できるメッセージに変換するモジュール。 |
tirdwr(7) |
トランスポート・インタフェース (TI) をサポートしているトランスポート・ユーザに,TI をサポートしているトランスポート・プロトコル・プロバイダへの別のインタフェースを提供するモジュール。 |
write(2) |
データを指定のバッファからファイルへ書き込む関数。 |
この節では,STREAMS モジュールおよびドライバを作成するカーネル・プログラマが熟知しておかなければならない情報について説明します。 説明する情報は,次のとおりです。
モジュール・データ構造体
メッセージ・データ構造体
モジュールおよびドライバの STREAMS 処理ルーチン
モジュールまたはドライバがシステムに組み込まれている場合は, そのモジュールまたはドライバで,読み取りキューと書き込みキュー,および他のモジュール情報を定義しなければなりません。
データ構造体
qinit,module_info,および
streamtab
は,すべて
<sys/stream.h>
ヘッダ・ファイルに記述されており,読み取りキューおよび書き込みキューを定義します。
STREAMS モジュールは,宣言部分で,これらのデータ構造体の内容を指定しておかなければなりません。
例については,付録 Aを参照してください。
モジュールが提供しなければならない外部データ構造体は,streamtab
だけです。
次に示す
qinit
構造体は,キューのためのインタフェース・ルーチンを定義します。
読み取りキューおよび書き込みキューそれぞれに,構造体のセットがあります。
struct qinit {
int (*qi_putp)(); /* put routine */
int (*qi_srvp)(); /* service routine */
int (*qi_qopen)(); /* called on each open */
/* or a push */
int (*qi_qclose)(); /* called on last close */
/* or a pop */
int (*qi_qadmin)(); /* reserved for future use */
struct module_info * qi_minfo; /* information structure */
struct module_stat * qi_mstat; /* statistics structure (op-
/* tional) */
};
module_info
構造体には,モジュールまたはドライバの ID および制限値が入ります。
次の例を参照してください。
struct module_info {
unsigned short mi_idnum; /* module ID number */
char *mi_idname; /* module name */
long mi_minpsz; /* min packet size, for */
/* developer use */
long mi_maxpsz; /* max packet size, for */
/* developer use */
ulong mi_hiwat; /* hi-water mark, for */
/* flow control */
ulong mi_lowat; /* lo-water mark, for */
/* flow control */
};
streamtab
構造体は,宣言の最上部に記述します。
これは,モジュールまたはドライバの外部に見えなければならない唯一の部分です。
次の例を参照してください。
struct streamtab {
struct qinit * st_rdinit; /* defines read QUEUE */
struct qinit * st_wrinit; /* defines write QUEUE */
struct qinit * st_muxrinit; /* for multiplexing drivers only */
struct qinit * st_muxwinit; /* ditto */
};
Tru64 UNIX STREAMS メッセージは,1 つ以上のリンクされたメッセージ・ブロックから構成されます。 各データ・ブロックには,次の 3 つの構成要素があります。
データ・バッファには,メッセージを構成するバイナリ・データが入っています。 STREAMS では,データ・バッファ内のデータのフォーマットに関して位置合わせの規則はありません。 ただし,ストリーム・ヘッドで処理されるメッセージのために従わなければならない位置合わせの規則はあります。
mblk_t
構造体には,メッセージの所有者が操作できる情報が入っています。
この構造体内の 2 つのフィールドは,データ・バッファへの読み取りポインタと書き込みポインタです。
dblk_t
制御構造体
dblk_t
構造体には,バッファの特性に関する情報が入っています。
たとえば,この構造体の 2 つのフィールドは,データ・バッファの制限値を指し示すポインタです。
他のフィールドには,メッセージ・タイプが入っています。
ストリーム・ヘッドは,データがアプリケーションからダウンストリームに流れるときに,メッセージ・データ構造体を作成して,その内容を指定します。 ストリーム・エンドは,データが外部通信デバイスから流れてくる場合などのように,データがアップストリームに流れるときに,メッセージ・データ構造体を作成して,その内容を指定します。
mblk_t
構造体および
dblk_t
構造体を次に示します。
どちらの構造体も
<sys/stream.h>
ヘッダ・ファイルに記述されています。
/* message block */
struct msgb {
struct msgb * b_next; /* next message on queue */
struct msgb * b_prev; /* previous message on queue */
struct msgb * b_cont; /* next message block of message */
unsigned char * b_rptr; /* first unread data byte in buffer */
unsigned char * b_wptr; /* first unwritten data byte */
struct datab * b_datap; /* data block */
unsigned char b_band; /* message priority */
unsigned char b_pad1;
unsigned short b_flag; /* message flags */
long b_pad2;
MSG_KERNEL_FIELDS
};
typedef struct msgb mblk_t;
/* data descriptor */
struct datab {
union {
struct datab * freep;
struct free_rtn * frtnp;
} db_f;
unsigned char * db_base; /* first byte of buffer */
unsigned char * db_lim; /* last byte+1 of buffer */
unsigned char db_ref; /* count of messages pointing */
/* to block */
unsigned char db_type; /* message type */
unsigned char db_iswhat; /* message status */
unsigned int db_size; /* used internally */
caddr_t db_msgaddr; /* used internally */
long db_filler;
};
#define db_freep db_f.freep
#define db_frtnp db_f.frtnp
typedef struct datab dblk_t;
/* Free return structure for esballoc */
typedef struct free_rtn {
void (*free_func)(char *, char *); /* Routine to free buffer */
char * free_arg; /* Parameter to free_func */
} frtn_t;
メッセージが STREAMS キューに入っている場合,そのメッセージは,ポインタ
b_next
および
b_prev
によってリンクされたメッセージ・リストの一部になります。
キューに入っている先頭のメッセージは,そのキューの
q_next
ポインタによって指し示され,キューに入っている最後のメッセージは,そのキューの
q_last
ポインタによって指し示されます。
5.3.3 ドライバおよびモジュールの STREAMS 処理ルーチン
モジュールまたはドライバは,アプリケーションが要求する処理をストリーム上で行うことができます。 ただし,要求された処理を行うためには,STREAMS モジュールまたはドライバは,STREAMS フレームワークによって動作が指定される特殊ルーチンを提供しなければなりません。 この項では,STREAMS モジュールおよびドライバが提供するルーチン,および処理の種類について説明します。 説明する項目は,次のとおりです。
オープン処理
クローズ処理
構成処理
読み取り側プット処理
書き込み側プット処理
読み取り側サービス処理
書き込み側サービス処理
注意
STREAMS モジュールおよびドライバは,オープン,クローズ,および構成処理を提供しなければなりません。 この項で説明する他の処理は,オプションです。
この項では,XX_routine_name
というフォーマットを使用して各ルーチンを説明します。
XX
は,ユーザ作成の STREAMS モジュール名またはドライバ名に置き換えてください。
たとえば,ユーザ作成の STREAMS 擬似デバイス・ドライバ
echo
の
open
ルーチンは,echo_open
になります。
5.3.3.1 オープンおよびクローズの処理
open
ルーチンおよび
close
ルーチンだけが,カーネルの
u_area
へのアクセスを提供します。
これらのルーチンは,シグナルをキャッチした場合にだけ,スリープすることができます。
オープン処理
モジュールおよびドライバには,open
ルーチンがなければなりません。
読み取り側の
qinit
構造体,st_rdinit
は,qi_qopen
フィールドに
open
ルーチンを定義します。
ドライバの
open
ルーチンは,アプリケーションがストリームをオープンするときに呼び出されます。
ストリーム・ヘッドは,アプリケーションがモジュールをそのストリームにプッシュすると,モジュール内の
open
ルーチンを呼び出します。
open
ルーチンのフォーマットは,次のとおりです。
XX_open(q, devp, flag, sflag, credp)
queue_t *q; /* pointer to the read queue */
dev_t *devp; /* pointer to major/minor number
for devices */
int flag; /* file flag */
int sflag; /* stream open flag */
cred_t *credp /* pointer to a credentials structure */
open
ルーチンは,STREAMS ドライバまたはモジュールが内部で使用するための,データ構造体を割り当てることができます。
このデータ構造体へのポインタは,通常
queue_t
構造体の
q_ptr
フィールドに格納されます。
このポインタには,モジュールまたはドライバの他の部分から後でアクセスできます。
クローズ処理
モジュールおよびドライバには,close
ルーチンがなければなりません。
読み取り側の
qinit
構造体,st_rdinit
は,qi_qclose
フィールドに
close
ルーチンを定義します。
ストリームをオープンしたアプリケーションがそのストリームをクローズするときに,ドライバは
close
ルーチンを呼び出します。
スタックからモジュールをポップするときに,ストリーム・ヘッドはモジュール内の
close
ルーチンを呼び出します。
close
ルーチンのフォーマットは,次のとおりです。
XX_close(q, flag, credp)
queue_t *q; /* pointer to read queue */
int flag; /* file flag */
cred_t *credp /* pointer to credentials structure */
close
ルーチンは,内部で使用したデータ構造体を解放して,クリーン・アップするとよい場合があります。
5.3.3.2 構成処理
configure
ルーチンは,STREAMS モジュールまたはドライバをカーネルに組み込むときに使用します。
これは,Tru64 UNIX 固有のものであり,5.4 節で使用方法を説明します。
configure
ルーチンのフォーマットは,次のとおりです。
XX_configure(op, indata, indatalen, outdata, outdatalen)
sysconfig_op_t op; /* operation - should be */
/* SYSCONFIG_CONFIGURE */
str_config_t * indata; /* for drivers - describes the device */
size_t indatalen; /* sizeof(str_config_t) */
str_config_t * outdata; /* pointer to returned data */
size_t outdatalen; /* sizeof(str_config_t) */
5.3.3.3 読み取り側プットおよび書き込み側プットの処理
読み取り側と書き込み側の両方の,XX_Xput
ルーチンがあります。
書き込み側のプット処理用は
XX_wput
であり,読み取り側のプット処理用は
XX_rput
です。
書き込み側プット処理
書き込み側のプット・ルーチン,XX_wput
は,アップストリーム・モジュールの書き込み側が
putnext
呼び出しを発行するときに呼び出されます。
XX_wput
ルーチンは,アップストリーム・モジュールから現在のモジュールまたはドライバへ引き渡されるメッセージ用の,唯一のインタフェースです。
XX_wput
ルーチンのフォーマットは,次のとおりです。
XX_wput(q, mp)
queue_t *q; /* pointer to write queue */
mblk_t *mp; /* message pointer */
読み取り側のプット・ルーチン,XX_rput
は,ダウンストリーム・モジュールの読み取り側が
putnext
呼び出しを発行するときに呼び出されます。
ストリーム・エンドであるドライバにはダウンストリーム・モジュールが存在しないので,読み取り側のプット・ルーチンがありません。
XX_rput
ルーチンは,ダウンストリーム・モジュールから現在のモジュールへ引き渡されるメッセージ用の,唯一のインタフェースです。
XX_rput
ルーチンのフォーマットは,次のとおりです。
XX_rput(q, mp)
queue_t *q; /* pointer to read queue */
mblk_t *mp; /* message pointer */
XX_Xput
ルーチンは,少なくとも次のうちの 1 つを行わなければなりません。
メッセージの処理
次のキューへのメッセージの引き渡し (putnext
の使用)
メッセージを,モジュールのサービス・ルーチンにプットすることによる,メッセージ処理の遅延 (putq
の使用)
XX_Xput
ルーチンは,大量に処理する場合には,サービス・ルーチンに依頼しなければなりせん。
5.3.3.4 読み取り側サービスおよび書き込み側サービスの処理
XX_Xput
ルーチンが,大量の処理を必要とするメッセージを受信した場合は,ただちに処理を行うと,フロー制御の問題が生じる可能性があります。
メッセージをただちに処理する代わりに,XX_rput
ルーチンは,(putq
システム・コールを使用して) メッセージを読み取り側のメッセージ・キューにいれ,XX_wput
ルーチンは,メッセージを書き込み側のキューにいれることができます。
STREAMS モジュールは,これらのキューにメッセージが入っていることを通知し,モジュールの読み取り側または書き込み側のサービス・ルーチンをスケジューリングして,それらのメッセージを処理します。
モジュールの
XX_rput
ルーチンが
putq
を呼び出さなければ,モジュールは,読み取り側のサービス・ルーチンを必要としません。
同様に,モジュールの
XX_wput
ルーチンが
putq
を呼び出さなければ,モジュールは,書き込み側のサービス・ルーチンを必要としません。
基本的なサービス・ルーチンのコードは,読み取り側も書き込み側も,次のフォーマットです。
XXXsrv(q)
queue_t *q;
{
mblk_t *mp;
while ((mp = getq(q)) != NULL)
{
/*
* If flow control is a problem, return
* the message to the queue
*/
if (!(canput(q->q_next))
return putbq(q, mp);
/*
* process message
*/
putnext(q, mp);
}
return 0;
}
次の STREAMS の概念は,Tru64 UNIX 独自のものです。 この項では,これらの概念と実現方法について説明します。
同期
タイムアウト
Tru64 UNIX は,複数のカーネル STREAMS スレッドの使用をサポートします。 STREAMS キューおよび関連するデータ構造体への排他的アクセスは保証されていません。 メッセージが同じストリームを同時に上下に移動したり,複数のプロセスが同じストリームを下るメッセージを送信することができます。
データ構造体へ同期をとってアクセスするため,各 STREAMS モジュールまたはドライバは許容できる同期レベルを選択します。
同期レベルは,モジュールまたはドライバで許可されている並列処理のレベルを決定します。
同期レベルは,モジュールまたはドライバの構成ルーチンで定義される
streamadm
データ構造体の
sa.sa_syn_level
フィールドで定義されます。
sa.sa_syn_level
フィールドは,次のいずれかの値でなければなりません。
キュー・レベル同期。 このレベルは,1 つの実行スレッドがモジュールまたはドライバの書き込みキューの任意のインスタンスにアクセスしているときに,別の実行スレッドがモジュールまたはドライバの読み取りキューの任意のインスタンスにアクセスできます。 キュー・レベル同期は,読み取りキューおよび書き込みキューが共通のデータを共用していない場合に使用できます。 引数 SQLVL_QUEUE は,Tru64 UNIX の STREAMS フレームワークにおいて利用できる最下位レベルの同期化を提供します。
たとえば,読み取りキューおよび書き込みキューの
q_ptr
フィールドは,同じメモリ位置を指しません。
キュー・ペア・レベル同期。 一度に 1 つのスレッドだけが,このモジュールまたはドライバの各インスタンスの読み取りキューおよび書き込みキューにアクセスできます。 この同期レベルは,データを処理し,ストリームごとの状態のみを持つほとんどのモジュールおよびドライバに共通です。
たとえば,モジュールのインスタンス内において,読み取りキューおよび書き込みキューの
q_ptr
フィールドは,同じメモリ位置を指します。
モジュール内には他に共用データはありません。
モジュール・レベル同期。 このモジュールまたはドライバ内のすべてのコードはシングル・スレッドです。 モジュールまたはドライバのすべてのインスタンスにアクセスできるのは,1 つの実行スレッドだけです。 たとえば,データは,モジュールまたはドライバのすべてのインスタンスによってアクセスされています。
任意レベル同期。
モジュールまたはドライバは,他の任意のモジュールまたはドライバと同期をとります。
このレベルは,互いにデータをアクセスするモジュールまたはドライバのグループの同期をとるために使用されます。
文字列は,streamadm
構造体の
sa.sync_info
フィールドにあるこのオプションと一緒に渡されます。
この文字列は,モジュールまたはドライバのセットと関連付けるために使用されます。
共同動作するモジュールまたはドライバ間の規約により,この文字列が決定されます。
たとえば,データを共用する TCP モジュールと IP モジュールのようなネットワーキング・スタックが,文字列
tcp/ip
の受け渡しを同意したとします。
この場合には,1 つの実行スレッドだけが,この文字列で同期をとるすべてのモジュールまたはドライバにアクセスすることができます。
グローバル・レベル同期。 これより低いレベルのモジュールまたはドライバはすべてシングル・スレッドです。 保護の異なる他のレベルを使用しているモジュールまたはドライバがあることに注意してください。 このオプションは主にデバッグで利用されます。
timeout
および
untimeout
へのカーネル・インタフェースは次のとおりです。
timeout(func, arg, ticks); untimeout(func, arg);
ただし,AT&T System V Release 4 の STREAMS とソースの互換性を維持するため,<sys/stream.h>
ヘッダ・ファイルでは
timeout
を次のように再定義して,System V インタフェースにします。
id = timeout(func, arg, ticks); untimeout(id);
変数
id
は
int
として定義されています。
STREAMS のモジュールおよびドライバは,System V インタフェースを使用しなければなりません。
5.4 Tru64 UNIX カーネル内へのユーザ作成の STREAMS ベースのモジュールまたはドライバの組み込み
ユーザが作成した STREAMS ドライバまたはモジュールにシステムがアクセスするためには,そのドライバとモジュールをシステムのカーネルに組み込まなければなりません。
STREAMS ドライバまたはモジュールは構成可能なカーネル・サブシステムとして認識されるべきなので,『プログラミング・ガイド』の記述に従ってカーネル・サブシステムの構成を行ってください。
次の説明では,ソース・ファイルが
mymodule1.c
および
mymodule2.c
である,STREAMS ベースのモジュール (プッシュ可能モジュール,ハードウェア,擬似デバイス・ドライバ) 例
mymod
をカーネルに追加する方法を示します。
モジュール・ソース・ファイル (この例では
/sys/streamsm/mymodule.c) 内で構成ルーチンを宣言する。
このサンプルの
mymod_configure
は,モジュール用です。
ドライバに使用する場合は,次のようにします。
コメント行
/* driver */
に続く次の行のコメントをはずす。
/* sa.sa_flags = STR_IS_DEVICE | STR_SYSV4_OPEN; */
コメント行
/* module */
に続く次の行をコメントにする。
sa.sa_flags = STR_IS_MODULE | STR_SYSV4_OPEN;
/* * Sample mymodule.c */
.
.
.
#include <sys/sysconfig.h> #include <sys/errno.h> struct streamtab mymodinfo = { &rinit, &winit }; cfg_subsys_attr_t mymod_attributes[] = { [1] {,0,0,0,0,0,0} /* required last element */ }; int mymod_configure( cfg_op_t op; caddr_t indata; ulong indata_size; caddr_t outdata; ulong outdata_size) { dev_t devno = NODEV; [2] struct streamadm sa; if (op != CFG_OP_CONFIGURE) [3] return EINVAL; sa.sa_version = OSF_STREAMS_10; /* module */ [4] sa.sa_flags = STR_IS_MODULE | STR_SYSV4_OPEN; /* driver */ /* sa.sa_flags = STR_IS_DEVICE | STR_SYSV4_OPEN; */ sa.sa_ttys = NULL; sa.sa_sync_level = SQLVL_MODULE; [5] sa.sa_sync_info = NULL; strcpy(sa.sa_name, "mymod"); if ((devno = strmod_add(devno, &mymodinfo, &sa)) == NODEV) { return ENODEV; } return ESUCCESS; }
この例は簡略化されているので,例中のサブルーチンが提供する属性テーブルは空で,サブルーチンに属性が渡されることも予期していません。 モジュールに属性を開発する場合は『プログラミング・ガイド』を参照してください。 [例に戻る]
cdevsw
テーブルの最初の仕様可能なスロットは自動的にモジュールに割り当てられます。
特定のデバイス番号を予約する場合は,conf.c
プログラムの
cdevsw
テーブルを調べてから定義してください。
cdevsw
テーブルおよびデバイス・ドライバ・エントリの追加についての詳細は『Writing Device Drivers』 を参照してください。
[例に戻る]
このルーチン例では,CFG_OP_CONFIGURE
オプションだけがサポートされています。
構成ルーチンの他のオプションについては『プログラミング・ガイド』を参照してください。
[例に戻る]
STR_SYSV4_OPEN
は,AT&T System V Release 4 の呼び出しシーケンスを使用して,モジュールまたはデバイスの
open
および
close
ルーチンを呼び出すことを指定します。
このビットが指定されていない場合には,AT&T System V Release 3.2 の呼び出しシーケンスが使用されます。
[例に戻る]
モジュールをカーネルと静的にリンクする。
構成する STREAMS モジュールを動的にロード可能にする場合は『プログラミング・ガイド』のカーネル・サブシステムの構成について参照してください。 構成するモジュールがハードウェア・デバイス・ドライバの場合は『Writing Device Drivers』 を参照してください。
モジュールをカーネルと静的にリンクする場合は,モジュールのソース・ファイル (mymodule1.c
および
mymodule2.c) を
/sys/streamsm
ディレクトリに置き,次の例のように
/sys/conf/files
ファイルのエントリに各ファイルを追加します。
次の例は,mymodule1.c
および
mymodule2.c
の
/sys/conf/files
ファイルのエントリを示します。
streamsm/mymodule1.c optional mymod Notbinary streamsm/mymodule2.c optional mymod Notbinary
カーネル構成ファイルに
MYMOD
オプションを追加します。
省略時のカーネル構成ファイルは
/sys/conf/HOSTNAME
です。
(HOSTNAME
にはシステムの名前を大文字で指定します)
たとえばシステム名が
TRU64
の場合,構成ファイル
/sys/conf/TRU64
に次の行を追加します。
options MYMOD
ハードウェア・デバイス・ドライバを組み込んでいる場合は,手順 3 を続け,ハードウェア・デバイス・ドライバを組み込んでいない場合には,手順 4 に進みます。
ハードウェア・デバイス・ドライバを組み込んでいる場合は,手順 3a から手順 3d までをすべて実行する。
ハードウェア・デバイス・ドライバを組み込んでいない場合には,手順 4 に進みます。
ハードウェア・デバイス・ドライバを組み込んでいる場合は,事前に
XXprobe
および
interrupt
ルーチンを定義しておかなければなりません。
probe
ルーチンおよび
interrupt
ルーチンの定義方法についての詳細は,『Writing Device Drivers』 を参照してください。
次の行を,デバイス・ドライバ構成ファイルの先頭に追加する。
この例では,デバイス・ドライバ構成ファイルは,/sys/stream/mydriver.c
です。
#include <io/common/devdriver.h>
コントローラ構造体へのポインタを定義する。
たとえば,次のようにします。
struct controller *XXinfo;
コントローラ構造体についての詳細は,『Writing Device Drivers』 を参照してください。
driver
構造体を宣言して初期化する。
たとえば,次のようにします。
struct driver XXdriver =
{
XXprobe, 0, 0, 0, 0, XXstd, 0, 0, "XX", XXinfo
};
driver
構造体についての詳細は,『Writing Device Drivers』 を参照してください。
コントローラ行を,カーネル構成ファイルに追加する。
省略時のカーネル構成ファイルは
/sys/conf/HOSTNAME
です。
ここで
HOSTNAME
はマシンの名前です (大文字で示します)。
たとえば,使用しているシステムの名前が
TRU64
の場合,次のような 1 行を
/sys/conf/TRU64
構成ファイルに追加します。
controller XX0 at bus vector XXintr
bus
キーワードが取り得る値についての詳細は,『システム管理ガイド』を参照してください。
doconfig
コマンドを使用して,このマシン用の新しいカーネルを,再構成,再構築して,ブートする。
カーネルの再構成についての詳細は,
doconfig(8)
strsetup -c
コマンドを実行して,デバイスが正しく構成されていることを確認する。
# /usr/sbin/strsetup -c
STREAMS Configuration Information...Wed Jun 2 09:30:11 1994
Name Type Major Minor Module ID
---- ---- ----- ----- ---------
clone 32 0
ptm device 37 0 7609
pts device 6 0 7608
log device 36 0 44
nuls device 38 0 5001
echo device 39 0 5000
sad device 40 0 45
pipe device 41 0 5304
kinfo device 42 0 5020
xtisoUDP device 43 0 5010
xtisoTCP device 44 0 5010
dlb device 49 0 5010
bufcall module 0
timod module 5006
tirdwr module 0
ifnet module 5501
ldtty module 7701
null module 5003
pass module 5003
errm module 5003
spass module 5007
rspass module 5008
pipemod module 5303
Configured devices = 11, modules = 11
この節では,STREAMS デバイス特殊ファイルとその作成方法について説明します。
また,clone
デバイスの概要についても説明します。
すべての STREAMS ドライバには,システムに作成された文字型特殊ファイルがなければなりません。
これらのファイルは,通常,/dev/streams
にあり,インストール時に作成されるか,または
/usr/sbin/strsetup
ユーティリティを実行することによって作成されます。
STREAMS ドライバには,主デバイス番号が関連付けられています。
これは,ドライバをシステムに組み込むときに決定されます。
STREAMS 以外のドライバには,通常,主デバイスと副デバイス番号の各組み合わせに対して文字型特殊ファイルが定義されています。
次は,/dev/rdisk
ディレクトリのエントリの例です。
crw------- 1 root system 8, 1024 Aug 25 15:38 dsk1a crw------- 1 root system 8, 1025 Aug 25 15:38 dsk1b crw------- 1 root system 8, 1026 Aug 25 15:38 dsk1c
この例では,dsk1a
の主デバイス番号は 8 であり,副デバイス番号は 1024 です。
dsk1b
は,主デバイス番号が 8 で,副デバイス番号が 1025,dsk1c
は,主デバイス番号が 8 で,副デバイス番号が 1026 です。
また,STREAMS ドライバの場合にも,主デバイス番号と副デバイス番号の各組み合わせに対して文字型特殊ファイルを定義できます。
次は,/dev/streams
ディレクトリのエントリの例です。
crw-rw-rw- 1 root system 32, 0 Jul 13 12:00 /dev/streams/echo0 crw-rw-rw- 1 root system 32, 1 Jul 13 12:00 /dev/streams/echo1
この例では,echo0
の主デバイス番号は 32 であり,副デバイス番号は 0 です。
echo1
は,主デバイス番号が 32 で,副デバイス番号が 1 です。
アプリケーションが,デバイスに対して一意のストリームをオープンするためには,そのデバイスの未使用の副デバイスをオープンしなければなりません。
最初のアプリケーションは,/dev/streams/echo0
についてオープンでき,2 番目のアプリケーションは,/dev/streams/echo1
についてオープンできます。
これらの各デバイスは,異なる副デバイス番号を持つので,各アプリケーションは,echo ドライバに対して一意のストリームを獲得します。
この方法では,各デバイス (この場合は echo) について,オープンできる各副デバイス用に 1 つの文字型特殊ファイルが必要です。
また,この方法では,すでに使用されている文字型特殊ファイルをオープンしないようにするために,アプリケーションがどの文字型特殊ファイルをオープンするべきかを判断する必要があります。
clone
デバイスは,オープンできる各副デバイスに対して,デバイス特殊ファイルを定義するもう 1 つの方法を提供します。
clone
デバイスを使用すると,各ドライバは,文字型特殊ファイルを 1 つだけ必要とします。
また,現在利用できる副デバイスをアプリケーションが判別する必要はなく,その代わりに,clone
デバイスの主デバイス番号を使用して,2 番目 (または 3 番目) のデバイスをオープンできます。
副デバイス番号は,オープンされているデバイス (この場合は echo) に関連付けられます。
clone
デバイスの主デバイス番号を使用してデバイスをオープンするたびに,STREAMS ドライバは,そのデバイスを一意のストリームとして解釈します。
strsetup
コマンドは,/dev/streams
ディレクトリにエントリを設定して,clone
デバイスを使用できるようにします。
次は,/dev/streams
ファイルのエントリの例です。
crw-rw-rw- 1 root system 32, 18 Jul 13 12:00 /dev/streams/echo
この例では,システムによって,clone
デバイスに主デバイス番号 32 が割り当てられています。
18 は,echo
に関連付けられた主デバイス番号です。
アプリケーションが
/dev/streams/echo
をオープンすると,clone
デバイスは,この呼び出しを遮断して,echo ドライバの代わりに
open
ルーチンを呼び出します。
さらに,clone
は,echo ドライバに,クローン・オープンを行うことを通知します。
echo ドライバがクローン・オープンを認識すると,主デバイス番号 18,および最初に利用できる副デバイス番号を返します。
注意
/usr/sbin/strsetupコマンドが作成する文字型特殊ファイルは,省略時には,主デバイス番号と同様にcloneを使用して/dev/streamsディレクトリに作成されます。 クローン・オープンを使用しないか,または異なる名前を使用している STREAMS ドライバをカーネルに組み込む場合は,に記述されている strsetup.conf(4)/etc/strsetup.confファイルを変更しなければなりません。使用しているシステムの
cloneデバイスの主デバイス番号を調べる場合は,strsetup -cコマンドを実行します。
STREAMS のエラーとイベントのロギングは,次の事項に関連しています。
エラー・ロガー・デーモン
トレース・ロガー
strclean
コマンド
エラー・ロガー・デーモン,strerr
は,STREAMS のエラー・ロギングおよびイベント・トレース機能に送信されたすべてのエラー・メッセージを,ファイルに記録します。
トレース・ロガー,strace
は,STREAMS のエラー・ロギングおよびイベント・トレース機能に送信されたトレース・メッセージを,標準出力に書き込みます。
strclean
コマンドを実行すると,strerr
デーモンによって生成された古いログ・ファイルをすべて削除することができます。
STREAMS モジュールまたはドライバは,strlog
カーネル・インタフェースを通して,エラー・メッセージおよびイベント・トレース・メッセージを,STREAMS のエラー・ロギングおよびイベント・トレース機能に送信できます。
これには,strlog
の呼び出しが含まれます。
次の例では,STREAMS ドライバが,オープン・ルーチンの実行中に,STREAMS のエラー・ロギングおよびイベント・トレース機能の両方に,主デバイス番号および副デバイス番号を出力します。
#include <sys/strlog.h>
strlog(MY_DRIVER_ID, 0, 0, SL_ERROR 1 SL_TRACE,
"My driver: mydriver_open() - major=%d,minor=%d",
major(dev,minor(dev));
また,ユーザ・プロセスも,/dev/streams/log
に対してストリームをオープンし,putmsg
を呼び出すことによって,STREAMS のエラー・ロギングおよびイベント・トレース機能に,メッセージを送信できます。
ログ・メッセージを
strlog
に引き渡すために,ユーザ・プロセスには,次のようなコードが含まれていなければなりません。
struct strbuf ctl, dat; struct log_ctl lc; char *message = "Last edited by <username> on <date>"; ctl_len = ctl.maxlen = sizeof (lc); ctl.buf = (char *)&lc; dat.len = dat.maxlen = strlen(message); dat.buf = message; lc.level = 0; lc.flags = SL_ERROR|SL_NOTIFY; putmsg (log, &ctl, &dat, 0);