(57)【要約】【課題】　特定のシステムコールを転向させることにより、再コンパイルすることなくソフトウェアアプリケーション中のシステムコールのパフォーマンスを向上させる。【解決手段】　本発明に係る方法は、ファイル記述子を代替イベント機構に登録することをさらに提供し、各ファイル記述子は、アプリケーションにとっての関心イベントを有することができる。また、本発明に係る方法は、代替イベント機構に登録されたファイル記述子を有するソケットのスキャンをさらに提供する。【選択図】図３
2004070948.tif 000002
【特許請求の範囲】
【請求項１】
　ソフトウェアアプリケーションにおいてシステムコールを代替機構で置き換える方法であって、
　システムコールをエミュレートするソフトウェアコードを含むライブラリの名前をソフトウェアアプリケーションにおける環境変数のための値として割り当てることと、
　前記ソフトウェアアプリケーションを起動することであって、これにより前記ソフトウェアアプリケーションに関連するローダが読み出される、起動することと、
　前記ローダが前記ライブラリを前記ソフトウェアアプリケーションにプレロードすることと、
　前記ソフトウェアアプリケーションがシステムコールを要求する場合、前記代替機構を呼び出すように前記ソフトウェアアプリケーションを転向させる（redirect）ことであって、該代替機構の呼び出しは、前記ライブラリを前記システムコールとして実施する、転向させることと
　を含む方法。
【請求項２】
　前記アプリケーションが関心のあるイベントのソケットを特定するファイル記述子リストを使用して、前記アプリケーションが前記システムコールを行う場合、複数のファイル記述子および関心イベントを前記代替機構に登録することをさらに含み、前記複数の前記ファイル記述子はそれぞれ、関係する関心ソケットに関する関心イベントに関連する
　請求項１記載の方法。
【請求項３】
　関心イベントが示される、前記代替機構に登録されたファイル記述子を有するソケットを調べること
　をさらに含む請求項２記載の方法。
【請求項４】
　前記代替機構の呼び出しに必要な、関心のあるファイル記述子の数を規定することを
　さらに含む請求項１記載の方法。
【請求項５】
　前記ファイル記述子の数が前記代替機構の呼び出しに必要な前記規定のファイル記述子の最小数を越える場合、前記代替機構を呼び出すこと
　をさらに含む請求項４記載の方法。
【請求項６】
　前記ソフトウェアアプリケーションが期待する機能性を前記ライブラリが提供することができない場合、前記システムコールに戻ることを
　さらに含む請求項１記載の方法。
【請求項７】
　前記システムコールはｓｅｌｅｃｔシステムコールである
　請求項１記載の方法。
【請求項８】
　前記システムコールはｐｏｌｌシステムコールである
　請求項１記載の方法。
【請求項９】
　前記ソフトウェアアプリケーションが動作可能な前記オペレーティングシステムは、前記代替機構の機能性を包含している
　請求項１記載の方法。
【請求項１０】
　コンピュータ実施命令を格納するコンピュータ可読媒体であって、
　前記命令は、
　システムコールに関連するプロセスを実行するソフトウェアコードを含む名前付けられたライブラリをソフトウェアアプリケーションにおける環境変数値として格納することと、
　前記ソフトウェアアプリケーションを起動し、これにより前記ソフトウェアアプリケーションに関連するローダが呼び出される、起動することと、
　前記ローダにより前記ライブラリを前記ソフトウェアアプリケーションにプレロードすることと、
　前記ソフトウェアアプリケーションがシステムコールを要求する場合、代替機構を呼び出すように前記ソフトウェアアプリケーションを転向させることであって、該代替機構の呼び出しは、前記ライブラリを前記システムコールとして実施する、転向させることと
　をコンピュータシステムに実行させるコンピュータ可読媒体。
【請求項１１】
　前記コンピュータ実施可能命令は、前記アプリケーションが関心のあるイベントのソケットを特定するファイル記述子リストを使用して、前記アプリケーションが前記システムコールを行う場合、複数のファイル記述子および関心イベントを前記代替機構に登録することをコンピュータシステムに実行させ、
　前記複数の前記ファイル記述子はそれぞれ、関心のある関連ソケットに関する関心イベントに関連する
　請求項１０記載のコンピュータ可読媒体。
【請求項１２】
　前記コンピュータにより実行可能な命令は、関心イベントが示される前記代替機構に登録されたファイル記述子を有するソケットを調べることをコンピュータシステムに実行させる
　請求項１１記載のコンピュータ可読媒体。
【請求項１３】
　前記コンピュータ実装可能命令は、前記代替機構の呼び出しに必要な規定の関心ファイル記述子の最小数を格納することをコンピュータシステムに実行させる
　請求項１０記載のコンピュータ可読媒体。
【請求項１４】
　前記コンピュータ実装可能命令は、前記ファイル記述子の最小数を越える場合、前記代替機構を呼び出すことをコンピュータシステムに実行させる
　請求項１４記載のコンピュータ可読媒体。
【請求項１５】
　前記コンピュータ実装可能命令は、前記ソフトウェアアプリケーションが期待する機能性を前記ライブラリが提供することができない場合、前記システムコールに戻ることをコンピュータシステムに実行させる
　請求項１１記載のコンピュータ可読媒体。
【請求項１６】
　前記システムコールはｓｅｌｅｃｔシステムコールである
　請求項１１記載のコンピュータ可読媒体。
【請求項１７】
　前記システムコールはｐｏｌｌシステムコールである
　請求項１１記載のコンピュータ可読媒体。
【請求項１８】
　前記ソフトウェアアプリケーションが動作可能な前記オペレーティングシステムは、前記代替機構の機能性を包含している
　請求項１１記載のコンピュータ可読媒体。
【請求項１９】
　コンピュータシステムネットワークにおけるコンピュータシステムであって、
　バスと、
　該バスに結合された表示装置と、
　前記バスに結合されたメモリユニットと、
　前記バスに結合され、ソフトウェアアプリケーションにおいてシステムコールを代替機構に変換させる方法を実行するプロセッサと
　を備え、
　前記方法は、
　前記ソフトウェアアプリケーションを起動し、これにより前記ソフトウェアアプリケーションに関連するローダが呼び出される、起動することと、
　システムコールをエミュレートするソフトウェアコードを含むライブラリ変数を前記ソフトウェアアプリケーションにプレロードすることと、
　前記アプリケーションが関心のあるイベントのソケットを特定するファイル記述子リストを使用して、前記アプリケーションが前記システムコールを行う場合、複数のファイル記述子および関心イベントを前記代替機構に登録することであって、前記複数の前記ファイル記述子はそれぞれ、関心のある関連ソケットに関する関心イベントに関連する、登録することと、
　前記ソフトウェアアプリケーションがシステムコールを要求する場合、前記代替機構を呼び出すように前記ソフトウェアアプリケーションを転向させることであって、該代替機構の呼び出しは、前記名前付けられたライブラリを前記システムコールとして実行する、転向させることと、
　関心イベントが示される前記代替機構に登録されたファイル記述子を有するソケットにアクセスすることと
　を含むコンピュータシステム。
【請求項２０】
　前記方法は、前記代替機構の呼び出しに必要な規定のファイル記述子の最小数を格納すること
　をさらに含む請求項１９記載のコンピュータシステム。
【請求項２１】
　前記方法は、前記ファイル記述子の数が前記最小数を越えた後に、前記代替機構を呼び出すこと
　をさらに含む請求項２０記載のコンピュータシステム。
【請求項２２】
　前記方法は、前記ソフトウェアアプリケーションが期待する機能性を前記名前付けられたライブラリが提供することができない場合、前記システムコールに戻ることを
　さらに含む請求項１９記載のコンピュータシステム。
【請求項２３】
　前記システムコールはｓｅｌｅｃｔシステムコールである
　請求項１９記載のコンピュータシステム。
【請求項２４】
　前記システムコールはｐｏｌｌシステムコールである
　請求項１９記載のコンピュータシステム。
【請求項２５】
　前記ソフトウェアアプリケーションが動作可能な前記オペレーティングシステムは、前記代替機構の機能性を包含している
　請求項１９記載のコンピュータシステム。
【請求項２６】
　ソフトウェアアプリケーションにおいて、代替機構を利用してライブラリの関数へのシステムコールを変換させるシステムであって、
　ソフトウェアアプリケーションを格納し起動する手段と、
　該ソフトウェアアプリケーションに関連するローダを呼び出す手段と、
　前記ソフトウェアアプリケーションが起動されると、前記システムコールをエミュレートするソフトウェアコードを含むライブラリを前記ソフトウェアアプリケーションにプレロードする手段と、
　前記アプリケーションが関心のあるイベントのソケットを特定するファイル記述子リストを使用して、前記アプリケーションが前記システムコールを行う場合、複数のファイル記述子および関心イベントを前記代替機構に登録する手段であって、前記複数の前記ファイル記述子はそれぞれ、関心のある関連ソケットに関する関心イベントに関連する、登録手段と、
　前記ソフトウェアアプリケーションがシステムコールを要求する場合、前記代替機構を呼び出すように前記ソフトウェアアプリケーションを転向させる手段であって、該代替機構の呼び出しは、前記ライブラリを前記システムコールとして実行する、転向手段と、
　関心イベントが示される前記代替機構に登録されたファイル記述子を有するソケットを調べる手段と
　を備えるシステム
【請求項２７】
　前記代替機構の呼び出しに必要なファイル記述子の最小数を規定する手段を
　さらに備える請求項２６記載のシステム。
【請求項２８】
　前記ファイル記述子の数が前記最小数を上回る場合、前記代替機構を呼び出す手段を
　さらに備える請求項２６記載のシステム。
【請求項２９】
　前記ソフトウェアアプリケーションが期待する機能性を前記ライブラリが提供することができない場合、前記システムコールに戻る手段を
　さらに備える請求項２６記載のシステム。
【請求項３０】
　前記ソフトウェアアプリケーションが動作可能な前記オペレーティングシステムに、前記代替機能の機能性を包含させる手段を
　さらに備える請求項２６記載のシステム。
【発明の詳細な説明】
【技術分野】
【０００１】
　本発明の実施形態は、ソフトウェアアプリケーションのパフォーマンスの向上に関する。
　特に本発明は、アプリケーションを再コンパイルする必要なくソフトウェアアプリケーションのパフォーマンスを向上させる方法を提供するものである。
【背景技術】
【０００２】
　コンピュータシステムまたはコンピュータネットワークでは、ポート番号により送信アプリケーションまたは宛先アプリケーションを特定する。
　ホストコンピュータシステム上で実行されているあらゆるアプリケーションは、特定のポートまたはある範囲のポートを使用して、他のホストコンピュータシステム上で実行されている他のアプリケーションと通信する。
　通信プロトコル、たとえばＴＣＰ（伝送制御プロトコル）またはＵＤＰ（ユーザデータグラムプロトコル）は、これらポート番号により、アプリケーションレイヤにおいてどのアプリケーションにデータを渡すかを決める。
【０００３】
　あるコンピュータシステム上のアプリケーションは、別のコンピュータシステム上のアプリケーションと通信したい場合、装置のアドレス（ＩＰアドレス）を指定するとともに、アプリケーション（ポート番号）を特定しなければならない。
　送信ポート番号、宛先ポート番号、送信ＩＰアドレス、および宛先ＩＰアドレスの組み合わせによってソケットが定義される。
　ソケットは、ＵＤＰまたはＴＣＰコネクションを一意に定義するために使用することができる。
【０００４】
　アプリケーション、たとえばインターネットアプリケーションは当初、１つまたは２つのソケットに対応するように書かれていた。
　インターネットアプリケーション、たとえばＴｅｌｎｅｔ、ＵＤＰ、またはＴＣＰ等は通常、１つまたは２つのソケットに対応するため、一度に１つまたは２つのコネクションを処理する。
　各ソケットにはソケットコールが関連付けられている。
　ソケットコールは、ソケットからの読み出しコール、ソケットへの書き込みコール、ソケット誤り修正コール等であることができるが、これらに限定されない。
【０００５】
　インターネット、特にワールドワイドウェブの普及により、多数のソケットに役立つ／多数のソケットを処理するように適合されたタイプのコンピュータシステムであるウェブサーバが開発された。
　今日の現行ウェブサーバの多くは、何千ものソケット／コネクションを同時に処理することができる。
【発明の開示】
【発明が解決しようとする課題】
【０００６】
　ソケットコールは上に列挙したもの、たとえば読み出し、書き込み、およびエラーチェックと同じであるが、処理するソケットの数は１つや２つではなく、通常何千とまではいかないが何百ものソケットを同時に開くことが可能である。
　これは、アプリケーションが各ソケットを読み出し、書き込み、かつ／またはエラーチェックに関してチェックすることを意味する。
　したがってアプリケーションは、何千ものソケットに対するソケットコールの実行に膨大な量の処理時間を費やす。
　不都合なことに、インターネットアプリケーションが何千という多数のソケットコールを実行している間は、他の有用な作業またはプロセスを実行することができない場合がある。
【０００７】
　この欠点を解消するために、ソケットからの読み出しが許可されているとき、またはソケットへの書き込みが許可されているときをアプリケーション、たとえばインターネットアプリケーションに通知することができるシステムコール、たとえばｓｅｌｅｃｔシステムコールおよびｐｏｌｌシステムコールが開発された。
【０００８】
　システムコールに伴う欠点がないわけではない。
　ｐｏｌｌコールまたはｓｅｌｅｃｔコールが行われると、カーネルは、ｐｏｌｌまたはｓｅｌｅｃｔコールにおいてアプリケーションが開けているあらゆるソケットを調べ、ソケットをロック／アンロックし、関心イベントについてチェックする。
　ソケットは何百、何千、または何万という数である可能性があり、各ソケットを調べる（ソケットによっては保留機構を備えているものもある）ため、これにも大量の処理時間が費やされる場合がある。
　したがって、多くのアプリケーションには効率的なソケット通信が提供されていない。　
【課題を解決するための手段】
【０００９】
　本発明の実施形態は、ファイル記述子を代替イベント機構に登録することをさらに提供し、各ファイル記述子は、アプリケーションにとっての関心イベントを有することができる。
　本発明の実施形態は、代替イベント機構に登録されたファイル記述子を有するソケットのスキャンをさらに提供する。
【００１０】
　一実施形態では、ソフトウェアアプリケーションにおいてシステムコールを代替の機構で置き換える方法は、ソフトウェアアプリケーションにおける環境変数の値としてライブラリに名称を割り当てることを含む。
　ライブラリは、システムコールをエミュレートするソフトウェアコードからなる。
　本方法はソフトウェアアプリケーションを起動させ、これによりソフトウェアアプリケーションに関連するローダを呼び出すことをさらに含む。
【００１１】
　本方法は、ライブラリをソフトウェアアプリケーションにプレロードすることをさらに含む。
　ローダはプレロードを行う。
　本方法は、ソフトウェアアプリケーションがシステムコールを要求するとき、ソフトウェアアプリケーションを転向させて代替イベント機構を呼び出すことをさらに含む。
　代替機構の呼び出しは、ライブラリを上記システムコールとして実装する。
【００１２】
　本方法は、アプリケーションが、アプリケーションが関心のあるイベントのソケットを特定するファイル記述子リストを使用して、アプリケーションが上記システムコールを行う場合、複数のファイル記述子および関心イベントを代替機構に登録することをさらに含む。
　上記複数の上記ファイル記述子はそれぞれ、関係する関心ソケットに関連する関心イベントに関連する。
　登録されたファイル記述子を有するソケットが、ソフトウェアアプリケーションによって検査される。
【発明の効果】
【００１３】
　本発明によれば、特定のシステムコールを転向させることにより、再コンパイルすることなくソフトウェアアプリケーション中のシステムコールのパフォーマンスを向上させることができる。
【発明を実施するための最良の形態】
【００１４】
　添付図面は、本明細書に組み込まれて本明細書の一部をなすとともに、本発明の実施形態を示し、説明と併せて本発明の原理の説明に役立つものである。
【００１５】
　アプリケーションを再コンパイルすることなく、ソフトウェアアプリケーションにおける選択されたシステムコールのパフォーマンスを向上させる方法の実施形態について述べる。
　これより、添付図面に例示する本発明の好ましい実施形態を詳細に参照する。
　本発明について好ましい実施形態と併せて述べるが、本発明をこれらの実施形態に限定する意図がないことは認められよう。
　対照的に、本発明は、併記の特許請求項によって規定される本発明の精神および範囲内に含めることのできる代替、変更、および同等物を網羅するよう意図される。
　さらに、以下の本発明の詳細な説明では、本発明の完全なる理解を提供するために多くの具体的な詳細を示している。
【００１６】
　一実施形態では、アプリケーションのパフォーマンスを向上させる方法は、ｓｅｌｅｃｔシステムコール、ｐｏｌｌシステムコール、およびｃｌｏｓｅコールを含むがこれらに限定されない、アプリケーションに関連する特定のシステムコールの代替を提供するコンピュータ命令ライブラリ、たとえば図１および図２のシム（ｓｈｉｍ）ライブラリ１５０を含む。
　シムライブラリは、関心ソケット上での関心イベントに関連する情報を提供するコードを含む。
【００１７】
　関心ソケットでの関心イベントは、アプリケーションにより代替イベント機構に自動的に登録される。
　シムライブラリは、呼び出されると、アプリケーションのｓｅｌｅｃｔおよびｐｏｌｌシステムコールを回避し、それぞれのスレッドで、アプリケーションが実行されているオペレーティングシステム内に含まれる機能、たとえばＥｖｅｎｔｐｏｒｔｓを利用して、回避したシステムコールに類似する機能を開始する。
【００１８】
　本発明の実施形態の利点は、以下に示すように、シムライブラリがアプリケーションのロードから独立して呼び出されることである。
　別の利点は、シムライブラリの変更により、アプリケーションが再コード化または再コンパイルを行う必要がないことである。
　さらなる利点は、シムライブラリにより、各ソケットが調べられる従来のシステムコールと比較して、登録され、関心イベントが保留になっているソケットのみを調べることで、システムコールに費やされるプロセッサ時間が一般に短くなることである。
【００１９】
　本発明の実施形態については、ネットワークおよび／またはクライアントサーバ環境において複数のソケット、たとえばインターネットアプリケーションに同時にサービス提供する、すなわちこれらを処理することができるソフトウェアアプリケーションの文脈において主に考察する。
　しかし、本発明の実施形態は、インターネットアプリケーションを含むがこれに限定されない複数のソケットに同時にサービス提供する、すなわちこれらを処理するように適合された他のソフトウェアアプリケーションも利用可能なことに留意されたい。
【００２０】
　図１は、本発明の実施形態を実施することができる例示的なクライアントサーバコンピュータシステムネットワーク、たとえばネットワーク１００を示すブロック図である。
　ネットワーク１００は、組織または企業のファイアウォール内にある通信ネットワーク（「イントラネット」）でよく、またはワールドワイドウェブすなわちインターネットの一部を表してもよい。
　クライアント（またはユーザ）コンピュータシステム１９０ａおよび１９０ｂと、サーバコンピュータシステム１９１とは、通信回線１７３ａおよび１７３ｂを介して通信可能に接続され、インターネットまたはイントラネットにわたってコンピュータシステムを接続する機構は、当分野において既知である。
【００２１】
　この接続は、ＩＰ（インターネットプロトコル）、ＴＣＰ（伝送制御プロトコル）、ＵＤＰ（ユーザデータグラムプロトコル）、ＴＥＬＮＥＴ、ＮｅｔＢＩＯＳ、ＩＰＸ（インターネットパケット交換）、およびＬＵ６．２等のネットワーク接続と、イーサネット（登録商標）、トークンリング、およびＡＴＭ（非同期転送モード）等のリンクレイヤプロトコルとをサポートするあらゆるネットワークプロトコルを介して行うことができる。
　代替として、クライアントコンピュータシステム１９０ａおよび１９０ｂは、サーバコンピュータシステム１９１の入出力ポート（たとえば、シリアルポート）を介してサーバコンピュータシステム１９１に接続することができる。
　すなわち、クライアントコンピュータシステム１９０ａおよび１９０ｂ、ならびにサーバコンピュータシステム１９１は、ネットワーク化されていない装置であってもよい。
【００２２】
　簡単にするために、２つのクライアントコンピュータシステムおよび１つのサーバコンピュータシステムのみが示されることは認められよう。
　しかし、ネットワーク１００は任意の数のクライアントコンピュータシステムおよびサーバコンピュータシステムを含むことができることが認められよう。
【００２３】
　さらに図１を参照して、一実施形態では、サーバ１９１に配置された、本発明の実施形態を表す命令ライブラリ、たとえばシムライブラリ１５０（Ｓ＿Ｌ１５０）も示す。
　一実施形態では、シムライブラリ１５０は、クライアントコンピュータ１９０ａおよび１９０ｂにも同様に配置される。
　一実施形態では、シムライブラリ１５０（Ｓ＿Ｌ１５０）は、アプリケーションが演算中に行うシステムコールのうちのいくつか、たとえばｓｅｌｅｃｔシステムコールおよびｐｏｌｌシステムコールの代わりに使用されるソフトウェア命令またはコードの集まりを含む。
【００２４】
　図２は、クライアントコンピュータシステム、たとえば図１のクライアントコンピュータシステム１９０ａおよび／または１９０ｂ内、ならびにサーバコンピュータシステム、たとえば図１のサーバコンピュータシステム１９０内で実施することのできる、本発明を実施可能な例示的なコンピュータシステム２００のコンポーネントおよび回路を示すブロック図である。
　コンピュータシステム２００は、情報を通信するためのアドレス／データバス２１０と、バスに接続され、情報および命令を処理する中央プロセッサ２０１と、バス２１０に接続され、中央プロセッサ２０１のために情報および命令を格納する揮発性メモリ（たとえば、ランダムアクセスメモリ、ＲＡＭ）２０２と、バスｌ２１０に接続され、プロセッサ２０１のために静的な情報および命令を格納する不揮発性メモリ（たとえば、読み取り専用メモリ、ＲＯＭ）２０３とを含む。
　一実施形態では、コンピュータシステム２００は複数のプロセッサ２０１を備えるように構成可能なことに留意されたい。
【００２５】
　図２のコンピュータシステム２００は、バス２１０に接続され、情報および命令、たとえばシムライブラリ１５０を格納するデータ格納装置２０４も含む。
　たとえば、データ格納装置２０４は、ＨＤＤ（ハードディスクドライブ）、ＦＤＤ（フロッピー（登録商標）ディスクドライブ）、メモリースティック、ＣＤ−ＲＷ（書き換え可能なコンパクトディスク）、テープドライブ等であることができ、さらに装置２０４はこれらの集まりまたは組み合わせであってもよい。
　データ格納装置２０４はまた、多重インスタンス化可能、取り外し可能、かつ／またはホットスワップ（コンピュータに電源を投入したままで着脱）可能であってもよい。
【００２６】
　さらに図２を参照すると、コンピュータシステム２００は、バス２１０に接続され、コンピュータシステム２００とネットワーク環境、たとえば図１のネットワーク環境１００との間に通信リンクを提供するネットワーク通信装置２３５も含む。
　したがって、ネットワーク通信装置２３５は、中央プロセッサユニット２０１が、ネットワーク、たとえば図１のネットワーク１００に接続された他の電子システムと通信できるようにする。
【００２７】
　ネットワーク通信装置２３５の本実施形態は幅広い方法で実施するのに適していることを理解されたい。
　一例では、ネットワーク通信装置２３５はアンテナに接続され、無線通信インタフェースを介して情報を送受信する機能を提供する。
　別の例では、ネットワーク通信装置２３５はモデムとして実施することができる。
　さらに別の例では、ネットワーク通信装置２３５はＮＩＣ（ネットワークインタフェースカード）として構成することができる。
【００２８】
　さらに図２を参照すると、一実施形態では、ネットワーク通信装置２３５は、ネットワーク通信装置２３５を介して送信すべきデータまたは受信したデータを処理するオプションのデジタル信号プロセッサ（ＤＳＰ）２２０を含む。
　代替として、プロセッサ２０１は、ＤＳＰ２２０によって実行される機能のいくつかまたはすべてを実行することができる。
【００２９】
　図２のコンピュータシステム２００には、オプションの文字数字入力装置２０６も含まれる。
　一実施態様では、装置２０６はキーボードである。
　文字数字入力装置２０６は、情報およびコマンド選択をプロセッサ２０１に伝えることができる。
【００３０】
　図２のコンピュータシステム２００は、バス２１０に接続され、ユーザ入力情報およびコマンド選択をプロセッサ２０１に伝えるオプションのカーソル制御または指示装置（オンスクリーンカーソル制御装置２０７）も含む。
　トラックボール、マウス、ジョイスティック、または所与の方向での移動または変位方法を伝えることができる、文字数字入力装置２０６上の特別なキーを含め、カーソル制御装置の多くの実施態様が当分野において既知である。
　カーソル制御装置２０７は、特別なキーおよびキーシーケンスコマンドを使用してのキーボードからの入力を介して指示かつ／または起動してもよいことを認められたい。
　代替として、カーソルは、複数の特別に適合されたカーソル指示装置からの入力を介して指示かつ／または起動してもよい。
【００３１】
　一実施態様では、オンスクリーンカーソル制御装置２０７は、表示装置２０５に組み込まれたタッチスクリーン装置である。
　オンスクリーンカーソル制御装置２０７は、ポインティングオブジェクト、たとえばスタイラスまたはユーザの手指が接触した表示装置２０５上の位置を登録することができる。
　別の実施態様では、オンスクリーンカーソル制御装置２０７はタッチパッドであり、また別の実施態様では手指で起動される押し棒（プッシュスティック）である。
　別の一般的な実施態様では、オンスクリーンカーソル制御装置２０７はマウスまたは同様のポインティングデバイスである。
【００３２】
　コンピュータシステム２００は、バス２１０に接続され、情報をコンピュータユーザに表示する表示装置２０５も含む。
　表示装置２０５は、グラフィックイメージおよび文字数字キャラクタをユーザが認識できるように生成することに適している。
　複数の表示技法、たとえば陰極線管（ＣＲＴ）、液晶ディスプレイ（ＬＣＤ）、電界放出ディスプレイ（ＦＥＤ）、薄膜トランジスタ（ＴＦＴ）、プラズマ等のいずれを表示装置２０５に使用することができる。
【００３３】
　本発明の実施形態によって提供される機能をまとめて参照すると、シムライブラリ、たとえば図１および図２のシムライブラリ１５０は、アプリケーション、たとえばインターネットアプリケーションのｓｅｌｅｃｔ、ｐｏｌｌ、およびｃｌｏｓｅシステムコール（ｓｅｌｅｃｔ（　）、ｐｏｌｌ（　）、およびｃｌｏｓｅ（　）それぞれ）をとり、アプリケーションには不可視な様式でこれらｓｅｌｅｃｔおよびｐｏｌｌシステムコールをｅｖｅｎｔｐｏｒｔコールに変えるように適合される。
　一実施形態では、シムライブラリ１５０は付録Ａおよび付録Ｂに見られるように２つの部分からなる。
【００３４】
　本実施形態では、付録Ａがｐｏｌｌシステムコールに関連し、付録Ｂがｓｅｌｅｃｔシステムコールに関連する。
　シムライブラリ１５０の各部分、すなわち付録Ａおよび付録Ｂはそれぞれ、ｐｏｌｌシステムコールおよびｓｅｌｅｃｔシステムコールの命令に関連するｃｌｏｓｅ（　）コールも含むことに留意する。
　ｅｖｅｎｔｐｏｒｔは、アプリケーションが動作可能なオペレーティングシステム内に含まれる代替イベント通知機構である。
　ｅｖｅｎｔｐｏｒｔに類似する機能を有する他の代替イベント通知機構も、本発明の実施形態の下で利用可能なことに留意する。
【００３５】
　一実施形態では、付録Ａに示し、特にその中のＳＥＣＴＩＯＮ　５に示すｐｏｌｌシステムコールを参照すると、本発明のシムライブラリ１５０は、イベントポート(eventport)に関連する情報を含むテーブル／ツリー構造を提供する。
　一実施形態では、アプリケーションからの一意のｐｏｌｌｆｄ（ｐｏｌｌファイル記述子）配列毎に１つのイベントポートファイル記述子がある。
【００３６】
　アプリケーションがｐｏｌｌ、たとえばｐｏｌｌ（　）を呼び出すと、関連するイベントポートが見つけられる。
　次いで、アプリケーションはアプリケーションのｐｏｌｌ（　）配列をウォーク（walk)する、すなわちスキャンする。
　付録ＡのＳＥＣＴＩＯＮ　３に示すように、ｐｏｌｌｆｄ配列内の各ファイル記述子が代替イベント通知機構、たとえばイベントポートに登録されたｆｄ（ファイル記述子）リストに照らし合わせてチェックされる。
【００３７】
　一実施形態では、ｆｄが、アプリケーションによってそのｆｄのｐｏｌｌｆｄ構造のイベントフィールドに配置されたイベントに予め登録されていた場合、ライブラリは次のｆｄに進む。
　一実施形態では、ｆｄが、アプリケーションが要求したイベントに予め登録されていなかった場合、ライブラリはそのｆｄを登録した後、次のｆｄに移る。
【００３８】
　一実施形態では、登録が失敗すると、シムライブラリ１５０内に含まれる関数が、アプリケーションによって提供される引数を使用して実際のｐｏｌｌ（　）システムコールにシームレスに戻る。
　一実施形態では、ｐｏｌｌｆｄ　ｓｔｒｕｃｔのイベントフィールドが望まれていないイベントタイプのものである場合、シムライブラリ１５０は、アプリケーションによって提供される引数を使用して実際のｐｏｌｌ（　）システムコールの呼び出しにシームレスに戻る。
【００３９】
　一実施形態では、オプションのしきい値および限度をセットすることができ、アプリケーションのｐｏｌｌまたはｓｅｌｅｃｔコールにおけるファイル記述子参照数が最小（しきい値）未満、または最大（限度）を越える場合には、付録ＡのＳＥＣＴＩＯＮ　１に示すように、アプリケーションによって提供される引数を使用して、ライブラリが実際のｐｏｌｌ（　）の呼び出しに戻る。
【００４０】
　一実施形態では、アプリケーションのｐｏｌｌｆｄ配列をスキャンし、アプリケーションの内部配列サイズを越えるファイル記述子がある場合、アプリケーションによって提供される引数を使用して、アプリケーションは実際のｐｏｌｌ（　）の呼び出しに戻る。
【００４１】
　一実施形態では、ｆｄ（ファイル記述子）はイベントポートに一旦登録されると、続くｐｏｌｌ（　）コールの一部ではない場合でも登録は即座に解除されることはない。
　一実施形態では、ｆｄを登録解除するオプションのしきい値をセットすることができ、所与のｐｏｌｌｆｄｓセットに対して、Ｎ回連続してｐｏｌｌ（　）コールの一部ではない所与のｆｄがある場合、そのｆｄは登録解除される。
【００４２】
　イベントポートから即座にはｆｄを登録解除しないことにより、ライブラリはイベントポートからイベントをｉｏｃｔｌ（入出力制御）検索するとき、アプリケーションにとって関心のないｆｄもいくつかあり得ることに留意する。
　アプリケーションのｆｄがイベントポートからｉｏｃｔｌによって戻されない場合、一実施形態では、イベントポートからイベントを続けてｉｏｃｔｌ検索する前に、一時的な停止があり得る。
　別の実施形態では、アプリケーションにとって関心がないｆｄにおいて関心を登録解除し、次いでイベントのｉｏｃｔｌ検索を試みるか、またはさらに別の実施形態では、付録ＡのＳＥＣＴＩＯＮ　４にまとめて示すように、実際のｐｏｌｌ（　）コールに戻る。
【００４３】
　付録Ｂに示すｓｅｌｅｃｔシステムコール、特にその中のＳＥＣＴＩＯＮ　５を参照すると、一実施形態では、本発明であるシムライブラリ１５０は、イベントポートに関連する情報を含むテーブル／ツリー構造を提供する。
　一実施形態では、アプリケーションからの一意のｆｄ＿ｓｅｔｓ配列毎に１つのイベントポートファイル記述子がある。
　アプリケーションがｆｄ＿ｓｅｔ配列アドレスを使用してｓｅｌｅｃｔ、たとえばｓｅｌｅｃｔ（　）を呼び出すと、関連するイベントポートが見つかる。
【００４４】
　次いで、アプリケーションはアプリケーションのｆｄ＿ｓｅｔ配列をウォークする、すなわちスキャンする。
　付録ＢのＳＥＣＴＩＯＮ　３に示すように、ｆｄ＿ｓｅｔ配列内の各ファイル記述子が代替イベント通知機構、たとえばイベントポートに登録されたｆｄ（ファイル記述子）リストに照らし合わせてチェックされる。
【００４５】
　一実施形態では、ｆｄが、アプリケーションによってそのｆｄのｆｄ＿ｓｅｔ構造のイベントフィールドに配置されたイベントに予め登録されていた場合、アプリケーションは次のｆｄに進む。
　一実施形態では、ｆｄが、アプリケーションが要求したイベントに予め登録されていなかった場合、アプリケーションはそのｆｄを登録した後、次のｆｄに移る。
【００４６】
　一実施形態では、登録が失敗すると、シムライブラリ１５０内に含まれる機能が、アプリケーションによって提供される引数を使用して実際のｓｅｌｅｃｔ（　）システムコールにシームレスに戻る。
　一実施形態では、ｆｄ＿ｓｅｔ　ｓｔｒｕｃｔのイベントフィールドが望まれていないイベントタイプのものである場合、シムライブラリ１５０は、アプリケーションによって提供される引数を使用して実際のｓｅｌｅｃｔ（　）システムコールの呼び出しにシームレスに戻る。
【００４７】
　一実施形態では、オプションのしきい値および限度をセットすることができ、登録されたファイル記述子数（ｎｆｄ）が最小（しきい値）未満、または最大（限度）を越える場合に、アプリケーションは、付録ＢのＳＥＣＴＩＯＮ　１に示すように、アプリケーションによって提供される引数を使用して、ライブラリが実際のｓｅｌｅｃｔ（　）コールの呼び出しに戻る。
【００４８】
　一実施形態では、アプリケーションのｆｄ＿ｓｅｔ配列をスキャンし、アプリケーションの内部配列サイズを越えるファイル記述子がある場合、アプリケーションによって提供される引数を使用して、アプリケーションは実際のｓｅｌｅｃｔ（　）の呼び出しに戻る。
【００４９】
　一実施形態では、ｆｄ（ファイル記述子）はイベントポートに一旦登録されると、続くｐｏｌｌ（　）コールの一部ではない場合でも登録は即座に解除されることはない。
　一実施形態では、ｆｄを登録解除するオプションのしきい値をセットすることができ、所与のｆｄ＿ｓｅｔセットに対して、Ｎ回連続してｓｅｌｅｃｔ（　）コールの一部ではない所与のｆｄがある場合、そのｆｄは登録解除される。
【００５０】
　イベントポートから即座にはｆｄを登録解除しないことにより、アプリケーションがイベントポートからイベントをｉｏｃｔｌ（入出力制御）検索するとき、アプリケーションにとって関心のないｆｄもいくつかあり得ることに留意する。
　アプリケーションのｆｄがイベントポートからｉｏｃｔｌによって戻されない場合、一実施形態では、イベントポートからイベントを続けてｉｏｃｔｌ検索する前に、一時的な停止があり得る。
　別の実施形態では、アプリケーションにとって関心がないｆｄの関心を登録解除し、次いでイベントのｉｏｃｔｌ検索を試みるか、またはさらに別の実施形態では、付録ＢのＳＥＣＴＩＯＮ　４にまとめて示すように、実際のｓｅｌｅｃｔ（　）に戻る。
【００５１】
　一実施形態では、アプリケーションによって呼び出される一意のｐｏｌｌｆｄ配列ベースおよびｆｄ＿ｓｅｔ配列ベース毎にｍｕｔｅｘ（相互排他）がある。
　ｐｏｌｌ（　）および／またはｓｅｌｅｃｔ（　）を呼び出す別個のスレッドがある場合、これらスレッドは、同じｐｏｌｌｆｄ配列および／またはｆｄ＿ｓｅｔ配列でｐｏｌｌ（　）および／またはｓｅｌｅｃｔ（　）を呼び出さないため、スレッドはｍｕｔｅｘ上では満足しない。
【００５２】
　一実施形態では、イベントポート自体のリストを保護するｍｕｔｅｘがある。
　一実施形態では、「グローバル」ｍｕｔｅｘがロックされ、次いで関連するエントリが見つけられる。
　そのｍｕｔｅｘがアンロックされ、次いでグローバルｍｕｔｅｘがアンロックされ、それによって他のスレッドがそれぞれに関連する機能および／またはタスクを実行できるようにする。
　別の実施形態では、ｍｕｔｅｘおよびグローバルｍｕｔｅｘが組み合わせられて１つの大きなグローバルｍｕｔｅｘになることに留意する。
【００５３】
　付録Ａおよび付録ＢのＳＥＣＴＩＯＮ　６に示すｃｌｏｓｅシステムコール、たとえばｃｌｏｓｅ（　）を参照すると、アプリケーションがｃｌｏｓｅ（　）を呼び出すと、本発明の一実施形態では、シムライブラリ１５０内に含まれる機能もまたｃｌｏｓｅコールをインタセプトする。
　アプリケーションは、ｃｌｏｓｅを呼び出す場合、グローバルｍｕｔｅｘを取得し、次いでｓｈｉｍ＿ｃｏｎｔｅｘｔｓのスキャンを開始し、割り当てられた各コンテキスト中のそのｆｄ（ファイル記述子）のｆｄ＿ｃｏｎｔｅｘｔエントリを消去する。
　ライブラリは、ｆｄをイベントポートから登録解除する必要はなく、これは、アプリケーションが実際のｃｌｏｓｅ（　）を呼び出すときに自動的に行われる。
【００５４】
　続けて、アプリケーションが再びｆｄを取得し、ｆｄを使用してｐｏｌｌｆｄ構造の１つにおけるｐｏｌｌ（　）を呼び出す場合、かつ／またはアプリケーションが再びｆｄを取得し、ｆｄを使用してｆｄ＿ｓｅｔ構造の１つにおけるｓｅｌｅｃｔ（　）を呼び出す場合、ｐｏｌｌｆｄ構造およびｆｄ＿ｓｅｔ構造は適切なシムコンテキストに再登録される。
【００５５】
　図３は、ソフトウェアアプリケーションにおいて、再コンパイルすることなく、選択されたシステムコール、たとえばｓｅｌｅｃｔシステムコールおよびｐｏｌｌシステムコールのパフォーマンスを向上させる方法を提供する本発明の一実施形態により行われるステップのフローチャート３００である。
　フローチャート３００は、一実施形態では、コンピュータが読み取り可能かつ実行可能な命令の制御下にあるプロセッサおよび電子コンポーネントによって実行される本発明のプロセスを含む。
【００５６】
　コンピュータが読み取り可能かつ実行可能な命令は、たとえば、図１のコンピュータ使用可能揮発性メモリ２０２、および／またはコンピュータ使用可能不揮発性メモリ２０３、および／またはデータ記憶装置２０４等、データ記憶機構にある。
　しかし、コンピュータ読み取り可能かつ実行可能な命令は、あらゆるタイプのコンピュータ可読媒体に存在してよい。
【００５７】
　フローチャート３００には特定のステップが開示されるが、かかるステップは例示的なものである。
　すなわち、本発明は、様々な他のステップまたは図３に記すステップを変形したものの実行に適している。
　本発明の範囲内で、フローチャート３００のステップは、ソフトウェア、ハードウェア、またはソフトウェアとハードウェアとの任意の組み合わせで実行してよいことを認められたい。
【００５８】
　図３のステップ３０２において、本発明の一実施形態では、ライブラリ、たとえば図１、図２、付録Ａ、および付録Ｂのシムライブラリ１５０（ｓｈｉｍ＿ｌｉｂ）に、ソフトウェアアプリケーションにおける環境変数の値として名前が割り当てられる。
　一実施形態では、シムライブラリ１５０は、アプリケーション、たとえばインターネットアプリケーションの動作中にアプリケーションによって行われるシステムコールを置き換えるソフトウェアコードを含む。
【００５９】
　図３のステップ３０４において、ソフトウェアアプリケーションが起動される。
　アプリケーションを起動する方法としては、コマンドラインインタフェースまたはグラフィカルユーザインタフェースを使用して、ソフトウェアアプリケーションに関連する実行可能ファイルを呼び出す方法を含むがこれに限定されない多くの既知の方法がある。
　ソフトウェアアプリケーションが起動すると、ソフトウェアアプリケーションに関連するローダが呼び出される。
【００６０】
　図３のステップ３０６において、本発明の一実施形態では、ローダが、環境変数において指定された名前を有するライブラリ、たとえば図２のシムライブラリ１５０をソフトウェアアプリケーションにプレロードする。
　一実施形態では、ソフトウェアアプリケーションが動作可能なオペレーティングシステムは、プレロード機能を包含しており、したがってプレロード機能を元々備えている。
　別の実施形態では、ソフトウェアコードの形態のパッチをオペレーティングシステムに追加して、プレロード機能を提供することができる。
【００６１】
　図３のステップ３０８において、ソフトウェアアプリケーションを起動した後、ソフトウェアアプリケーション、本例ではインターネットアプリケーションが複数のソケットを開き、また開かれたソケットそれぞれに関連する複数のファイル記述子を作成する。
　各ファイル記述子は、関連する関心ソケットに関する関心イベントに関連する。
　これらファイル記述子は、付録Ａおよび付録ＢのＳＥＣＴＩＯＮ　３に示し、ソフトウェアアプリケーションが動作可能なオペレーティングシステム内に機能が含まれた代替イベント通知機構に登録される。
【００６２】
　さらにステップ３０８を参照すると、一実施形態では、代替イベント通知機構はイベントポートである。
　一実施形態では、イベントポートはオペレーティングシステムに固有であり、これは機能がオペレーティングシステム内に含まれていることを意味する。
　別の実施形態では、パッチをオペレーティングシステムに適用して、元々はイベントポートを備えるように構成されていないオペレーティングシステムにイベントポート機能を提供することもできる。
　略あらゆる代替イベント通知機構が、本発明の実施形態によって提供される機能から恩恵を受けることができることに留意する。
【００６３】
　さらに図３を参照すると、一実施形態では、ソフトウェアアプリケーションが動作可能なオペレーティングシステムは、Ｕｎｉｘ（登録商標）、Ｌｉｎｕｘ、Ａｐｐｌｅ　ＯＳ　Ｘ（Ｕｎｉｘ（登録商標）由来）等を含むがこれらに限定されないＵｎｉｘ（登録商標）タイプのオペレーティングシステムである。
　他のオペレーティングシステムも、プレロード機能および代替イベント通知機構機能を備えて構成される場合には、本発明の実施形態によって提供される機能から恩恵を受けることができることに留意する。
【００６４】
　図３のステップ３１０において、ソフトウェアアプリケーション、たとえばインターネットアプリケーションは、システムコール、たとえばｓｅｌｅｃｔシステムコールおよび／またはｐｏｌｌシステムコールを行うときに、代替イベント通知機構、たとえばイベントポートを呼び出すように転向される。
　イベントポートが呼び出されると、シムライブラリ１５０が実施され、ｓｅｌｅｃｔシステムコールおよびｐｏｌｌシステムコールを含むがこれらに限定されないシステムコールが置き換えられる。
【００６５】
　図３のステップ３１２において、関心ソケットに対する関心イベントをイベントポートに登録することにより、そのように登録されたイベントを有するソケットのみが、関心イベントについてチェックされる。
　都合のよいことに、これにより、スキャンされるソケット数が大幅に低減し、したがってＣＰＵの使用量が少なくなり、費やされる時間が短くなる。
【００６６】
　図４は、ソフトウェアアプリケーションにおいて、再コンパイルすることなく、選択されたシステムコール、たとえばｓｅｌｅｃｔシステムコールおよびｐｏｌｌシステムコールのパフォーマンスを向上させる方法を提供する本発明の別の実施形態により行われるステップのフローチャート４００である。
　フローチャート４００は、一実施形態では、コンピュータが読み取り可能かつ実行可能な命令の制御下にあるプロセッサおよび電子コンポーネントによって実行される本発明のプロセスを含む。
【００６７】
　コンピュータが読み取り可能かつ実行可能な命令は、たとえば、図２のコンピュータ使用可能揮発性メモリ２０２、および／またはコンピュータ使用可能不揮発性メモリ２０３、および／またはデータ記憶装置２０４等、データ記憶機構にある。
　しかし、コンピュータ読み取り可能かつ実行可能な命令は、あらゆるタイプのコンピュータ可読媒体に存在してよい。
【００６８】
　フローチャート４００には特定のステップが開示されるが、かかるステップは例示的なものである。
　すなわち、本発明は、様々な他のステップまたは図４に記すステップを変形したものの実行に適している。本実施形態の範囲内で、フローチャート４００のステップは、ソフトウェア、ハードウェア、またはソフトウェアとハードウェアとの任意の組み合わせで実行してよいことを認められたい。
【００６９】
　図４のステップ４０２において、本発明の一実施形態では、ライブラリ、たとえば付録Ａ、および付録Ｂのシムライブラリ１５０（ｓｈｉｍ＿ｌｉｂ）に、ソフトウェアアプリケーションにおける環境変数の値として名前が割り当てられる。
　一実施形態では、シムライブラリ１５０は、アプリケーション、たとえばインターネットアプリケーションの動作中にアプリケーションによって行われるシステムコールを置き換えるソフトウェアコードを含む。
【００７０】
　図４のステップ４０４において、ソフトウェアアプリケーションが起動される。
　アプリケーションを起動する方法としては、コマンドラインインタフェースまたはグラフィカルユーザインタフェースを使用して、ソフトウェアアプリケーションに関連する実行可能ファイルを呼び出す方法を含むがこれに限定されない多くの既知の方法がある。
　ソフトウェアアプリケーションが起動すると、ソフトウェアアプリケーションに関連するローダが呼び出される。
【００７１】
　一実施形態では、ソフトウェアアプリケーションが動作可能なオペレーティングシステムは、Ｕｎｉｘ（登録商標）、Ｌｉｎｕｘ、Ａｐｐｌｅ　ＯＳ　Ｘ（Ｕｎｉｘ（登録商標）由来）等を含むがこれらに限定されないＵｎｉｘ（登録商標）タイプのオペレーティングシステムである。
　他のオペレーティングシステムも、プレロード機能および代替イベント通知機構機能を備えて構成される場合には、本発明の実施形態によって提供される機能から恩恵を受けることができることに留意する。
【００７２】
　図４のステップ４０６において、本発明の一実施形態では、ローダが環境変数、たとえば図２のシムライブラリ１５０をソフトウェアアプリケーションにプレロードする。
　一実施形態では、ソフトウェアアプリケーションが動作可能なオペレーティングシステムは、プレロード機能を包含しており、したがってプレロード機能を元々備えている。
　別の実施形態では、ソフトウェアコードの形態のパッチをオペレーティングシステムに追加して、プレロード機能を提供することができる。
【００７３】
　図４のステップ４０８において、本発明の一実施形態では、複数のファイル記述子が、代替イベント通知機構、たとえば付録Ａおよび付録ＢのＳＥＣＴＩＯＮ　３に示すイベントポートに登録される。
　ファイル記述子は、ソケットがアプリケーションによって開かれるときにオペレーティングシステムによって作成される。
　複数のファイル記述子はそれぞれ、関連ソケットに関する関心イベントに関連する。
【００７４】
　図４のステップ４１０において、本発明の一実施形態では、付録Ａおよび付録ＢのＳＥＣＴＩＯＮ　１に示すように、イベントポートを呼び出すには、規定されたファイル記述子最小数分がイベントポートに登録されている必要がある。
　一実施形態では、登録ファイル記述子最小数はファイル記述子１２８個である。
　別の実施形態では、代替イベント通知機構の呼び出しに、より大きなまたは小さな登録ファイル記述数を指定することができる。
【００７５】
　図４のステップ４１２において、本発明の一実施形態では、ステップ４１０において上に述べた代替イベント通知機構を呼び出すために必要な規定の登録ファイル記述子数により、その最小数を越えるまで、イベントポートは呼び出されない。
　これは、アプリケーションがｐｏｌｌまたはｓｅｌｅｃｔシステムコールを行うと、実際のｐｏｌｌおよびｓｅｌｅｃｔコールが行われることを意味する。
　しかし、最小数を一旦越えると、代替イベント通知機構が呼び出される。
【００７６】
　図４のステップ４１４において、ソフトウェアアプリケーション、たとえばインターネットアプリケーションは、システムコール、たとえばｓｅｌｅｃｔシステムコールおよび／またはｐｏｌｌシステムコールを行うときに、代替イベント通知機構、たとえばｅｖｅｎｔｐｏｒｔを呼び出すように指示し直される。
　ｅｖｅｎｔｐｏｒｔｓが呼び出されると、シムライブラリ１５０が実施され、ｓｅｌｅｃｔシステムコールおよびｐｏｌｌシステムコールを含むがこれらに限定されないシステムコールが置き換えられる。
【００７７】
　図４のステップ４１６において、関心ソケットに対する関心イベントをｅｖｅｎｔｐｏｒｔｓに登録することにより、そのように登録されたイベントを有するソケットのみが、関心イベントについてチェックされる。
　都合のよいことに、これにより、スキャンされるソケット数が大幅に低減し、したがってＣＰＵの使用量が少なくなり、費やされる時間が短くなる。
【００７８】
　本発明の実際の実施態様では、シムライブラリ１５０は、旅行業界の企業向けのアプリケーションに適合される。
　アプリケーションはｐｏｌｌ（　）を使用するように既に書かれており、したがって既にイベントポートに必要なセマンティクスおよびシンタックスの多くを備えて構成されている。
【００７９】
　このアプリケーションは、ｐｏｌｌ（　）を呼び出す３つのスレッド、ｒｅｃｖ（　）を呼び出すさらに他の３つの中間スレッド、およびｗｒｉｔｅｖ（　）を呼び出す３つのスレッドにコネクションを分散させる。
　したがって、以下の表中のコネクション数が１０００を示す場合、これは、ｐｏｌｌ（　）への各呼び出しがおおよそ３３３個のコネクションに対するものであったことを意味する。
【００８０】
　このアプリケーションは、必要な場合以外は書き込みにｐｏｌｌ（　）しなかった。
　また、アプリケーションの振る舞いは書き込みの場合にはｐｏｌｌ（　）を決して必要としないようなものであり、そしてまたこれが最もよい実装であった。
　ネットワーク環境、たとえば図１のネットワーク環境１００において実施される試験中のコンピュータネットワークシステム、たとえばコンピュータシステム１００は、イベントポートおよび種々雑多な他のパッチがインストールされたＵｎｉｘ（登録商標）環境で動作するマルチノードネットワーク環境（図１のネットワーク１００）におけるマルチプロセッサコンピュータシステムであった。
【００８１】
　このコンピュータネットワークシステムのクライアント「側」には、５つのマルチプロセッサコンピュータシステム、たとえば図２のコンピュータシステム２００があってリモートクライアントをシミュレートし、このシステムのサーバ「側」には、別の５つのマルチプロセッサコンピュータシステムがあってバックエンドサーバをシミュレートした。
　本例の測定セットでは、ＳＵＴ（被試験システム）のＣＰＵ利用率は常に１００％であるため、測定単位としてトランザクション／秒を示す。
　この状況１でのコネクションは以下のようなものであることに留意する。
【００８２】
【表１】
2004070948.tif 000003
【００８３】
　上記表１は、イベントポートによるパフォーマンスの増大はかなり顕著であり得ることを示す。
　「ｐｏｌｌ（　）」と書かれた列は、ｐｏｌｌ（　）を使用するように書かれた場合のアプリケーションのパフォーマンスである。
　「イベントポートシムライブラリ」と標示された列は、一実施形態では、アプリケーションがシムライブラリ１５０を使用してロードされた場合のパフォーマンスである。
【００８４】
　このライブラリは、ＬＤ＿ＰＲＥＬＯＡＤ機能を介して実行中のアプリケーションイメージにプレロードされ、アプリケーションのｐｏｌｌ（　）への呼び出しをインタセプトし、Ｅｖｅｎｔｐｏｒｔコールに向ける。
　示すように、これが成功し、パフォーマンスが大幅に向上する。
【００８５】
　したがって、ライブラリ、たとえばシムライブラリ１５０をシステムコールの代替として呼び出すことにより、アプリケーションの再コンパイルなしで、アプリケーションの選択されたシステムコールのパフォーマンスを向上させる方法を提供する本発明の実施形態について描写した。
　さらに、シムライブラリ１５０が代替イベント通知機構に登録されたソケットのみを調べることにより、ＣＰＵ使用量の大幅な低減が実現される。
　さらなる利点は、ソケットがさらに追加される場合、アプリケーション自体ではなくシムライブラリが記録されることである。
【００８６】
　本発明の特定の実施形態についての上記説明は、例示および説明を目的として提示された。
　網羅的、すなわち本発明を開示された厳密な形態に限定する意図はなく、上記教示に照らして多くの変更および変形が可能である。
　実施形態は、当業者が、意図する特定の用途に適した各種変更を行って本発明および各種実施形態を最もよく利用することができるように、本発明の原理およびその実際の応用を最良に説明するために選択され説明されたものである。
　本発明の範囲は、本明細書中の併記特許請求項およびその等価物によって規定されるものと意図される。
【００８７】
　［付録Ａ］
　注：以下のリストにおいては、出願処理の都合上、半角の”＜”および”＞”は、全角に変換されている。
/* cc +z -D_REENTRANT ＜archstuff＞ -c poll_shim.c */
/* ld -b -o libpollshim.sl poll_shim.o -lpthread */
#include ＜stdio.h＞
#include ＜stdlib.h＞
#include ＜unistd.h＞
#include ＜stropts.h＞
#include ＜fcntl.h＞
#include ＜devpoll.h＞
/* poll.h is included by devpoll.h, but this shouldn't hurt（poll.hはdevpoll.hに含まれるが、これは支障ない） */
#include ＜poll.h＞
#include ＜dlfcn.h＞
#include ＜pthread.h＞
static const char poll_shim_version[] = \
"@(#)poll_shim.c ";
【００８８】
SECTION 1:
#define POLL_SHIM_MAX_CONTEXTS   16
#define POLL_SHIM_NFDS_LIMIT             20000
#define POLL_SHIM_NFDS_THRESHOLD 128
#define POLL_SHIM_DUMP_STATS     1024
#define POLL_SHIM_NFDS_DUP_COUNT INT_MAX
static int poll_shim_nfds_threshold = POLL_SHIM_NFDS_THRESHOLD;
static int poll_shim_nfds_dup_count = POLL_SHIM_NFDS_DUP_COUNT;
static int poll_shim_nfds_limit = POLL_SHIM_NFDS_LIMIT;
/* For tracking things associated with a given FD（所与のFDに関連するものを追跡するため） */
struct shim_fd_context {
struct pollfd *users_pollfd_ptr; 
/* ptr to this FD in the users pollfd array.  For quickly finding the entry in the users pollfd array after the eventport ioctl returns（users pollfd配列中のこのＦＤへのptr。eventport ioctlリターン後のusers pollfd配列中のエントリを素早く見つけるため） */   
unsigned int  generation;  
/* The last time this FD appeared in the users pollfd array.  For detecting duplicate fds in the user's pollfd array.  If an entry with the same generation number as this generation of call is encountered, it means that the user had the same FD in the pollfd array at least twice and we will punt to the real poll() call.  Subsequently, it will also be used to decide when to unregister an FD from the eventport（users pollfd配列においてこのFDが最後に現れるとき。users pollfd配列中の複製fdsを検出するため。このコール生成と同じ生成番号のエントリに直面する場合、これは、ユーザがpollfd配列中に同じFDを少なくとも２度有したことを意味し、実際のpoll( )コールに戻る。続けて、eventportからFDを登録解除すべきときを決定するためにも用いられる） */
int registered;             
/* Is this FD already registered in the eventport?（このFDはeventportに登録済か？） */
short events;
/* For what events have we registered this FD in the eventport?  Initially this should either be zero to mean nothing registered, or flags to indicate we've registered for interest in reading, but not writing, at normal priorities.（どのイベントについて、このFDをeventportに登録したのか？最初は、これは何も登録されていないことを意味する０であるか、あるいは通常の優先度で書き込みではなく読み出しに注目して登録したことを示すフラグであるべきである） */
};
/*  The table of contexts that will be tracked（追跡するコンテキストのテーブル） */
struct shim_context {
void *users_pollfd_base_ptr;
/* The mutex used to protect this specific shim_context （この特定のshim_contextを保護するために使用されるmutex）*/
pthread_mutex_t shim_context_mutex;
unsigned int      generation;  
/* How many times the user called poll() with the same pollfd pointer（同じpollfdポインタでユーザがpoll( )を呼び出した回数） */  
int   eventport;  
/* File descriptor for the event port.（eventportのファイル記述子） */ 
int   nfds;  
/* Count of fd's registered to the eventport （eventportに登録されたfdのカウント）*/
/*  The list of "state" info the shim maintains on FDs that may/may not be registered with the eventport.  This can be a sparse array.  We are trading memory for time so we can use FD values as indices.（eventportに登録されている\いないかもしれないFDについてshimが保持する「状態」情報のリスト。これは疎な配列であってよい。時間のためにメモリを犠牲にしているため(We are trading memory for time)、FD値をインデックスとして使用できる） */
struct shim_fd_context shim_fd_contexts[POLL_SHIM_NFDS_LIMIT];
};
struct shim_context poll_shim_contexts[POLL_SHIM_MAX_CONTEXTS];
/*  Protecting these statistics is not a concern, since all that is ever done is to increment them and runtime decisions are not made based on these statistics.（これら統計の保護は重要ではない。理由は、行ったことといえばこれらの統計の増分だけであり、実行時判断はこれら統計に基づいて行われないためである） */
static int      poll_calls=0;         
/* Number of times application calls poll （アプリケーションがpollを呼び出した回数）*/
static int      eventport_calls=0;    
/* Number of times eventport called（eventportが呼び出された回数） */
static int      evp_returned_fds=0;  
/* Number of times an eventport call returned fd's of interest to user（eventportコールがユーザ関心fdを戻した回数） */
static int      realpoll_calls=0;     
/* Number of times poll called（pollが呼び出された回数） */
static int      eventport_registers=0; 
/* Number of fd's registered（登録されたfdの数） */
static int      eventport_deregisters=0; 
/* Number of fd's deregistered（登録解除されたfd） */
static int      user_dup_fds=0;  
/* Number of times same fd appeared twice in fds array（fds配列中で同じfdが２度出現した回数） */
static int      eventport_regfail=0; 
/* Number of times an eventport registration failed（eventport登録が失敗した回数） */
static int      eventport_deregfail=0; 
/* Number of times an eventport registration failed（eventport登録解除が失敗した回数） */
static int      event_not_pollin=0; 
/* Number of times punting because user wanted something other than POLLIN（ユーザがＰＯＬＬＩＮ以外を求めたことにより復帰した回数） */  
static int      nfds_below_threshold=0; 
/* Number of times punting because user was asking for too few fds to be polled.（ユーザがポーリングを要求するfdsが少なすぎることにより復帰した回数） */
static int      nfds_above_limit=0;  
/* Number of times punting to poll because user was asking for more fds than configured to track.（ユーザの要求するfdsが追跡するように構成されたfdsよりも多いことによりポーリングに復帰した回数） */
static int      close_calls = 0; 
/* Number of calls to close() intercepted by the shim（shimがインタセプトしたclose( )への呼び出し数） */
static int      close_evp_walks = 0; 
/* Number of intercepted close calls which walked the shim contexts（shim contextをウォークしたインタセプトcloseコール数） */
static int      reg_walk_avoids = 0; 
/* Number of times registration avoided, by virtue of the heuristic.（ヒューリスティックにより登録が回避された回数） */
static int      reg_heuristic_resets = 0; 
/* Number of times resetting the registration walk avoidance heuristic（登録ウォーク回避ヒューリスティックをリセットした回数） */
static int      reg_heuristic_resets1 = 0;
static int      reg_heuristic_resets2 = 0;
static int      reg_heuristic_resets3 = 0;
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
static pthread_mutex_t poll_shim_global_mutex = PTHREAD_MUTEX_INITIALIZER;
int     *(*real_poll)(struct pollfd fds[], nfds_t nfds, int timeout) = NULL;
int     *(*real_close)(int fildes) = NULL;
void
poll_shim_stats() 
{
fprintf(stderr,"poll_shim statistics:\n");
fprintf(stderr,"\t%d calls to poll() by user\n",poll_calls);
fprintf(stderr,"\t%d calls to eventport by shim\n",eventport_calls);
fprintf(stderr,"\t%d evp calls returned interesting fds\n",evp_returned_fds);
fprintf(stderr,"\t%d calls to poll() by shim\n",realpoll_calls);
fprintf(stderr,"\t%d fds registered by shim\n",eventport_registers);
fprintf(stderr,"\t%d fds deregistered by shim\n",eventport_deregisters);
fprintf(stderr,"\t%d calls with fd listed twice in fds \n",user_dup_fds);
fprintf(stderr,"\t%d eventport registration failures\n",eventport_regfail);
fprintf(stderr,"\t%d calls with an event other than POLLIN|POLLRDNORM\n",event_not_pollin);
fprintf(stderr,"\t%d calls with nfds ＜ threshold (%d)\n",
nfds_below_threshold,
poll_shim_nfds_threshold);
fprintf(stderr,"\t%d calls with nfds ＞ limit (%d)\n",
nfds_above_limit,
poll_shim_nfds_limit);
fprintf(stderr,"\t%d calls to close\n",close_calls);
fprintf(stderr,"\t%d calls to close walked shim contexts\n",close_evp_walks);
fprintf(stderr,"\t%d registration walks avoided by heuristic\n",
reg_walk_avoids); 
fprintf(stderr,"\t%d registration avoidance heuristic resets\n",
reg_heuristic_resets);
fprintf(stderr,"\t\t%d location 1\n",reg_heuristic_resets1);
fprintf(stderr,"\t\t%d location 2\n",reg_heuristic_resets2);
fprintf(stderr,"\t\t%d location 3\n",reg_heuristic_resets3);
fflush(stderr);
}
void
poll_shim_initialize() {
char *threshold_string;
int ret;
if (real_poll == NULL) {
fprintf(stderr,
" ＞＞＞WARNING! POLL() to EVP SHIM ACTIVATED＜＜＜ \n");
fprintf(stderr,"%s\n",poll_shim_version);
atexit(poll_shim_stats);
} 
else {
fprintf(stderr,"someone we had pthread_shim_initialize called twice?\n");
return;
}
/* dlsym() to get entry point to real poll for when it is necessary.  Just use RTLD_NEXT magic "handle" and presume that LD_PRELOADed is loaded into the executable, so poll() should be found without having to dlopen() anything, as implied from the dlopen() manpage.（必要な場合に実際のpollへのエントリポイントを取得するdlsym( )。RTLD_NEXTマジック「ハンドル」を使用し、LD_PRELOADされたものが実行可能ファイル（executable)にロードされたものと想定すると、poll( )は、dlopen( )マンページから示されるように、何もdlopen( )する必要なく見つかるはずである） */
real_poll = 
(int * (*) (struct pollfd fds[], 
nfds_t nfds, 
int timeout))dlsym (RTLD_NEXT, "poll") ;
if (real_poll == NULL)
{
fprintf(stderr,"unable to dlsym poll: %s\n",dlerror());
fprintf(stderr,"consider undoing the LD_PRELOAD of the poll shim\n");
exit (0) ;
}
real_close =  (int * (*) (int fildes))dlsym (RTLD_NEXT, "close") ;
if (real_close == NULL)
{
fprintf(stderr,"unable to dlsym close: %s\n",dlerror());
fprintf(stderr,"consider undoing the LD_PRELOAD of the poll shim\n");
exit (0) ;
}
if ((threshold_string = getenv("EVP_SHIM_NFDS_THRESHOLD")) !=
NULL) {
/* User wants to set value for nfsd that will trigger using eventport.（ユーザが、eventportの使用をトリガするnfsdの値を設定したい） */
if ((ret = sscanf(threshold_string,
"%d",
&poll_shim_nfds_threshold)) != 1) {
/* Error in reading threshold value from the environment, use the default（環境からのしきい値読み出しエラー、デフォルトを使用） */
poll_shim_nfds_threshold = POLL_SHIM_NFDS_THRESHOLD;
}
}
if ((threshold_string = getenv("EVP_SHIM_NFDS_DUP_COUNT")) !=
NULL) {
/* The user wants to set value for the number of times nfsd is the same that will trigger not bothering to walk the pollfd array and assume that everything is already registered.（ユーザは、わざわざpollfd配列をウォークすることがないnfsdが同じ回数の値を設定し、すべて登録済であるものと想定したい） */ 
if ((ret = sscanf(threshold_string,
"%d",
&poll_shim_nfds_dup_count)) !=1) {
/* Error in reading dup_count value from the environment, use the default（環境からのdup_count値読み出しエラー、デフォルトを使用） */
poll_shim_nfds_dup_count = POLL_SHIM_NFDS_DUP_COUNT;
}
}
fprintf(stderr,"Eventport shim settings: \n");
fprintf(stderr,"\t use evp when nfds ＞ %d\n",
poll_shim_nfds_threshold);
fprintf(stderr,"\t use evp when nfds ＜ %d\n",
poll_shim_nfds_limit);
fprintf(stderr,"\t use ＜= %d evp contexts\n",
poll_shim_nfds_limit);
fprintf(stderr,"\t don't regwalk when nfds same %d times\n",
poll_shim_nfds_dup_count);
}
【００８９】
SECTION 2:
/*  This routine is only called during initialization of a poll_shim_context, for setting initial values of poll_fd_context struct to desired values.  It is here as a separate call only to satisfy those who insist on pure CS 101 coding styles.  Because initialization should be rare, the call overhead is acceptable.（このルーチンは、poll_shim_contextの初期化中にのみ呼び出され、poll_fd_context structの初期値を所望の値に設定する。ここでは、純粋なＣＳ１０１符号化スタイルを主張する者のみを満足させる別個のコールである。初期化は稀であるはずのため、コールオーバヘッドを許容することができる） */
void
poll_fd_context_initialize(struct shim_fd_context fd_contexts[]) {
int i;
/* By virtue of this being a contiguous array and everything is being set to zero/NULL, could just call memset().（これは連続配列であり、すべてが０／ヌルに設定されるため、memset( )を呼び出すだけでよい） */
for (i=0; i ＜ POLL_SHIM_NFDS_LIMIT; i++) {
fd_contexts[i].users_pollfd_ptr = NULL;
fd_contexts[i].generation = 0;
fd_contexts[i].events = 0;
}
}
/*  This routine will initialize a context for a given context_id (a users pollfd array address).  It presumes that the poll_shim_global_mutex is locked and unlocked by the caller.  Generation counter is initialized, eventport filedescriptor is opened, and context-specific mutex is initialized.  Set the users_pollfd-base_ptr to the context_id and return.  If error occurs, cleanup and return a failure message and the caller can decide what to do, e.g., fallback on the "real" poll call.（このルーチンは、所与のcontext_id（users pollfd配列アドレス）のコンテキストを初期化する。poll_shim_global_mutexは呼び出し元によりロックおよびアンロックされるものと想定する。
　生成カウンタを初期化し、eventportファイル記述子を開き、コンテキスト固有mutexを初期化する。users_pollfd-base_ptrをcontext_idにセットし、戻す。
　エラーが発生する場合にはクリーンアップし、失敗メッセージを戻し、呼び出し元は何をすべきか、たとえば「実際の」pollコールにフォールバックすると判断することができる） */
int
poll_shim_context_initialize(struct shim_context *context, 
void *context_id) {
int ret;
pthread_mutexattr_t attr;
if ((ret = pthread_mutexattr_init(&attr)) == 0) {
/* Keep going（続行） */
if ((ret = pthread_mutex_init(&(context-＞shim_context_mutex),
&attr)) == 0) {
/* Keep going（続行） */
if ((context-＞eventport = open("/dev/poll", O_RDWR)) ＞= 0) {
/* Keep going, none of the rest of the stuff can "fail"（続行、残りはいずれも「失敗」しえない） */
poll_fd_context_initialize(context-＞shim_fd_contexts);
context-＞generation = 0;
context-＞users_pollfd_base_ptr = context_id;
return(0);
}
else {
/* The open of /dev/poll failed（/dev/pollのオープン失敗） */
}
}
else {
/* The pthread_mutex_init failed（pthread_mutex_init失敗） */
}
}
else {
/* The pthread_mutexattr_init failed（pthread_mutexattr_init失敗） */
}
return(1);    
}
/*  Returns a pointer to poll_shim_context struct associated with  context_id.  
If context_id is not found and there is room in the context store, a context is initialized.  If the context is not found, and there is no room in the context store, NULL is returned.  Upon return of a non-NULL pointer, the mutex for the poll_shim_context will be locked.  This routine will lock the global_shim_mutex while it performs the search and also while a newly allocated context is initialized.  This should be OK so long as stuff like opening an event port  does not take too much time.  The routine will unlock the global_shim_mutex before it returns.  
If any unrecoverable errors are encountered, this routine will clean up as best it can and will return a value of NULL.  At that point it will be up to the caller to decide whether or not it wishes to abort/exit or simply fallback to the "real" poll() call.
（ポインタをcontext_idに関連するpoll_shim_context structに戻す。
　context_idが見つからず、かつコンテキスト格納場所に空きがある場合、コンテキストは初期化される。
　コンテキストが見つからず、かつコンテキスト格納場所に空きがない場合、ヌルが戻される。
　非ヌルポインタが戻されると、poll_shim_contextのmutexがロックされる。
　このルーチンは、探索を行う間、また新たに割り当てられたコンテキストが初期化される間、global_shim_mutexをロックする。
　これは、eventportオープンなどにかかる時間がそれほど長くない限り、支障ないはずである。このルーチンは、global_shim_mutexを戻す前にアンロックする。
　なんらかの回復不可能なエラーに直面した場合、このルーチンはできる限りクリーンアップし、ヌル値を戻す。
　この時点で中止\終了したいか、または単に「実際の」poll( )コールにフォールバックしたいか否かは、呼び出し元次第である。*\
struct shim_context *
poll_shim_find_context(void *context_id) {
int i;
int ret;
struct shim_context *found_context = NULL;
if ((ret = pthread_mutex_lock(&poll_shim_global_mutex)) != 0) {
/*Error, time to punt.（エラー、戻る（time to punt）） */
fprintf(stderr,
"pollshim: unable to lock poll_shim_global_mutex, errno %d, exiting!\n", ret);
fflush(stderr);
exit(-1);
}
/*  We only initialize contexts, we never "free" them, so the unallocated entries in the array (users_pollfd_base_ptr == NULL) should always be at the end of the array, and if we get to one, it means there is going to be no match with an existing entry.（コンテキストを初期化するだけであり、決して「解放」しないため、配列中の割り当てられていないエントリ（users_pollfd_base ptr==NULL)は常に配列の末尾にあるはずであり、これに達すると、これは既存のエントリとのマッチングがなくなることを意味する） */
i = 0;
while ((i ＜ POLL_SHIM_MAX_CONTEXTS) && 
(found_context == NULL)) {
if (poll_shim_contexts[i].users_pollfd_base_ptr == NULL) {
/* Should usually not have a NULL user_pollfd_base_ptr before the match to the supplied context_id is found, so finding a NULL means that there is no context for that context_id.（通常、与えられたcontext_idとのマッチングが見つかる前にヌルのuser_pollfd_base_ptrを有することはまずないため、ヌルが見つかるということは、そのcontext_idにコンテキストがないことを意味する） */
if ((ret = 
poll_shim_context_initialize(&(poll_shim_contexts[i]),
context_id)) == 0) {
/* All was well（すべて順調） */
found_context = &(poll_shim_contexts[i]);
}
else {
/* The call to poll_shim_context_initialize failed（poll_shim_context_initializeへの呼び出し失敗） */
}
/*  At this point, we either found and initialized a new context, or that failed. there is no point in continuing in the while loop, because if the init failure were transient we might try to initialize the next NULL entry and then actually have a NULL entry  separating valid entries. That would be bad.（この時点で、新しいコンテキストを見つけて初期化するか、あるいはそれに失敗する。init失敗が一過性のものである場合、次のヌルエントリの初期化を試み、有効なエントリを隔てるヌルエントリが実際に生じてしまうことがあるため、whileループを続けることに意味はない。続けるのはよくないであろう） */ 
break;
}
else {
/* The users_poll_fd_base_ptr was not null.  Does it perhaps match the context_id for which we are looking?（users_poll_fd_base_ptrはヌルではなかった。ひょっとすると探しているcontext_idにマッチングするか？） */
if (poll_shim_contexts[i].users_pollfd_base_ptr == context_id) {
/* We have a match（マッチング） */
found_context = &(poll_shim_contexts[i]);
}
else {
/* There was no match, try the next entry（マッチングしなかった。次のエントリを試す） */
i++;
}
}
}
/* Once we get to this point, either we have a valid non-NULL shim_context, or it is NULL.  Time to unlock the global mutex and return.  However, if our context is non-NULL, we have to remember to lock the context mutex first.（この時点に達すると、有効な非ヌルのshim_contextを得ているか、あるいはshim_contextがヌルである。グローバルmutexをアンロックし、戻るべきときである。しかし、コンテキストが非ヌルの場合、コンテキストmutexをまずロックするということを想起する必要がある） */
if (found_context != NULL) {
if ((i = pthread_mutex_lock(&found_context-＞shim_context_mutex)) != 0) {
/* Error, time to punt.（エラー、戻る） */
fprintf(stderr,
"pollshim: unable to lock context mutex, errno %d, exiting!\n", i);
fflush(stderr);
exit(-1);
}
}
if ((i = pthread_mutex_unlock(&poll_shim_global_mutex)) != 0)
/* Error, time to punt.（エラー、戻る） */
fprintf(stderr,
"pollshim: unable to unlock poll_shim_global_mutex, errno %d, exiting!\n", i);
fflush(stderr);
exit(-1);
}
return(found_context);
}
【００９０】
SECTION 3:
/* This routine presumes that the mutex protecting the shim_context struct is already locked by the caller.  We walk the list of pollfds, and see what events are of interest.  
If the FD is within our tracking limit we next see if that FD has been registered with the eventport with the events in which the user has just expressed interest.  
If the all the events of interest for the FD have not been registered with the eventport, we attempt to register the FD with the eventport.  
We also store a pointer in the shim fd context structure to the appropriate element of the fds list.  This way, when we get the return from the eventport ioctl we can take the (generally much) shorter list returned from it, use the fd to index into the shim fd context structure and find the right entry in the user's fds list to update.
As we walk the user's pollfd array, we clear the user's revents field of each pollfd structure.  It is best/necessary to do it here because this is the _only_ place we will walk the user's entire fds array - we do not walk that array after the eventport ioctl as we only update for those FDs that came back from the ioctl call.  We also have to set the generation count appropriately.  The generation count is used to protect us when the user does something silly like list the same FD twice in the fds array - we don't want to handle that, and will want to punt.  
If the attempt to register the FD with the eventport fails, we return a failure code. It is then up to the caller to decide whether or not it wants to do something or call the "real" poll routine.  .fd check against limit（このルーチンは、shim_context structを保護するmutexが呼び出し元によってすでにロックされているものと想定する。pollfdsリストをウォークし、どのイベントが関心イベントかを調べる*\
\*FDが追跡限度内にある場合には、次に、ユーザがちょうど関心を示したイベントを有するeventportに、そのFDに登録されているかどうかを調べる。FDの関心イベントのすべてがまだeventportに登録されたわけではない場合、ＦＤをeventportに登録しようと試みる。
また、fdsリストの適切な要素へのポインタをshim fd context structureに格納する。この方法では、eventport ioctlから戻り値を得ると、eventport icotlから戻された（一般にはるかに）短いリストを採用し、fdを使用してshim fd context構造にインデックスを付け、ユーザのfdsリスト中の更新すべき正しいエントリを見つけることができる。
　ユーザのpollfd配列をウォークする際、各pollfd構造のユーザ復帰フィールドをクリアする。これは、ユーザのfds配列全体をウォークする_only_placeであるため、そうすることがここでは最良\必要である。ioctlコールから戻ったFDのみを更新するため、eventport ioctl後にその配列をウォークすることはない。また、生成カウントを適宜セットする必要がある。生成カウントは、ユーザが、同じFDをfds配列に２度リストするなど何か馬鹿げたこと（扱いたくないので戻りたくなる）をする際の保護として使用される。
　FDをeventportに登録する試みが失敗する場合には、失敗コードを戻す。次に、何かしたいか否か、または「実際の」pollルーチンを呼び出すか否かの判断は呼び出し元次第である。限度に照らし合わせての.fdチェック。） */
int
poll_shim_walk_and_reg_fds(struct shim_context *context, 
struct pollfd fds[],
nfds_t nfds) {
int i;
struct shim_fd_context *fd_context;
struct pollfd register_this;
/* Might as well be pedantic about it.（それについて厳密にしたほうがよい） */
register_this.fd = -1;
register_this.events = 0;
register_this.revents = 0;
for (i = 0; i ＜ nfds; i++) {
/* Do not forget to zero-out all the revents of the users fds array!!! - we will do this here to make sure we do not forget - even though if we are going to failover to poll(), poll() would do it for us.（ユーザfds配列のreventsをすべて０にすることを忘れないこと。ここでは確実に忘れないように−poll( )にフェイルオーバすることになる場合であっても、poll( )がこれを行ってくれるように、これを行う） */
fds[i].revents = 0;
if (fds[i].fd ＜ poll_shim_nfds_limit) {
/* Keep going.  Is the FD already registered with the even port with a superset of the events in which the user is interested?（続行。FDがすでに、ユーザが関心を持つイベントのスーパーセットを有するeventportに登録されているか？） */ 
fd_context = &(context-＞shim_fd_contexts[fds[i].fd]);
/* We can probably use the events field and get rid of the registered field if we really wanted to.（おそらく、eventsフィールドを使用し、登録されたフィールドを除去することができる（本当にそうしたいならば）） */
if ((fd_context-＞registered) &&
((fd_context-＞events & fds[i].events) == fds[i].events)) {
/* Keep going - need to check and update the generation value（続行−生成値をチェックし更新する必要あり） */
if ((context-＞generation) != (fd_context-＞generation)) {
/* OK, this FD has not already appeared in the users fds array, and it is registered, so update the fields that need it.  Registered and events should already be set（ＯＫ、このFDはまだユーザfds配列に現れておらず、登録され、よって必要なフィールドを更新する。registeredおよびeventsはすでにセットされているはずである） */
fd_context-＞users_pollfd_ptr = &(fds[i]);
fd_context-＞generation = context-＞generation;
/* Given the nesting of the if/else stuff, the continue may not be necessary, but it shouldn't hurt.（if\elseの入れ子が与えられるならば、継続する必要はないかもしれず、支障はないはずである） */
continue;
}
else {
/* The generation numbers match which means we have hit this fd once before this time around. We do not know what to do in that case, so return an error.（生成番号がマッチングすることは、今回以前に一度このfdにヒットしたことを意味する。この場合、何をすべきかはわからないため、エラーを戻す） */
user_dup_fds++;
return(1);
}
}
else {
/* We need to try to register the fd with the eventport（fdをeventportに登録しようと試みる必要がある） */
register_this.fd = fds[i].fd;
register_this.events = fds[i].events;
if (write(context-＞eventport,
&register_this,
sizeof(register_this)) == sizeof(register_this)) {
/* The registration was successful, update some fields and continue.  The continue may not be needed.（登録は成功した。いくつかのフィールドを更新して継続する。継続する必要がない場合もある） */
fd_context-＞users_pollfd_ptr = &(fds[i]);
fd_context-＞generation = context-＞generation;
fd_context-＞registered = 1;
fd_context-＞events = fds[i].events;
eventport_registers++;
context-＞nfds += 1;
continue;
}
else {
/* The write failed, return an error（書き込み失敗、エラーを戻す） */
eventport_regfail++;
return(1);
}
}
}
else {
/* User gave us an fd that was above the limit for tracking in our array, return an error（ユーザが与えたfdは、配列の追跡限度を超える。エラーを戻す） */
poll_shim_nfds_limit++;
return(1);
}
}
return(0);
}
/* This routine will take the events returned from the eventport ioctl, and for each of them find the corresponding fd_context struct in the context area provided.  
If the user was indeed interested in this fd (the generation numbers match) then we will update the revents struct of their pollfd accordingly. 
If they were not interested we will do nothing with the event.
The routine will return the number of user-interested FDs found in the list returned from the eventport. it is up to the caller to decide what to do if that value is zero.   
This routine presumes that it is called with the context mutex locked.
（このルーチンは、eventport icotlから戻されたイベントをとり、それぞれについて、提供されたコンテキストエリアにおいて対応するfd_context structを見つける。
　ユーザが本当にこのfdに関心があった（生成番号がマッチングする）場合、それに従ってそれぞれのpollfdのrevents structを更新する。
　関心のないものであった場合、そのイベントについて何もしない。
　ルーチンは、eventportから戻されたリストに見られるユーザ関心FDの数を戻す。その値が０であった場合に何をするかは呼び出し元次第である。
　このルーチンは、コンテキストmutexがロックされた状態で呼び出されるものと想定する） */
int
poll_shim_walk_returned_events(struct shim_context *context, 
struct dvpoll *dp_results,
nfds_t nfds) {
int fds_ready = 0;
struct shim_fd_context *fd_context;
pollfd_t *eventfds;
int i;
struct pollfd *users_pollfd_entry;
eventfds    =  dp_results-＞dp_fds;
for (i = 0; i ＜ nfds; i++) {
/* So, was the event we got back from the eventport one in which the user was interested this time around?  The fds in the list returned by the eventport are used as indices into the list of fds kept in the context. 
If the generation in the fd in the context and the generation of the context match, then this was an fd in the user's pollfd array.  If not, this was an fd in which the user _used_ to have an interest but not at the present.（そうすると、eventportから戻したイベントは、ユーザが今回関心のあるものであったか？eventportによって戻されたリスト中のfdsは、コンテキストに保持されるfdsのリストへのインデックスとして用いられる。
　コンテキスト中のfdにおける生成とコンテキストの生成とがマッチングする場合、これは、ユーザのpollfd配列中のfdであった。マッチングしない場合、これは、ユーザが以前関心を持っていたが現在では関心がないfdであった */
fd_context =  &(context-＞shim_fd_contexts[eventfds[i].fd]);
/* Generations must match, and the users interest must be a superset of that for which we've registered.（生成はマッチングしなければならず、ユーザの関心は登録したもののスーパーセットでなければならない） */
if ((fd_context-＞generation == context-＞generation) &&
(((fd_context-＞users_pollfd_ptr)-＞events) & 
(eventfds[i].revents))) {
/* This was an fd of interest to the user, update the corresponding pollfd entry（これはユーザにとって関心のあるfdであった。対応するpollfdエントリを更新） */
(fd_context-＞users_pollfd_ptr)-＞revents = 
((eventfds[i].revents) & ((fd_context-＞users_pollfd_ptr)-＞events));
fds_ready += 1;
}
}
return(fds_ready);
}
【００９１】
SECTION 4:
/*  This routine, when finally implemented, will deregister fds with events from an eventport in which the user is no longer interested.  It is anticipated that this routine will only be called when an eventport ioctl returns nothing but fd's that are not of interest to the user, so the caller can then go back and issue another ioctl with (preumeably) only fd's that are of interest to the caller.（このルーチンは、やっと実施されると、ユーザがもはや関心のないイベントを有するfdをeventportから登録解除する。このルーチンは、eventport ioctlが、ユーザにとって関心のないfdしか戻さない場合にのみ呼び出されるものと予想される。よって、呼び出し元は次に戻り、（おそらく）呼び出し元にとって関心のあるfdのみを有する別のioctlを発行する） */ 
int
poll_shim_deregister_boring_fds(struct shim_context *context,
struct dvpoll *dp_results,
nfds_t nfds) {
struct shim_fd_context *fd_context;
pollfd_t *eventfds;
struct pollfd dereg_this;
int i;
int dereg_failure = 0;
/*  If we have been called, it may mean that we've not registered an FD of interest to the user thanks to a "false positive" on the pollfd array walk avoidance heuristic, so we best turn that off so the next time around we will walk the list and do some registers.（呼び出されたことがある場合、これは、pollfd配列ウォーク回避ヒューリスティックでの「フォールスポジティブ」により、関心FDをユーザに登録していないことを意味しうるため、それをオフにして、次回にはリストをウォークしいくらかの登録を行うことが最もよい） */
/*  We can assume that anything in the list of results from the eventport ioctl were not of interest to the user, so all the entries in the list should be de-registered.  Do not need to access the users pollfd array like we do in poll_shim_walk_returned_events().（eventport ioctlからの結果のリスト中のものはすべてユーザにとって関心がないものであったと想定することができ、よってリスト中のすべてのエントリを登録解除すべきである。poll_shim_walk_returned_events( )で行うように、ユーザpollfd配列にアクセスする必要はない） */
dereg_this.events = POLLREMOVE;
dereg_this.revents = 0; 
/* Probably being pedantic（おそらく厳密である） */
eventfds = dp_results-＞dp_fds;
for (i = 0; i ＜ nfds; i++) {
/* Might as well go ahead and assume the dereg succeeds（先に進み、登録解除が成功したものと想定したほうがよい） */
fd_context = &(context-＞shim_fd_contexts[eventfds[i].fd]);
fd_context-＞generation = 0;
fd_context-＞registered = 0;
fd_context-＞events     = 0;
fd_context-＞users_pollfd_ptr = NULL;
dereg_this.fd = eventfds[i].fd;
if (write(context-＞eventport,
&dereg_this,
sizeof(dereg_this)) == sizeof(dereg_this)) {
/* Successful registration（登録成功） */
eventport_deregisters++;
}
else {
/* Error.  Check the errno and do something based on that.  The dereg failed, pass a failure indication back to the caller and call the "real" poll this time around.（エラー。errnoをチェックし、チェックに基づいて何かを行う。登録解除が失敗し、失敗インジケーションを呼び出し元に渡し、今回は「実際の」pollを呼び出す） */
dereg_failure = 1;
eventport_deregfail++;
}
}
if (!dereg_failure) {
return(0);
}
else {
return(1);
}
}
【００９２】
SECTION 5:
/*  This is the poll shim. it is intended to intercept the user's call to poll, and then poof, gee wiz, convert the user's poll calls into eventport calls.（これはpoll shimである。ユーザのpollコールをインタセプトし、次いでユーザのpollコールを検査し、驚くことにeventportコールに変換するように意図される） */
int 
poll(struct pollfd fds[], nfds_t nfds, int timeout)
{
int ret;
int ret2;
struct pollfd devp_fds[POLL_SHIM_NFDS_LIMIT]; 
/* used in the dvp_struct to tell the ioctl where the return info should be placed.  we could malloc this as we go and increase its size as we go, but we'll not bother and just burn the RAM.  Another option would be to do a getrlimit on the hard limit to the number of FDs for this process.（dvp_structにおいて、リターン情報を配置すべき場所をioctlに教えるために使用される。途中でこれをmallocし、そのサイズを増大してよいが、ここではわざわざそうすることはせず、単にＲＡＭに焼き付ける。別のオプションは、このプロセスのFD数へのハードリミットに対するgetrlimitを行うことである。） */ 
struct dvpoll dvp_struct;
struct shim_context *context; 
/* this will be the pointer to the shim_context associated with the users fds array.（これは、users fds配列に関連するshim_contextへのポインタになる） */ 
int context_locked;
/* tell us whether or not we think the shim_context mutex is locked so we can try to do the right thing when we take the bypass.（迂回する際に正しいことを行おうとすることができるように、shim_context mutexがロックされていると考えるか否かを教える） */ 
dvp_struct.dp_fds = devp_fds;
/* If the address of the "real" poll call is not known, we can assume that we've not been called yet.（「実際の」pollコールのアドレスがわからない場合、まだ呼び出されていないものと仮定することができる） */
if (real_poll == NULL) {
pthread_once(&once_control,poll_shim_initialize);
}
context_locked = 0; 
/* assume that we will not be able to use the eventport.（eventportを使用することができないものと想定） */ 
poll_calls++;
/* We really are not interested in the onsey-twosy calls to poll()（poll( )への１つや２つなどの呼び出しには実際に関心がない） */
if (nfds ＜ poll_shim_nfds_threshold) {
nfds_below_threshold++;
goto bypass;
}
/* Similarly, if we are called with too many fds, we have to punt（同様に、fdsの呼び出しが多すぎる場合、戻る必要がある） */
if (nfds ＞ poll_shim_nfds_limit) {
nfds_above_limit++;
goto bypass;
}
if ((context = poll_shim_find_context(fds)) != NULL) {
/* Continue and make sure that all the fds in the users pollfd array are registered with the eventport（継続し、確実にusers pollfd配列中のすべてのfdsがeventportに登録されるようにする） */
context_locked = 1;
context-＞generation += 1;
if (poll_shim_walk_and_reg_fds(context,fds,nfds) == 0) {
/* We know that the eventport has at least all the fds in which the user is interested registered, so go ahead and do the eventport ioctl().（eventportに、ユーザが関心を有する少なくともすべてのfdが登録されたことがわかるため、先に進み、eventport ioctl( )を行う） */
dvp_struct.dp_nfds = context-＞nfds;
dvp_struct.dp_timeout = timeout;
if ((ret = ioctl(context-＞eventport,
DP_POLL,
&dvp_struct)) ＞ 0) {
/* We have some fd's returned, walk the list and update the users fds array accordingly（fdがいくつか戻され、リストをウォークし、それに従ってusers fds配列を更新する） */
eventport_calls++;
if ((ret = poll_shim_walk_returned_events(context,
&(dvp_struct),
ret)) ＞ 0) {
/* Happiness and joy - we got some events from the eventport for the user's pollfd array, so we can return.  However, we have to remember to unlock the context mutex first!-)（幸福と喜び−users pollfd配列のeventportからいくつかのイベントが戻されたため、戻ることができる。しかし、コンテキストmutexをまずアンロックすることを想起する必要がある） */
if ((ret2 = 
pthread_mutex_unlock(&(context-＞shim_context_mutex))) != 0) {
fprintf(stderr,
"Unable to unlock shim context pointer, errno %d, exiting!",
ret2);
fflush(stderr);
exit(-1);
}
evp_returned_fds++;
return(ret);
}
else {
/* We either got nothing back or ran into some error.  For now, let's punt.（何も戻されなかったか、あるいはあるエラーが発生した。この場合、戻る） */
goto bypass;
}
}
else {
/* There was some sort of error or there were no fds returned from the ioctl (perhaps a timeout) precisely what we should do here is anyone's guess.  Hit the bypass so our mutex is dealt with correctly.（ある種のエラーが発生したか、またはioctlからfdsが戻されなかった（おそらくタイムアウト）。この場合に厳密に何をすべきかは、誰にも分からない。mutexに正しく対処するように迂回する） */
goto bypass;
}
}
else {
/* Either an eventport registration failed, or the user asked for something other than POLLIN on one of the FDs, so we need to punt and call the "real" poll.（eventport登録が失敗した、あるいはユーザがFDの１つに対してPOLLIN以外を要求した。したがって、戻って「実際の」pollを呼び出す必要がある） */
goto bypass;
}
}
else {
/* We could neither find, nor allocate a context based on the user's fds address, so we have to call the "real" poll.（ユーザのfdsアドレスに基づいてコンテキストを見つけることも、また割り当てることもできなった。よって「実際の」pollを呼び出す必要がある） */
goto bypass;
}
bypass:
/* For some reason or another, it was not possible to use eventports on this call to poll.  Check and see if the context mutex is locked and if so, try to unlock it before we go into poll() lest we end-up in a deadlock next time we are called.  If the unlock fails, we aren't in Kansas anymore toto, and we best click our heals together and say "There's no call like exit. There's no call like exit.  There's no call like exit." and get the flock out of dodge（何らかの理由により、このpollコールに対してeventportを使用することができなかった。コンテキストmutexがロックされているか否かをチェックして調べ、ロックされている場合、次に呼び出されるときにデッドロック状態にならないように、poll( )に入る前にコンテキストmutexをアンロックするよう試みる。アンロックが失敗する場合には、トト、ここはカンザスじゃないみたい、ということで靴のかかとを打ち鳴らし「出口なんてコールはない、出口なんてコールはない、出口なんてコールはない」と唱えて逃げ出すのが最も良い） */
if (context_locked) {
if ((ret = 
pthread_mutex_unlock(&(context-＞shim_context_mutex))) != 0) {
fprintf(stderr,
"Unable to unlock shim context pointer, errno %d, exiting!",
ret);
fflush(stderr);
exit(-1);
}
}
if ((poll_calls % POLL_SHIM_DUMP_STATS) == 0) {
printf("calling the real poll, with fds at %p, nfds %d, timeout %d\n",
fds,nfds,timeout);
poll_shim_stats();
}
realpoll_calls++;
return (int)(*real_poll)(fds,nfds,timeout) ;
}
【００９３】
SECTION 6:
/* When an application calls close() on a filedescriptor, the kernel will automatically deregister it from any eventports.  However,  the shim is not going to know unless it intercepts the call to close.  So, here we are, intercepting the call to close().  When the application calls close, we have to lock the global mutex, and then walk the list of active contexts.  For each context, we lock the context mutex; if we find a  match with a registered FD, we have to clear out that fd_context; then we unlock the context mutex and move-on. 
Once all the contexts have been searched, we call close() - we want to do this with the global context still held since we don't want any other call to poll by some other thread in the app to come along before we are done with the call to close.  This may be a bit overly paranoid of me, but at the moment it feels right. besides, apps should never be trying to close() and poll() on the same FD at the same time anyway, so the possibility of contention on the mutex would be slim.
（アプリケーションがフィールドスクリプタに対してclose( )を呼び出す場合、カーネルはあらゆるeventportsから自動的に登録解除する。しかし、shimは、closeコールをインタセプトしない限り知ることがない。よってここでは、close( )コールをインタセプトする。アプリケーションがcloseを呼び出すときには、グローバルmutexをロックし、次いでアクティブコンテキストリストをウォークする必要がある。各コンテキスト毎にコンテキストmutexをロックし、登録されたFDとマッチングが見つかる場合にはそのfd_contextを消去する必要があり、次いでコンテキストmutexをアンロックし、次に進む。
　コンテキストがすべて探索されてから、close( )を呼び出す。closeコールを終了する前に、アプリケーション中の他のあるスレッドによる他のいずれのpollコールも出現して欲しくないため、まだ保持されているグローバルコンテキストを使用してこれを行いたい。これは少し考えすぎかもしれないが、今のところは正しいと思う。その他に、mutex上で競合する確率を低くするために、アプリケーションは決して、同じFDに対してclose( )およびpoll( )を同時に試行すべきではない） */
int
close(int fildes) {
int i;
int ret;
struct shim_fd_context *fd_context;
/* Yes, we are checking for real_poll rather than real_close - if  one is not initialized, the other will not be, and if one is initialized, the other must be. so, we just have to check for the one.（その通り、real_closeではなくreal_pollをチェックしている。一方が初期化されていない場合には他方も初期化されることはなく、また、一方が初期化されている場合には他方も初期化しなければならない。したがって、チェックする必要があるのは一方だけである） */
if (real_poll == NULL) {
pthread_once(&once_control,poll_shim_initialize);
}
close_calls++;
if (fildes ＜ poll_shim_nfds_limit) {
/* It is theoretically possible that the shim has registered this FD with one or more eventports, so we best go make sure that we clear out the appropriate data structures.（理論上、shimがこのFDを１つまたは複数のeventportに登録することが可能である。よって、適切なデータ構造を消去するよう確実にすることが最もよい） */
if ((ret = pthread_mutex_lock(&poll_shim_global_mutex)) != 0) {
/* Something is seriously wrong, time to punt.（重大な異常あり。戻る） */
fprintf(stderr,
"pollshim: unable to lock poll_shim_global_mutex, errno %d, exiting!\n", ret);
fflush(stderr);
exit(-1);
}
/*  We only initialize contexts, we never "free" them, so the unallocated entries in the array (users_pollfd_base_ptr == NULL) should always be at the end of the array, and if we get to one, it means there is going to be no match with an existing entry.（コンテキストを初期化するだけであり、決して「解放」しないため、配列中の割り当てられていないエントリ（users_pollfd_base_ptr==NULL)は常に配列の末尾にあるはずであり、これに達すると、これは既存のエントリとのマッチングがなくなることを意味する） */
i = 0;
while ((i ＜ POLL_SHIM_MAX_CONTEXTS) &&
(poll_shim_contexts[i].users_pollfd_base_ptr != NULL)) {
close_evp_walks++;
/* Do not forget to lock the context mutex. once we have the context mutex, and the global mutex, we know that no-one else can be doing anything :)（コンテキストmutexのロックを忘れないこと。一旦コンテキストmutexおよびグローバルmutexを持ってしまうと、他の誰も何もできなくなることが分かっている：）） */
if ((ret = pthread_mutex_lock(&(poll_shim_contexts[i].shim_context_mutex))) != 0) {
/* Something is seriously wrong, time to punt.（重大な異常あり。戻る） */
fprintf(stderr,
"pollshim: unable to lock context mutex, errno %d, exiting!\n", i);
fflush(stderr);
exit(-1);
}
/*  Since we are not being PBO'd, and since our lists could be quite sparse, perhaps it is just simplest to arbitrarily clear the fields of that FD rather than having a conditional check.  That way, we have no worries about branch misprediction.（ＰＢＯされていないため、またリストはかなり疎であり得るため、条件付きチェックを行うよりもそのFDのフィールドを任意にクリアすることのほうが、おそらく実際に最も簡単である。そのようにすると、分岐の予測ミスについての心配がない） */
fd_context = &(poll_shim_contexts[i].shim_fd_contexts[fildes]);
fd_context-＞users_pollfd_ptr = NULL;
fd_context-＞registered = 0;
fd_context-＞generation = 0;
fd_context-＞events = 0;
/* Now we need to unlock the shim_context mutex（ここで、shim_context mutexをアンロックする必要がある） */
if ((ret = pthread_mutex_unlock(&(poll_shim_contexts[i].shim_context_mutex))) != 0) {
/* Something is seriously wrong, time to punt.（重大な異常あり。戻る） */
fprintf(stderr,
"pollshim: unable to lock context mutex, errno %d, exiting!\n", i);
fflush(stderr);
exit(-1);
}
i++;
}
/* Now we can call close(), secure in the knowledge that we have removed all traces of it from the shim contexts.（ここで、シムコンテキストからすべての痕跡を除去したことがわかったため、安心してclose( )を呼び出すことができる） */
i = (int)(*real_close)(fildes);
/* Forgetting to unlock the mutex could ruin your whole day.（mutexのアンロックを忘れると、君の丸一日が無駄になる） */
if ((ret = pthread_mutex_unlock(&poll_shim_global_mutex)) != 0) {
/* Something is seriously wrong, time to punt.（重大な異常あり。戻る） */
fprintf(stderr,
"pollshim: unable to lock poll_shim_global_mutex, errno %d, exiting!\n", ret);
fflush(stderr);
exit(-1);
}
return(i);
}
else {
/* This fd was beyond the limits of what we could have possibly registered, so just return the real_close.（このfdは、登録することが可能な限度を越えていた。よって、ただreal_closeを戻す） */
return (int)(*real_close)(fildes);
}
}
【００９４】
　［付録Ｂ］
/* cc +z -D_REENTRANT ＜archstuff＞ -c select_shim.c */
/* ld -b -o libselectshim.sl select_shim.o -lpthread */
#include ＜stdio.h＞
#include ＜stdlib.h＞
#include ＜unistd.h＞
#include ＜stropts.h＞
#include ＜fcntl.h＞
#include ＜devpoll.h＞
/* under HP-UX, poll.h is included by devpoll.h, but this shouldn't hurt（HP-UXの下では、poll.hはdevpoll.hに含まれるが、これは、支障ない） */
#include ＜poll.h＞
#include ＜dlfcn.h＞
#include ＜sys/time.h＞
#include ＜pthread.h＞
static const char select_shim_version[] = \
"@(#)select_shim.c ";
#ifdef DEBUG
#define ROUTINE_ENTRY_TRACE fprintf(stderr,"entry to routine %s\n",__func__);\
fflush(stderr);
#define MUTEX_LOCK_TRACE(x) fprintf(stderr,\
"routine %s locking mutex %p\n",\
__func__,x);\
fflush(stderr);
#define MUTEX_UNLOCK_TRACE(x) fprintf(stderr,\
"routine %s unlocking mutex %p\n",\
__func__,x);\
fflush(stderr);
#else
#define ROUTINE_ENTRY_TRACE 
#define MUTEX_LOCK_TRACE(x)
#define MUTEX_UNLOCK_TRACE(x)
#endif /* DEBUG */
【００９５】
SECTION 1:
#define SELECT_SHIM_MAX_CONTEXTS   16
#define SELECT_SHIM_NFDS_LIMIT     20000
#define SELECT_SHIM_NFDS_THRESHOLD 128
#define SELECT_SHIM_DUMP_STATS     1024
static int select_shim_nfds_threshold = SELECT_SHIM_NFDS_THRESHOLD;
static int select_shim_nfds_limit = SELECT_SHIM_NFDS_LIMIT;
static int select_shim_recurse_enabled = 0;
struct shim_fd_context {
unsigned int  generation;   
/* The last time this FD appeared in the users fd_set array.  This is used to detect duplicate fds in the user's fd_set array.  If we encounter an entry with the same generation number as this generation of call, it means that the user had the same FD in the fd_set array at least twice and we will punt to the real poll() call.  Later it will also be used to decide when to unregister an FD from the eventport（users fd_set配列においてこのFDが最後に現れるとき。これは、users fd_set配列中の複製fdsを検出するために用いられる。このコール生成と同じ生成番号のエントリに直面する場合、これは、ユーザがfd_set配列中に同じFDを少なくとも２度有したことを意味し、実際のpoll( )コールに戻る。後に、これは、eventportからFDを登録解除すべきときを決定するためにも用いられる） */  
int registered;
/* Is this FD already registered in the eventport?（このFDはeventportに登録済か？） */
short events;         
/* For what events have we registered this FD in the eventport?  Initially this should either be zero to mean nothing registered, or flags to indicate that in which we've registered interest（どのイベントについて、このFDをeventportに登録したのか？最初は、これは何も登録されていないことを意味する０であるか、あるいは関心を登録したことを示すフラグであるべきである） */  
short userwanted;          
/* The events in which the user was interested this generation. we use POLLIN, POLLOUT and POLLERR（ユーザがこの生成に関心をもったイベント。POLLIN、POLLOUT、およびPOLLERRを使用する） */
};
/* The table of contexts we will track（追跡するコンテキストのテーブル） */
struct shim_context {
/* The mutex used to protect this specific shim_context（この特定のshim_contextを保護するために使用されるmutex） */
pthread_mutex_t shim_context_mutex;
fd_set *users_readfds_ptr;      
/* The pointer back to the user's readfds fd_set（ユーザのreadfds fd_setに戻るポインタ） */ 
fd_set *users_writefds_ptr;     
/* The pointer back to the user's writefds fd_set（ユーザのwritefds fd_setに戻るポインタ） */
fd_set *users_errorfds_ptr;     
/* The pointer back to the user's errorfds fd_set（ユーザのerrorfds fd_setに戻るポインタ） */
unsigned int      generation;   
/* How many times has user called select() with the samefd_set pointer（同じfd_setポインタでユーザがselect( )を呼び出した回数） */  
int      eventport;             
/* The file descriptor for the event port.（eventportのファイル記述子） */  
int      nfds;                 
/* The count of fd's registered to the eventport（eventportに登録されたfdのカウント） */ 
/* The list of "state" info the shim maintains on FDs that may or may not be registered with the eventport.  This will probably be a sparse array - we are trading memory for time so we can use FD values as indices.（eventportに登録されている／いないかもしれないFDについてshimが保持する「状態」情報のリスト。これは疎な配列であってよい。時間のためにメモリを犠牲にしているため(We are trading memory for time)、FD値をインデックスとして使用できる） */
struct shim_fd_context shim_fd_contexts[SELECT_SHIM_NFDS_LIMIT];
};
struct shim_context select_shim_contexts[SELECT_SHIM_MAX_CONTEXTS];
/*  Protecting these statistics is not a concern, since all we ever do is increment them, and runtime decisions are not based on these statistics.（これら統計の保護は重要ではない。理由は、行ったことといえば統計の増分だけであり、実行時判断はこれら統計に基づいて行われないためである） */
static int      select_calls=0;       
/* Number of times the app calls select（アプリケーションがselectを呼び出した回数） */ 
static int      eventport_calls=0;   
/* Number of times we eventport（eventportを呼び出した回数） */
static int      evp_returned_fds=0;   
/* Number of times an eventport call returned fd's of interest to the user（eventportコールがユーザ関心fdsを戻した回数） */ 
static int      evp_ioctl_errs=0;    
/* Number of times the ioctl call failed（ioctlコールが失敗した回数） */
static int      evp_ioctl_no_fds=0; 
/* Number of times the ioctl call returned no fds at all（ioctlコールがfdsをまったく戻さなかった回数） */
static int      realselect_calls=0;   
/* Number of times we call select（selectを呼び出した回数） */
static int      eventport_registers=0; 
/* Number of fd's registered（登録されたfdsの数） */
static int      eventport_deregisters=0; 
/* Number of fd's deregistered（登録解除されたfdsの数） */
static int      user_dup_fds=0;  
/* How often the same fd appeared twice in the fds array（fds配列中で同じfdが２度出現した頻度） */
static int      eventport_regfail=0; 
/* How often an eventport registration failed（eventport登録が失敗した頻度） */
static int      eventport_deregfail=0; 
/* How often an eventport registration failed（eventport登録解除が失敗した頻度） */
static int      event_not_pollin=0; 
/* Times we punted because the user wanted something other than POLLIN（ユーザがＰＯＬＬＩＮ以外を求めたことにより戻った回数） */  
static int      nfds_below_threshold=0; 
/* Times we punted because the user was asking for too few fds to be selected.（ユーザがselecctを要求するfdsが少なすぎることにより戻った回数） */
static int      nfds_above_limit=0; 
/* Times we punted to select because the user was asking for more fds than we were configured to track.（ユーザの要求するfdsが追跡するように構成されたfdsよりも多いことにより戻った回数） */
static int      close_calls = 0; 
/* The number of calls to close() intercepted by the shim（shimがインタセプトしたclose( )への呼び出し数） */
static int      close_evp_walks = 0; 
/* The number of intercepted close calls which walked the shim contexts（shim contextをウォークしたインタセプトcloseコール数） */
static int      select_shim_recursions = 0;
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
static pthread_mutex_t select_shim_global_mutex = PTHREAD_MUTEX_INITIALIZER;
int     *(*real_select)(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *errorfds, struct timeval *timeout) = NULL;
int     *(*real_close)(int fildes) = NULL;
void
select_shim_stats() 
{
fprintf(stderr,"select_shim statistics:\n");
fprintf(stderr,"\t%d calls to select() by user\n",select_calls);
fprintf(stderr,"\t%d calls to eventport by shim\n",eventport_calls);
fprintf(stderr,"\t%d evp calls returned interesting fds\n",evp_returned_fds);
fprintf(stderr,"\t%d evp ioctls returned erorrs\n",evp_ioctl_errs);
fprintf(stderr,"\t%d evp ioctls returned no fds\n",evp_ioctl_no_fds);
fprintf(stderr,"\t%d calls to select() by shim\n",realselect_calls);
fprintf(stderr,"\t%d recursive calls by shim\n",select_shim_recursions);
fprintf(stderr,"\t%d fds registered by shim\n",eventport_registers);
fprintf(stderr,"\t%d fds deregistered by shim\n",eventport_deregisters);
fprintf(stderr,"\t%d calls with fd listed twice in fds \n",user_dup_fds);
fprintf(stderr,"\t%d eventport registration failures\n",eventport_regfail);
fprintf(stderr,"\t%d eventport deregistration failures\n",eventport_deregfail);
fprintf(stderr,"\t%d calls with an event other than POLLIN|POLLRDNORM\n",event_not_pollin);
fprintf(stderr,"\t%d calls with nfds ＜ threshold (%d)\n",
nfds_below_threshold,
select_shim_nfds_threshold);
fprintf(stderr,"\t%d calls with nfds ＞ limit (%d)\n",
nfds_above_limit,
select_shim_nfds_limit);
fprintf(stderr,"\t%d calls to close\n",close_calls);
fprintf(stderr,"\t%d calls to close walked shim contexts\n",close_evp_walks);
fflush(stderr);
}
void
select_shim_initialize() {
char *threshold_string;
int ret;
ROUTINE_ENTRY_TRACE;
if (real_select == NULL) {
fprintf(stderr,
"＞＞＞＞ WARNING! SELECT() to EVP SHIM ACTIVATED ＜＜＜＜\n");
fprintf(stderr,"%s",select_shim_version);
atexit(select_shim_stats);
} 
else {
fprintf(stderr,"someone we had pthread_shim_initialize called twice?\n");
return;
}
/* dlsym() to get the entry point to the real select for when it is necessary.  Just use the RTLD_NEXT magic "handle" and presume that we are LD_PRELOADed into the executable, so select() should be found without having to dlopen() anything.  That at least is the implication from the dlopen() manpage - famous last words :)（必要な場合に実際のselectへのエントリポイントを取得するdlsym( )。RTLD_NEXTマジック「ハンドル」を使用する。実行可能ファイル（executable)にLD_PRELOADされたものと想定すると、select( )は、何もdlopen( )する必要なく見つかるはずである。dlopen( )マンページから示されるように、これは少なくとも、dlopen( )マンページに含意される（それはどうかな：））ものである） */
real_select = 
(int * (*) (int nfds, 
fd_set *readfds,
fd_set *writefds,
fd_set *errorfds,
struct timeval *timeout))dlsym (RTLD_NEXT, "select") ;
if (real_select == NULL)
{
fprintf(stderr,"unable to dlsym select: %s\n",dlerror());
fprintf(stderr,"consider undoing the LD_PRELOAD of the select shim\n");
exit (0) ;
}
real_close =  (int * (*) (int fildes))dlsym (RTLD_NEXT, "close") ;
if (real_close == NULL)
{
fprintf(stderr,"unable to dlsym close: %s\n",dlerror());
fprintf(stderr,"consider undoing the LD_PRELOAD of the select shim\n");
exit (0) ;
}
if ((threshold_string = getenv("EVP_SHIM_NFDS_THRESHOLD")) !=
NULL) {
/* the user wants to set the value for nfsd that will trigger using the eventport.（eventportを使用してトリガするnfsdのための値をユーザはセットしたい） */
if ((ret = sscanf(threshold_string,
"%d",
&select_shim_nfds_threshold)) != 1) {
/* Something went awry in reading the threshold value from the environment, use the default（環境からのしきい値の読み出しがうまくいかない。デフォルト使用） */
select_shim_nfds_threshold = SELECT_SHIM_NFDS_THRESHOLD;
}
}
if ((threshold_string = getenv("EVP_SHIM_RECURSE_ENABLE")) !=
NULL) {
select_shim_recurse_enabled = 1;
}
fprintf(stderr,"Eventport shim settings: \n");
fprintf(stderr,"\t use evp when nfds ＞ %d\n",
select_shim_nfds_threshold);
fprintf(stderr,"\t use evp when nfds ＜ %d\n",
select_shim_nfds_limit);
fprintf(stderr,"\t use ＜= %d evp contexts\n",
select_shim_nfds_limit);
fprintf(stderr,"\t recursion enabled %d\n",
select_shim_recurse_enabled);
}
【００９６】
SECTION 2:
/* This routine is only called during the initialization of a select_shim_context, to set the initial values of the select_fd_context struct to the desired values.  It is here as a separate call only to satisfy those who insist on pure CS 101 coding styles.  I'm willing to have the call overhead because initialization should be rare :)（このルーチンは、select_shim_contextの初期化中にのみ呼び出され、select_fd_context structの初期値を所望の値に設定する。ここでは、純粋なＣＳ１０１符号化スタイルを主張する者のみを満足させる別個のコールである。初期化は稀であるはずのため、コールオーバヘッドを厭わない：）） */
void
select_fd_context_initialize(struct shim_fd_context fd_contexts[]) {
int i;
ROUTINE_ENTRY_TRACE;
/* Since this is a contiguous array and everything is being set to zero/NULL, I suppose I could just call memset().（これは連続配列であり、すべてが０／ヌルに設定されるため、memset( )を呼び出すだけでよい） */
for (i=0; i ＜ SELECT_SHIM_NFDS_LIMIT; i++) {
fd_contexts[i].userwanted = 0;
fd_contexts[i].generation = 0;
fd_contexts[i].events = 0;
}
}
/*  This routine will initialize a context for a given context_id (a users fd_set array address). It presumes that the select_shim_global_mutex is locked and unlocked by the caller.  
We initialize the generation counter, open the eventport filedescriptor, and initialize the context-specific mutex.  Finally we set the users_fd_set-base_ptr to the context_id and return. 
If anything goes wrong, we cleanup and return a failure message and the caller can decide what to do - perhaps fallback on the "real"  select call.
（このルーチンは、所与のcontext_id（users fd_set配列アドレス）のコンテキストを初期化する。select_shim_global_mutexは呼び出し元によりロックおよびアンロックされるものと想定する。
　生成カウンタを初期化し、eventportファイル記述子を開き、コンテキスト固有mutexを初期化する。最後にusers_fd_set-base_ptrをcontext_idにセットし、戻す。
　エラーが発生する場合にはクリーンアップし、失敗メッセージを戻し、呼び出し元は何をすべきか、たとえば「実際の」selectコールにフォールバックすると判断することができる） */
int
select_shim_context_initialize(struct shim_context *context, 
void *context_id) {
int ret;
pthread_mutexattr_t attr;
ROUTINE_ENTRY_TRACE;
if ((ret = pthread_mutexattr_init(&attr)) == 0) {
/* Keep going（続行） */
if ((ret = pthread_mutex_init(&(context-＞shim_context_mutex),
&attr)) == 0) {
/* Keep going（続行） */
if ((context-＞eventport = open("/dev/poll", O_RDWR)) ＞= 0) {
/* Keep going, none of the rest of the stuff can "fail"（続行、残りはいずれも「失敗」しえない） */
select_fd_context_initialize(context-＞shim_fd_contexts);
context-＞generation = 0;
context-＞users_readfds_ptr = context_id;
return(0);
}
else {
/* the open of /dev/poll failed（/dev/pollのオープン失敗） */
}
}
else {
/* the pthread_mutex_init failed（pthread_mutex_init失敗） */
}
}
else {
/* the pthread_mutexattr_init failed（pthread_mutexattr_init失敗） */
}
return(1);
}
/*  Returns a pointer to the select_shim_context struct associated with context_id.  
If context_id is not found and there is room in the context store, a context is initialized. 
If the context is not   found, and there is no room in the context store, NULL is returned. 
Upon return of a non-NULL pointer, the mutex for the select_shim_context will be locked.
This routine will lock the global_shim_mutex while it performs the search and also while a newly allocated context is initialized.
This should be OK so long as stuff like opening an event port does not take too much time.  The routine will unlock the  global_shim_mutex before it returns. 
If any unrecoverable errors are encountered, this routine will clean up as best it can and will return a value of NULL.  
At that point it will be up to the caller to decide whether or not it wishes to abort/exit or simply fallback to the "real" select() call.
（ポインタをcontext_idに関連するselect_shim_contex structに戻す。
　context_idが見つからず、かつコンテキスト格納場所に空きがある場合、コンテキストは初期化される。
　コンテキストが見つからず、かつコンテキスト格納場所に空きがない場合、ヌルが戻される。
　非ヌルポインタが戻されると、select_shim_contextのmutexがロックされる。
　このルーチンは、探索を行う間、また新たに割り当てられたコンテキストが初期化される間、global_shim_mutexをロックする。
　これは、eventportオープンなどにかかる時間がそれほど長くない限り、支障ないはずである。このルーチンは、global_shim_mutexを戻す前にアンロックする。
　何等かの回復不可能なエラーに直面した場合、このルーチンはできる限りクリーンアップし、ヌル値を戻す。
　この時点で中止\終了したいか、または単に「実際の」select( )コールにフォールバックしたいか否かは、呼び出し元次第である。） */
struct shim_context *
select_shim_find_context(void *context_id) {
int i;
int ret;
struct shim_context *found_context = NULL;
ROUTINE_ENTRY_TRACE;
MUTEX_LOCK_TRACE(&select_shim_global_mutex);
if ((ret = pthread_mutex_lock(&select_shim_global_mutex)) != 0) {
/* Something is seriously wrong, time to punt.（重大な異常あり。戻る） */
fprintf(stderr,
"selectshim: unable to lock select_shim_global_mutex, errno %d, exiting!\n", ret);
fflush(stderr);
exit(-1);
}
/* We only initialize contexts, we never "free" them, so the unallocated entries in the array (users_readfds_ptr == NULL) should always be at the end of the array, and if we get to one, it means there is going to be no match with an existing entry.（コンテキストを初期化するだけであり、決して「解放」しないため、配列中の割り当てられていないエントリ（users_readfds_ptr==NULL)は常に配列の末尾にあるはずであり、これに達すると、これは既存のエントリとのマッチングがなくなることを意味する） */
i = 0;
while ((i ＜ SELECT_SHIM_MAX_CONTEXTS) && 
(found_context == NULL)) {
if (select_shim_contexts[i].users_readfds_ptr == NULL) {
/* We should never have a NULL user_fd_set_base_ptr before the match to the supplied context_id is found, so finding a NULL means that there is no context for that context_id.（通常、与えられたcontext_idとのマッチングが見つかる前にヌルのuser_fd_set_base_ptrを有することはまずないため、ヌルが見つかるということは、そのcontext_idにコンテキストがないことを意味する） */
if ((ret = 
select_shim_context_initialize(&(select_shim_contexts[i]),
context_id)) == 0) {
/* All was well（すべて順調） */
found_context = &(select_shim_contexts[i]);
}
else {
/* The call to select_shim_context_initialize failed（select_shim_context_initializeへの呼び出し失敗） */
}
/* At this point, we either found and initialized a new context, or that failed. there is no point in continuing in the while loop, because if the init failure were transient we might try to initialize the next NULL entry and then actually have a NULL entry  separating valid entries. That would be bad.（この時点で、新しいコンテキストを見つけて初期化するか、あるいはそれに失敗する。init失敗が一過性のものである場合、次のヌルエントリの初期化を試み、有効なエントリを隔てるヌルエントリが実際に生じてしまうことがあるため、whileループを続けることに意味はない。続けるのはよくないであろう。） */ 
break;
}
else {
/* The users_poll_fd_base_ptr was not null.  Does it perhaps match the context_id we are looking for?（users_select_fd_base_ptrはヌルではなかった。ひょっとすると探しているcontext_idにマッチングするか？） */
if (select_shim_contexts[i].users_readfds_ptr == context_id) {
/* We have a match（マッチング） */
found_context = &(select_shim_contexts[i]);
}
else {
/* There was no match, try the next entry（マッチングしなかった。次のエントリを試す） */
i++;
}
}
}
/* Once we get to this point, either we have a valid non-NULL shim_context, or it is NULL.  Time to unlock the global mutex and return. However, if our context is non-NULL, we have to remember to lock the context mutex first.（この時点に達すると、有効な非ヌルのshim_contextを得ているか、あるいはshim_contextがヌルである。グローバルmutexをアンロックし、戻すべきときである。しかし、コンテキストが非ヌルの場合、コンテキストmutexをまずロックするということを想起する必要がある） */
if (found_context != NULL) {
MUTEX_LOCK_TRACE(&found_context-＞shim_context_mutex);
if ((i = pthread_mutex_lock(&found_context-＞shim_context_mutex)) != 0) {
/* Error, time to punt.（エラー、戻る） */
fprintf(stderr,
"selectshim: unable to lock context mutex, errno %d, exiting!\n", i);
fflush(stderr);
exit(-1);
}
}
MUTEX_UNLOCK_TRACE(&select_shim_global_mutex);
if ((i = pthread_mutex_unlock(&select_shim_global_mutex)) != 0) {
/* Error, time to punt.（エラー、戻る） */
fprintf(stderr,
"selectshim: unable to unlock select_shim_global_mutex, errno %d, exiting!\n", i);
fflush(stderr);
exit(-1);
}
return(found_context);
}
【００９７】
SECTION 3:
/* This routine presumes that the mutex protecting the shim_context struct is already locked by the caller. we walk the three fd_sets stored in the context, and see what events are of interest.  
If the all the events of interest for the FD have not been registered with the eventport, we attempt to register the FD with the eventport.  We also store away the knowledge of what the user was interested in for this fd to the appropriate element of each of the three fd_sets for each fd_context. Thus, when we get the return from the eventport ioctl we can take the (generally much) shorter list returned from it, use the fd to index into the shim fd context structure and find the right FDs in the user's fd_sets to set.
As we walk the user's fd_set array, we clear the bits of each fd_set.  It is best/necessary to do it here because this is the_only_ place we will walk the user's entire fd_sets - we do not walk those fd_sets after the eventport ioctl as we only update for those FDs that came back from the ioctl call in which the user was interested.  We also have to set the generation count appropriately.
If the attempt to register the FD with the eventport fails, we return a failure code. It is then up to the caller to decide whether or not it wants to do something or call the "real" select routine. .fd check against limit . check against limit not necessary for select() version. 
（このルーチンは、shim_context structを保護するmutexが呼び出し元によってすでにロックされているものと想定する。コンテキストに格納されている３つのfd_setsをウォークし、どのイベントが関心イベントかを調べる。
　FDの関心イベントのすべてがまだeventportに登録されたわけではない場合、ＦＤをeventportに登録しようと試みる。また、このfdについてユーザが何に関心を持っているかについての知識を、fd_context毎に３つのfd_setsそれぞれの適切な要素に格納する。したがって、eventport ioctlから戻り値を得ると、eventport icotlから戻された（一般にはるかに）短いリストを採用し、fdを使用してshim fd context構造にインデックスを付け、ユーザのfd_sets中のセットすべき正しいFDを見つけることができる。
　ユーザのfd_set配列をウォークする際、各fd_setのビットをクリアする。これは、ユーザのfd_set全体をウォークする_only_placeであるため、そうすることがここでは最良\必要である。ユーザが関心を持ったioctlコールから戻されたFDのみを更新するため、eventport ioctl後にその配列をfd_setsはウォークしない。また、生成カウントを適宜セットする必要がある。
　FDをeventportに登録する試みが失敗する場合には、失敗コードを戻す。次に、何かしたいか否か、または「実際の」selectルーチンを呼び出すか否かの判断は呼び出し元次第である。限度に照らし合わせての.fdチェック。select( )版の場合には、限度に照らし合わせてのチェックは必要ない。） */
int
select_shim_walk_and_reg_fds(struct shim_context *context, 
nfds_t nfds) {
int i;
struct shim_fd_context *fd_context;
struct pollfd register_this;
struct fd_set *readfds;
struct fd_set *writefds;
struct fd_set *errorfds;
ROUTINE_ENTRY_TRACE;
/* Might as well be pedantic about it.（それについて厳密にしたほうがよい） */
register_this.fd = -1;
register_this.events = 0;
register_this.revents = 0;
readfds = context-＞users_readfds_ptr;
writefds = context-＞users_writefds_ptr;
errorfds = context-＞users_errorfds_ptr;
for (i = 0; i ＜ nfds; i++) {
fd_context = &(context-＞shim_fd_contexts[i]);
fd_context-＞userwanted = 0;
/* The readfds can never be NULL because we always bypass the shim when the user uses a NULL readfds ptr.（ユーザがヌルreadfds ptrを使用するときは常にshimを迂回するため、readfdsは決してヌルにならない） */
if FD_ISSET(i,readfds) {
/* Remember that the user wanted read on the FD and clear the bit（ユーザがFDに対する読み出しを求めることを想起し、ビットをクリアする） */
fd_context-＞userwanted |= POLLIN;
FD_CLR(i,readfds);
}
if (writefds &&
(FD_ISSET(i,writefds))) {
/* Remember that the user wanted write on the FD and clear the bit（ユーザがFDに対して書き込みを行いたいことを想起し、ビットをクリア） */
fd_context-＞userwanted |= POLLOUT;
FD_CLR(i,writefds);
}
if (errorfds &&
(FD_ISSET(i,errorfds))) {
/* Remember that the user wanted error on the FD and clear the  bit（ユーザがFDに対してエラーを求めることを想起し、ビットをクリア） */
fd_context-＞userwanted |= POLLERR;
FD_CLR(i,errorfds);
}
/*  Now that we know what the user wanted, see if that is the same as that for which we've already registered the FD with the eventport. if the registered events bitwise ANDed with the user wanted events then we have enough registered. 
If it is not equal to the userwanted, the cumulative nature of our event registration means that there is something in userwanted we've not yet registered. The XOR of userwanted and events should then be the events in userwanted we've not yet registered.
（ここで、ユーザが何を欲しいかがわかる。これが、eventportにすでに登録したFDと同じであるかどうかを調べる。登録されたイベントがユーザが欲するイベントとビット単位で論理積をとる場合、充分登録されている。
　ユーザが欲するものと等しくない場合、イベント登録の累積性質は、まだ登録していない、ユーザが欲する何かがあることを意味する。そうすると、ユーザが欲するものとイベントとの排他的論理和は、まだ登録していない、ユーザが欲するイベントであるはずである） */
if (((fd_context-＞events) & (fd_context-＞userwanted)) ==
fd_context-＞userwanted)  {
/* We already have everything necessary registered（必要なものすべてをすでに登録した） */
fd_context-＞generation = context-＞generation;
continue;
}
else {
/* There is something in userwanted for which we've not registered（登録していない、ユーザが望む何かかがある） */
register_this.fd = i;
register_this.events = ((fd_context-＞events) ^
(fd_context-＞userwanted));
if (write(context-＞eventport,
&register_this,
sizeof(register_this)) == sizeof(register_this)) {
/* The registration was successful, update some fields and continue.  The continue may not be needed, but it feels safer.（登録は成功した。いくつかのフィールドを更新して継続する。継続する必要はないかもしれないが、そのほうが安全な感じがする） */
fd_context-＞generation = context-＞generation;
fd_context-＞registered = 1;
fd_context-＞events = fd_context-＞userwanted;
eventport_registers++;
context-＞nfds += 1;
continue;
}
else {
/* The write failed, return an error. however, before we return, we have to go back and set those bits that need to be set in the fd_sets so the real call to select will actually have something to do!（書き込み失敗。エラーを戻す。しかし戻す前に戻って、実際のselectコールが実際に何かすることがあるように、fd_setsにおいてセットする必要があるこれらビットをセットする） */
eventport_regfail++;
return(1);
}      
}
}
return(0);
}
/*  This routine will use the state saved in the context to "rebuild" (we have the technology, we have the money...).  The fd_sets prior to calling the real select.  Therefore,  we do not call select with a bunch of zeroed-out fd_sets and sit there forever and a day.  This routine presumes that the context mutex is already locked when called.（このルーチンは、コンテキストに保存された状態を使用して、実際のselectを呼び出す前にfd_setsを「再構築」する（そうする技術もあるし金もある）。したがって、すべてゼロにセットされたfd_setsの集まりでselectを呼び出さず、よって永久にそこにいるということはない。このルーチンは、コンテキストmutexが、呼び出すときにすでにロックされているものと想定する） */
void
select_shim_rebuild_fd_sets(struct shim_context *context,
nfds_t nfds)
{
int i;
struct shim_fd_context *fd_context;
struct fd_set *readfds;
struct fd_set *writefds;
struct fd_set *errorfds;
ROUTINE_ENTRY_TRACE;
readfds = context-＞users_readfds_ptr;
writefds = context-＞users_writefds_ptr;
errorfds = context-＞users_errorfds_ptr;
for (i = 0; i ＜ nfds; i++) {
fd_context = &(context-＞shim_fd_contexts[i]);
if ((readfds) && 
(fd_context-＞userwanted & POLLIN)) {
FD_SET(i,readfds);
}
if ((writefds) && 
(fd_context-＞userwanted & POLLOUT)) {
FD_SET(i,writefds);
}
if ((errorfds) && 
(fd_context-＞userwanted & POLLERR)) {
FD_SET(i,errorfds);
}
fd_context-＞userwanted = 0;
}
}
/*  This routine will walk the events returned from the eventport and will dump some stuff about them to a debug file.（このルーチンはeventportから戻されたイベントをウォークし、イベントについてのいくつかをデバッグファイルにダンプする） */
void
select_shim_print_returned_events(struct shim_context *context,
struct dvpoll *dp_results,
nfds_t nfds) {
int fds_ready;
struct shim_fd_context *fd_context;
short matched_events;
pollfd_t *eventfds;
int i;
FILE *debugfile;
ROUTINE_ENTRY_TRACE;
fds_ready = 0;
eventfds    =  dp_results-＞dp_fds;
debugfile = fopen("/udir/debugstuff","a+");
if (debugfile == NULL) {
return;
}
for (i = 0; i ＜ nfds; i++) {
/*  So, was the event we got back from the eventport one in which the user was interested this time around? the fds in the list returned by the eventport are used as indices into the list of fds kept in the context.
If the generation in the fd in the context and the generation of the context match, then this was an fd in the user's fd_set array.
If not, this was an fd in which the user _used_ to have an interest but not at the present. 
（そうすると、eventportから戻したイベントは、ユーザが今回関心のあるものであったか？eventportによって戻されたリスト中のfdsは、コンテキストに保持されるfdsのリストへのインデックスとして用いられる。
　コンテキスト中のfdにおける生成とコンテキストの生成とがマッチングする場合、これは、ユーザのfd_set配列中のfdであった。
　マッチングしない場合、これは、ユーザが以前関心を持っていたが現在では関心がないfdであった） */
fd_context =  &(context-＞shim_fd_contexts[eventfds[i].fd]);
/* Generations must match, and the user's interest must be a subset of that for which we've registered.（生成はマッチングしなければならず、ユーザの関心は登録したもののサブセットでなければならない） */
matched_events = ((fd_context-＞userwanted) & 
(eventfds[i].revents));
fprintf(debugfile,
"event %d fd %d fd_ctx %p, usrwtd %x rvnts %x match %x cgen %d fdgen %d\n",
i,
eventfds[i].fd,
fd_context,
fd_context-＞userwanted,
eventfds[i].revents,
matched_events,
context-＞generation,
fd_context-＞generation);
}
/* OK, so maybe I am paranoid about the flush :)（ＯＫ、よって多分フラッシュについて考えすぎた：）） */
fflush(debugfile);
fclose(debugfile);
}
/*  This routine will take the events returned from the eventport ioctl, and for each of them find the corresponding fd_context struct in the context area provided. 
If the user was indeed interested in this fd (the generation numbers match) then we will
update the revents struct of their fd_set accordingly. 
If they were not interested we will do nothing with the event.
The routine will return the number of user-interested FDs found in the list returned from the eventport. it is up to the caller to decide what to do if that value is zero. 
This routine presumes that it is called with the context mutex locked.
（このルーチンは、eventport icotlから戻されたイベントをとり、それぞれについて、提供されたコンテキストエリアにおいて対応するfd_context structを見つける。
　ユーザが本当にこのfdに関心があった（生成番号がマッチングする）場合、それに従ってそれぞれのfd_setのrevents structを更新する。
　関心のないものであった場合、そのイベントについて何もしない。
　ルーチンは、eventportから戻されたリストに見られるユーザ関心FDの数を戻す。その値が０であった場合に何をするかは呼び出し元次第である。
　このルーチンは、コンテキストmutexがロックされた状態で呼び出されるものと想定する） */
int
select_shim_walk_returned_events(struct shim_context *context, 
struct dvpoll *dp_results,
nfds_t nfds) {
int fds_ready;
struct shim_fd_context *fd_context;
short matched_events;
pollfd_t *eventfds;
int i;
struct fd_set *users_fd_set_entry;
ROUTINE_ENTRY_TRACE;
fds_ready = 0;
eventfds    =  dp_results-＞dp_fds;
for (i = 0; i ＜ nfds; i++) {
/* So, was the event we got back from the eventport one in which the user was interested this time around? the fds in the list returned by the eventport are used as indices into the list of fds kept in the context.  If the generation in the fd in the context and the generation of the context match, then this was an fd in the user's fd_set array. 
If not, this was an fd in which the user _used_ to have an interest but not at the present.
（そうすると、eventportから戻したイベントは、ユーザが今回関心のあるものであったか？eventportによって戻されたリスト中のfdsは、コンテキストに保持されるfdsのリストへのインデックスとして用いられる。コンテキスト中のfdにおける生成とコンテキストの生成とがマッチングする場合、これは、ユーザのfd_set配列中のfdであった。
　マッチングしない場合、これは、ユーザが以前関心を持っていたが現在では関心がないfdであった） */
fd_context =  &(context-＞shim_fd_contexts[eventfds[i].fd]);
/* Generations must match, and the user's interest must be a subset of that for which we've registered.（生成はマッチングしなければならず、ユーザの関心は登録したもののサブセットでなければならない） */
matched_events = ((fd_context-＞userwanted) & 
(eventfds[i].revents));
if ((fd_context-＞generation == context-＞generation) &&
matched_events) {
/*  This was an fd of interest to the user, update the corresponding fd_set entry. it should not be necessary to check the users_mumble_ptrs as they should always be valid if there is a match on an event.（これはユーザが関心を有するfdであり、対応するfd_setエントリを更新する。イベントにマッチングがある場合、users_mumble_ptrsは常に有効なはずであるため、これをチェックする必要はないはずである） */
if (matched_events & POLLIN) {
FD_SET(eventfds[i].fd,context-＞users_readfds_ptr);
fds_ready += 1;
}
if (matched_events & POLLOUT) {
FD_SET(eventfds[i].fd,context-＞users_writefds_ptr);
fds_ready += 1;
}
if (matched_events & POLLERR) {
FD_SET(eventfds[i].fd,context-＞users_errorfds_ptr);
fds_ready += 1;
}
}
}
#ifdef DEBUG
if (fds_ready == 0) {
select_shim_print_returned_events(context,dp_results,nfds);
}
#endif /* DEBUG */
return(fds_ready);
}
【００９８】
SECTION 4:
/*  This routine, when implemented, will deregister fds with events from an eventport in which the user is no longer interested. it is anticipated that this routine will only be called when an eventport ioctl returns nothing but fd's that are not of interest to the user, so the caller can then go back and issue another ioctl with (presumably) only fd's that are of interest to the caller.  
This routine must _NEVER_ be called before the "rebuild" routine or some of the user's desired events will be lost! 
（このルーチンは、実施されると、ユーザがもはや関心のないイベントを有するfdsをeventportから登録解除する。このルーチンは、eventport ioctlが、ユーザにとって関心のないfdしか戻さない場合にのみ呼び出されるものと予想される。よって、呼び出し元は次に戻り、（おそらく）呼び出し元にとって関心のあるfdのみを有する別のioctlを発行する。
　このルーチンは、「rebuild」ルーチンの前に決して呼びだしてはならない。さもなくば、ユーザの望むイベントのいくつかが失われることになる）*/
void
select_shim_deregister_boring_fds(struct shim_context *context,
struct dvpoll *dp_results,
nfds_t nfds) 
{
struct shim_fd_context *fd_context;
pollfd_t *eventfds;
struct pollfd dereg_this;
int i;
int dereg_failure = 0;
ROUTINE_ENTRY_TRACE;
/* We can assume that anything in the list of results from the eventport ioctl were not of interest to the user, so all the entries in the list should be de-registered. we do not need to
access the users fd_set array like we do in  select_shim_walk_returned_events().（eventport ioctlからの結果のリスト中のものはすべてユーザにとって関心がないものであったと想定することができ、よってリスト中のすべてのエントリを登録解除すべきである。select_shim_walk_returned_events( )で行うように、ユーザfd_set配列にアクセスする必要はない） */
dereg_this.events = POLLREMOVE;
dereg_this.revents = 0; /* probably being pedantic */
eventfds = dp_results-＞dp_fds;
for (i = 0; i ＜ nfds; i++) {
/* Might as well go ahead and assume the dereg succeeds（先に進み、登録解除が成功したものと想定したほうがよい） */
fd_context = &(context-＞shim_fd_contexts[eventfds[i].fd]);
fd_context-＞generation = 0;
fd_context-＞registered = 0;
fd_context-＞events     = 0;
fd_context-＞userwanted = 0; 
dereg_this.fd = eventfds[i].fd;
if (write(context-＞eventport,
&dereg_this,
sizeof(dereg_this)) == sizeof(dereg_this)) {
/* Successful registration（登録成功） */
eventport_deregisters++;
context-＞nfds -= 1;
}
else {
/* Error, check the errno and do something based on that.  The dereg failed, pass a failure indication back to  the caller and call the "real" select this time around.（エラー。errnoをチェックし、チェックに基づいて何かを行う。登録解除が失敗し、失敗インジケーションを呼び出し元に渡し、今回は「実際の」selectを呼び出す） */
dereg_failure = 1;
printf("dereg failed for fd %d\n",dereg_this.fd);
eventport_deregfail++;
}
}
}
【００９９】
SECTION 5:
/*  This is the select shim. it is intended to intercept the user's call to select, and then poof, gee wiz, convert the user's select calls into eventport calls.（これはselect shimである。ユーザのselectコールをインタセプトし、次いでユーザのselectコールを検査し、驚くことにeventportコールに変換するように意図される） */
int 
select(int nfds, 
fd_set *readfds, 
fd_set *writefds, 
fd_set *errorfds,
struct timeval *timeout)
{
int ret;
int ret2;
int ret3;
struct pollfd devp_fds[SELECT_SHIM_NFDS_LIMIT];
/* Used in the dvp_struct to tell the ioctl where the return info should be placed.  We could    malloc this as we go and increase its size as we go, but we'll not bother and just     burn the RAM.  Another option would be to do a getrlimit on the hard limit to the number of FDs for this process.（dvp_structにおいて、リターン情報を配置すべき場所をioctlに教えるために使用される。途中でこれをmallocし、そのサイズを増大してよいが、ここではわざわざそうすることはせず、単にＲＡＭに焼き付ける。別のオプションは、このプロセスのFD数へのハードリミットに対するgetrlimitを行うことである。） */    
struct dvpoll dvp_struct; 
/* Used to communicate with the eventport（eventportとやりとりするために用いられる） */
struct shim_context *context; 
/* This will be the pointer to the shim_context associated with the users fds array.（これは、ユーザfds配列に関連するshim_contextへのポインタになる） */
int context_locked; 
/* Tell us whether or not we think the shim_context mutex is locked so we can try to do the right thing when we take the bypass.（迂回する際に正しいことを行おうとすることができるように、shim_context mutexがロックされていると考えるか否かを教える） */ 
dvp_struct.dp_fds = devp_fds;
/* We want to make sure that when/if we get to bypass that the ret values are "correct" for the different returns. The ret values are only checked in the bypass path when the context_locked flag is set.（迂回しなければならないとき／場合に、戻り値が様々なリターンにとって「正しい」ものであることを確実にしたい。ret値（ret value)は、context_lockedフラグがセットされている場合に迂回パスにおいてチェックされるだけである） */
ret = ret2 = ret3 = 0;
/* If the address of the "real" select call is not known, we can  assume that we've not been called yet.（「実際の」selectコールのアドレスがわからない場合、まだ呼び出されていないものと仮定することができる） */
if (real_select == NULL) {
pthread_once(&once_control,select_shim_initialize);
}
context_locked = 0; 
/* assume that we will not be able to use the eventport.（eventportを使用することができないものと想定する） */ 
select_calls++;
/* We really are not interested in the onsey-twosy calls to select()（select( )への１つや２つなどの呼び出しには実際に関心がない） */
if (nfds ＜ select_shim_nfds_threshold) {
nfds_below_threshold++;
goto bypass;
}
/* Similarly, if we are called with too many fds, we have to punt（同様に、fdsの多すぎる呼び出しの場合、戻る必要がある） */
if (nfds ＞ select_shim_nfds_limit) {
nfds_above_limit++;
goto bypass;
}
/* We only consider using the shim if the user has passed-in a non-NULL readfds ptr（ユーザが非ヌルreadfds ptrを渡した場合、shimを使用することのみを考える） */
if (readfds == NULL) {
goto bypass;
}
if ((context = select_shim_find_context(readfds)) != NULL) {
/* Continue and make sure that all the fds in the users fd_set array are registered with the eventport（継続し、確実にusers fd_set配列中のすべてのfdsがeventportに登録されるようにする） */
context_locked = 1;
context-＞generation += 1;
/* We don't have to add the user's readfds ptr since we found the context based on that :)（readfds ptrに基づいてコンテキストを見つけたため、ユーザのreadfds ptrを追加する必要はない） */
context-＞users_writefds_ptr = writefds;
context-＞users_errorfds_ptr = errorfds;
/* Select_shim_walk_and_ref_fds can find the fd_set ptrs in the context.（select_shim_walk_and_ref_fdsは、fd_set ptrをコンテキストにおいて見つけることができる） */
if (select_shim_walk_and_reg_fds(context, nfds) == 0) {
/* We know that the eventport has at least all the fds in which the user is interested registered, so go ahead and do the eventport ioctl().（ユーザが関心を有するすべてのfdsを、eventportに登録したことがわかるため、先に進み、eventoport ioctl( )を行う） */
dvp_struct.dp_nfds = context-＞nfds;
/* OK, now we have to convert the users timeval into a timeout, hopefully, keeping all the correct semantics.（ＯＫ、ここで、願わくはすべての正しいセマンティクスを保ちつつ、ユーザのtimevalをtimeoutに変換する必要がある） */
if (timeout != NULL) {
/* Thankfully, a valid timeval ptr pointing to a timeout of zero in select has the same semantics as a timeout of zero in poll :) so we can just do the math and be done with it（有り難いことに、selectにおける０のtimeoutを指す有効なtimeval ptrは、pollにおけるtimeout０と同じセマンティクスを有する：）ため、ただ数学を解いて終えることができる） */
dvp_struct.dp_timeout = (timeout-＞tv_sec * 1000);
dvp_struct.dp_timeout += (timeout-＞tv_usec / 1000);
}
else {
/* A NULL timeval pointer in select means to sleep indefinitely（selectにおけるヌルtimevalポインタは、無期限に眠ることを意味する） */
dvp_struct.dp_timeout = -1;
}
if ((ret = ioctl(context-＞eventport,
DP_POLL,
&dvp_struct)) ＞ 0) {
/* We have some fd's returned, walk the list and update the users fds array accordingly（fdがいくつか戻され、リストをウォークし、それに従ってusers fds配列を更新する） */
eventport_calls++;
if ((ret3 = select_shim_walk_returned_events(context,
&(dvp_struct),
ret)) ＞ 0) {
/* Happiness and joy - we got some events from the eventport for the user's fd_set array, so we can return.  However, we have to remember to unlock the context mutex first!-)（幸福と喜び−ユーザのfd_set配列のeventportからいくつかのイベントが戻されたため、戻ることができる。しかし、コンテキストmutexをまずアンロックすることを想起する必要がある） */ 
MUTEX_UNLOCK_TRACE(&(context-＞shim_context_mutex));
if ((ret2 = 
pthread_mutex_unlock(&(context-＞shim_context_mutex))) != 0) {
fprintf(stderr,
"Unable to unlock shim context pointer, errno %d, exiting!",
ret2);
fflush(stderr);
exit(-1);
}
evp_returned_fds++;
return(ret3);
}
else {
/* We either got nothing back or ran into some error.  For now, lets punt and deal with the deregistrations in the bypass path.（何も戻されなかったか、あるいはあるエラーが発生した。ここでは戻り、迂回パスでの登録解除に対処する） */
goto bypass;
}
}
else {
/* There was some sort of error and/or there were no fds returned from the ioctl (perhaps a timeout) precisely what we should do here is  anyone's guess. For now, go to the bypass.（ある種のエラーが発生した、かつ\またはioctlからfdsが戻されなかった（おそらくタイムアウト）。この場合に厳密に何をすべきかは、誰にも分からない。ここでは迂回する*） */
if (ret ＜ 0) {
evp_ioctl_errs++;
}
else {
evp_ioctl_no_fds++;
}
goto bypass;
}
}
else {
/* Either an eventport registration failed, or the user asked for something other than POLLIN on one of the FDs, so we need to punt and call the "real" select.（eventport登録が失敗した、あるいはユーザがFDの１つに対してPOLLIN以外を要求した。したがって、戻って「実際の」selectを呼び出す必要がある*\
\*ユーザのfdsアドレスに基づいてコンテキストを見つけることも、また割り当てることもできなった。よって「実際の」selectを呼び出す必要がある） */
goto bypass;
}
}
else {
/* We could neither find, nor allocate a context based on the user's fds address, so we have to call the "real" select.（ユーザのfdsアドレスに基づいてコンテキストを見つけることも、また割り当てることもできなった。よって「実際の」selectを呼び出す必要がある） */
goto bypass;
}
bypass:
/* For some reason or another, it was not possible to use eventports on this call to select. check and see if the context mutex is locked and if so, try to unlock it before we go into select() lest we end-up in a deadlock next time we are called. 
If the unlock fails, we aren't in Kansas anymore toto and we best click our heals together and say "There's no call like exit. There's no call like exit. There's no call like exit." and get the flock out of dodge :)  */
if (context_locked) {
/* We only want to try to rebuild the fd_sets when the context is locked. if we are at this point and the context is not locked, we have not done anything that should require trying to rebuild the fd_sets... famous last words :)
（何らかの理由により、このselectコールに対してeventportを使用することができなかった。コンテキストmutexがロックされているか否かをチェックして調べ、ロックされている場合、次に呼び出されるときにデッドロック状態にならないように、select( )に入る前にコンテキストmutexをアンロックするよう試みる。
　アンロックが失敗する場合には、トト、ここはカンザスじゃないみたい、ということで靴のかかとを打ち鳴らし「出口なんてコールはない、出口なんてコールはない、出口なんてコールはない」と唱えて逃げ出すのが最もよい：）*\
\*コンテキストがロックされている場合、fd_setsの再構築を試みたいだけである。この時点にいて、コンテキストがロックされていない場合、fd_setsの再構築試行に必要なことは何も終えていない・・・それはどうかな：）） */
select_shim_rebuild_fd_sets(context,nfds);
if ((ret ＞ 0) && (ret3 == 0)) {
/*  The ioctl returned events, but the walked said none were interesting.（ioctlはイベントを戻したが、上記をウォークしても関心のあるものはなかった） */
select_shim_deregister_boring_fds(context,&(dvp_struct),ret);
}
MUTEX_UNLOCK_TRACE(&(context-＞shim_context_mutex));
if ((ret2 = 
pthread_mutex_unlock(&(context-＞shim_context_mutex))) != 0) {
fprintf(stderr,
"Unable to unlock shim context pointer, errno %d, exiting!",
ret2);
fflush(stderr);
exit(-1);
}
}
if ((select_calls % SELECT_SHIM_DUMP_STATS) == 0) {
printf("calling the real select with:\n");
printf("\tnfds %d\n\treadfds %p\n\twritefds %p",nfds,readfds,writefds);
printf("\terrorfds %p\n\ttimeout %p\n",errorfds,timeout);
select_shim_stats();
}
/*  If we got here because we got nothing but uninteresting FDs from the eventport, if recursion is enabled, recurse back to our select() call and try again.  This is not quite as efficient as simply going back into the ioctl again, but the logic is simpler the way things are currently written, and the number of times we recurse _should_ be very small.（eventportからのFDが関心のないものだけであったためにここに来た場合、再帰が可能であれば、select( )コールに再帰して再試行する。これは、単にioctlに再び戻ることほど効率的ではないが、今ここに書かれている方法よりもロジックはより単純であり、再帰回数は非常に少ないはずである） */
if ((ret ＞ 0) && (ret3 == 0) && select_shim_recurse_enabled) {
select_shim_recursions++;
return (select(nfds,readfds,writefds,errorfds,timeout));
}
else {
/* Either it was some other bypass reason, or recursion was not enabled（ある他の迂回理由か、あるいは再帰が不可能であった） */
realselect_calls++;
return (int)(*real_select)(nfds,readfds,writefds,errorfds,timeout) ;
}
}
【０１００】
SECTION 6:
/* When an application calls close() on a filedescriptor, the kernel will automatically deregister it from any eventports.  However, the shim is not going to know unless it intercepts the call to close.  So, here we are, intercepting the call to close().  When the application calls close, we have to lock the global mutex, and then walk the list of active contexts. for each context, we lock the context mutex; if we find a  match with a registered FD, we have to clear-out that fd_context; then we unlock the context mutex and
move on. 
Once all the contexts have been searched, we call close() - we want to do this with the global context still held since we don't want any other call to select by some other thread in the app to come along before we are done with the call to close. this may be a bit overly paranoid of me, but at the moment it feels right.  Besides, apps should never be trying to close() and select() on the same FD at the same time anyway, so the possibility of contention on the mutex would be slim. 
（アプリケーションがフィールドスクリプタに対してclose( )を呼び出す場合、カーネルはあらゆるeventportsから自動的に登録解除する。しかし、shimは、closeコールをインタセプトしない限り知ることがない。よってここでは、close( )コールをインタセプトする。アプリケーションがcloseを呼び出すときには、グローバルmutexをロックし、次いでアクティブコンテキストリストをウォークする必要がある。各コンテキスト毎にコンテキストmutexをロックし、登録されたFDとマッチングが見つかる場合にはそのfd_contextを消去する必要があり、次いでコンテキストmutexをアンロックし、次に進む。
　コンテキストがすべて探索されてから、close( )を呼び出す。closeコールを終了する前に、アプリケーション中の他のあるスレッドによる他のいずれのselectコールも出現して欲しくないため、まだ保持されているグローバルコンテキストを使用してこれを行いたい。これは少し考えすぎかもしれないが、今のところは正しいと思う。その他に、mutex上で競合する確率を低くするために、アプリケーションは決して、同じFDに対してclose( )およびselect( )を同時に試行すべきではない）*/
int
close(int fildes) {
int i;
int ret;
struct shim_fd_context *fd_context;
/* Yes, we are checking for real_select rather than real_close - if one is not initialized, the other will not be, and if one is initialized, the other must be.  So, we just have to check for the one.（その通り、real_closeではなくreal_selectをチェックしている。一方が初期化されていない場合には他方も初期化されることはなく、また、一方が初期化されている場合には他方も初期化しなければならない。したがって、チェックする必要があるのは一方だけである） */
if (real_select == NULL) {
pthread_once(&once_control,select_shim_initialize);
}
close_calls++;
if (fildes ＜ select_shim_nfds_limit) {
/* It is theoretically possible that the shim has registered this FD with one or more eventports, so we best go make sure that we clear out the appropriate data structures.（理論上、シムがこのFDを１つまたは複数のeventportに登録することが可能である。よって、適切なデータ構造を消去するよう確実にすることが最もよい） */
MUTEX_LOCK_TRACE(&select_shim_global_mutex);
if ((ret = pthread_mutex_lock(&select_shim_global_mutex)) != 0) {
/* Something is seriously wrong, time to punt.（重大な異常あり。戻る） */
fprintf(stderr,
"selectshim: unable to lock select_shim_global_mutex, errno %d, exiting!\n", ret);
fflush(stderr);
exit(-1);
}
/* We only initialize contexts, we never "free" them, so the unallocated entries in the array (users_readfds_ptr == NULL)  should always be at the end of the array, and if we get to one, it means there is going to be no match with an existing entry.（コンテキストを初期化するだけであり、決して「解放」しないため、配列中の割り当てられていないエントリ（users_readfds_ptr==NULL)は常に配列の末尾にあるはずであり、これに達すると、これは既存のエントリとのマッチングがなくなることを意味する） */
i = 0;
while ((i ＜ SELECT_SHIM_MAX_CONTEXTS) &&
(select_shim_contexts[i].users_readfds_ptr != NULL)) {
close_evp_walks++;
/* Do not forget to lock the context mutex. once we have the  context mutex, and the global mutex, we know that no-one else can be doing anything :)（コンテキストmutexのロックを忘れないこと。一旦コンテキストmutexおよびグローバルmutexを持ってしまうと、他の誰も何もできなくなることを知っている：）） */
MUTEX_LOCK_TRACE(&(select_shim_contexts[i].shim_context_mutex));
if ((ret = pthread_mutex_lock(&(select_shim_contexts[i].shim_context_mutex))) != 0) {
/* Something is seriously wrong, time to punt.（重大な異常あり。戻る） */
fprintf(stderr,
"selectshim: unable to lock context mutex, errno %d, exiting!\n", i);
fflush(stderr);
exit(-1);
}
/*  If an FD actually registered in the context is being closed, we need to decrement the nfds count in the context.（コンテキストに登録されていたFDが実際に閉じられている場合、コンテキストにおけるnfdsカウントを減分する必要がある） */
fd_context = &(select_shim_contexts[i].shim_fd_contexts[fildes]);
if (fd_context-＞registered != 0) {
select_shim_contexts[i].nfds -= 1;
}
/* Now just go ahead and clear the fields regardless in case there was any slop.（ここで、ただ先に進み、スロップ(slop）がある場合に関わりなくフィールドをクリアする） */
fd_context-＞generation = 0;
fd_context-＞registered = 0;
fd_context-＞events = 0;
fd_context-＞userwanted = 0;
/* Now we need to unlock the shim_context mutex（ここで、shim_context mutexをアンロックする必要がある） */
MUTEX_UNLOCK_TRACE(&(select_shim_contexts[i].shim_context_mutex));
if ((ret = pthread_mutex_unlock(&(select_shim_contexts[i].shim_context_mutex))) != 0) {
/* Something is seriously wrong, time to punt.（重大な異常あり。戻る） */
fprintf(stderr,
"selectshim: unable to lock context mutex, errno %d, exiting!\n", i);
fflush(stderr);
exit(-1);
}
i++;
}
/* Now we can call close(), secure in the knowledge that we have removed all traces of it from the shim contexts.（ここで、シムコンテキストからすべての痕跡を除去したことがわかったため、安心してclose( )を呼び出すことができる） */
i = (int)(*real_close)(fildes);
/* Forgetting to unlock the mutex could ruin your whole day...（mutexをアンロックし忘れると、君の丸１日が無駄になるかも・・） */
MUTEX_UNLOCK_TRACE(&select_shim_global_mutex);
if ((ret = pthread_mutex_unlock(&select_shim_global_mutex)) != 0) {
/* Something is seriously wrong, time to punt.（重大な異常あり。戻る） */
fprintf(stderr,
"selectshim: unable to lock select_shim_global_mutex, errno %d, exiting!\n", ret);
fflush(stderr);
exit(-1);
}
return(i);
}
else {
/* This fd was beyond the limits of what we could have possibly registered, so just return the real_close.（このfdは、登録することが可能な限度を越えていた。よって、ただreal_closeを戻す） */
return (int)(*real_close)(fildes);
}
}
【産業上の利用可能性】
【０１０１】
　本発明は、コンピュータソフトウェアアプリケーションのパフォーマンスを向上させるために利用可能である。
【図面の簡単な説明】
【０１０２】
【図１】本発明の一実施形態による、本発明の実施形態を実施することのできる例示的なネットワーク環境の図である。
【図２】本発明の一実施形態による、本発明の実施形態を実施することのできるコンピュータシステムのブロック図である。
【図３】本発明の一実施形態による、再コンパイルすることなくソフトウェアアプリケーションにおけるシステムコールのパフォーマンスを向上させるプロセスのステップを示すフローチャートである。
【図４】本発明の別の実施形態による、再コンパイルすることなくソフトウェアアプリケーションにおけるシステムコールのパフォーマンスを向上させる別のプロセスのステップを示すフローチャートである。
【符号の説明】
【０１０３】
１５０・・・シムライブラリ、
１７３ａ、１７３ｂ・・・通信回線、
１９０ａ、１９０ｂ・・・クライアントコンピュータシステム、
１９１・・・サーバコンピュータシステム、
２０１・・・プロセッサ、
２０２・・・揮発性メモリ（ＲＡＭ）、
２０３・・・不揮発性メモリ（ＲＯＭ）、
２０４・・・データ格納装置、
２０５・・・表示装置、
２０６・・・文字数字入力装置、
２０７・・・カーソル制御装置、
２３５・・・ネットワーク通信装置、
【図１】
2004070948.tif 000004
【図２】
2004070948.tif 000005
【図３】
2004070948.tif 000006
【図４】
2004070948.tif 000007