この章では,開発環境に関する注意事項および問題点について説明するとともに,可能な場合には,それらの問題の解決方法を示します。 以下の項目について説明します。
プログラミング全般の注意事項を以下に示します。
6.1.1 bcopy,bcmp,および bzero の変更
bcopy
,bcmp
,および
bzero
システム関数の引数タイプは,ANSI 仕様に準拠するように変更されました。
新しいインタフェースのプロトタイプは,次のとおりです。
int bcmp __((const void *, const void *, size_t); int bcopy __((const void *, void *, size_t); int bzero __((void *, size_t);
以前のプロトタイプ定義を使用したい場合は,次のように
-D__V40_OBJ_COMPAT
コンパイル・フラグを指定してアプリケーションをコンパイルすることによって利用できます。
> cc -D__V40_OBJ_COMPAT test.c
6.1.2 struct utmp,struct utmpx および struct lastlog に対する変更
種々の UNIX およびインターネット標準に準拠するように,struct utmp
,struct utmpx
,および
struct lastlog
構造体が Version 5.0 でアップデートされました。
これらの変更は,/usr/include/utmp.h
,/usr/include/utmpx.h
,および
/usr/include/lastlog.h
ファイルに影響します。
6.1.3 getaddrinfo() ルーチンが間違った状態値を返す問題
下記のような状況では,getaddrinfo()
ルーチンはアプリケーションに間違った状態を返します。
ヒントのアドレス・ファミリが指定されていない場合 (PF_UNSPEC
),あるいはこのパラメータが NULL の場合,getaddrinfo()
ルーチンは間違って状態値
EAI_FAMILY
を返します。
getaddrinfo()
ルーチンは,下記のような状況では,状態値として間違って
EAI_SERVICE
を返します。
/etc/services
ファイルにサービスの名前として
servname
パラメータが指定されている。
ai_socktype
および
ai_protocol
addrinfo
構造体メンバが指定されていない。
/etc/services
ファイルで,servname
パラメータに指定されているサービスのみが TCP プロトコルを持つ。
これらの問題を回避するためには,res
ポインタが正しいことを確認してください。
6.2 POSIX スレッド・ライブラリ (pthreads)
DECthreads は POSIX スレッド・ライブラリに名称が変更されました。 このライブラリは,スレッド・アプリケーションのいくつかのクラスの性能を改善するために拡張されています。
この節では,POSIX スレッド・ライブラリに関する注意事項について説明します。
6.2.1 pthread_mutex_destroy() がロックされてない mutex に対して EBUSY を返す問題
POSIX スレッド・ライブラリ・ルーチン
pthread_mutex_destroy()
が返す状態値として最も可能性の高い状態値の 1 つとして EBUSY があります。
通常この状態値は,破棄される mutex が,現在ロックされているあるいは使用中であることを示しています。
ロック中あるいは使用中の mutex を破棄しようとするとアプリケーション・エラーが発生します。
ある特定のタイミングで,mutex がロックあるいは使用されていないにもかかわらず,pthread_mutex_destroy()
が間違って EBUSY を返す場合があります。
このような場合,mutex は破棄されません。
アプリケーションが EBUSY 状態値を検知すると,pthread_mutex_destroy()
呼び出しが繰り返されます。その後実行される呼び出しは,成功する場合もあれば,再度 EBUSY が返される場合もあります。最終的には,呼び出しは成功するはずですが,呼び出しの失敗が繰り返されると,若干のメモリ・リークが発生します。
6.2.2 stackaddr スレッド作成属性の使用に関する注意事項
スレッドにユーザ独自のスタックを割り当てることを可能にする
stackaddr
スレッド作成属性の使用はお勧めできません。
POSIX および統一 UNIX 仕様 Version 2 で定義されているこの属性のセマンティクスは,不十分です。
その結果,この属性を使うコードでは実装間の移植性が失われる傾向があります。
開発者が,マシン・アーキテクチャと実装について細部まで知識を持っており,割り当てられたスタックに相対的に指定するための正しいアドレスを知っている必要があるので,信頼して使用するのが難しい属性です。
インタフェースが十分な情報を提供しないので,実装は不適切な値があることを診断できません。
不適切な値を使用すると,原因を特定できないプログラムの異常が発生する可能性があります。
ユーザ自身のスレッド・スタックを用意したい場合は,pthread_attr_setstackaddr_np()
ルーチンの使用を検討してください。
標準のインタフェースにおける最悪の事態を回避するために,呼び出し側からは,ベース・アドレスおよびサイズを使用してスレッド・スタックを指定します。
6.2.3 メモリ割り当てに関する問題
古い Alpha プロセッサ (21264 チップより前のもの) は,最低でクォドワード (8 バイト) の単位でメモリにアクセスできますが,それぞれが 8 バイトよりも小さい複数の変数が,メモリ内で同一のクォドワードを占有することができます。 このような場合,2 つ以上のスレッドが同一のクォドワードを読み取り,そのクォドワードの別々の部分を更新してから個別にそれぞれのコピーをメモリに書き戻すと,マルチスレッド・プログラムで問題が発生する可能性があります。 クォドワードに書き込む最後のスレッドは,それまでにクォドワードの他の部分に書き込まれたデータを上書きします。 この問題は,それぞれのスレッドが独自の相互排他でクォドワードのそれぞれの部分を保護している場合も発生します。
Tru64 UNIX C コンパイラは,メモリ内のスカラ変数にクォドワード (8 バイト) 境界を割り当てることで,この問題からスカラ変数を保護しています。 ただし,構造体や配列のような複合型のデータ・オブジェクトでは,コンパイラはそれら自体が持つ境界にメンバを割り当てます。 たとえば,2 バイトのメンバは 2 バイト境界で割り当てられます。 このため,合計で 8 バイトまたはそれよりも少ない複合型オブジェクトに隣接するメンバは,メモリ内で同一のクォドワードを占有する可能性があります。
マルチスレッド・アプリケーションのコードを調べて,メモリ内で同一のクォドワードを共有する可能性のある隣接メンバを持つような,複合型データ・オブジェクトがあるかどうかを確認してください。 そのようなオブジェクトが存在する場合は,メンバ変数を 8 バイト以上の変数に再定義することで,または,合計で 8 バイトになるように変数の後ろに十分な埋め込み記憶域を定義することで,それぞれのメンバ変数の割り当てをクォドワード境界に強制することをお勧めします。
代替案として,隣接メンバがメモリ内で同一のクォドワードを共有できるような各複合型データ・オブジェクトに対して,1 つの相互排他を作成することで対処することもできます。 この相互排他を使って,複合型データ・オブジェクトに対するすべてのスレッドによるすべての書き込みアクセスを保護します。 ただし,このテクニックは,性能を考慮するとあまり望ましいものではないかもしれません。
詳細については,『Guide to POSIX Threads Library』を参照してください。
6.2.4 POSIX スレッド・ライブラリの pthread_debug() および pthread_debug_cmd() ルーチン
より包括的で強力なスレッド・デバッグ環境を可能にするために,pthread_debug()
ルーチンと
pthread_debug_cmd()
ルーチンが削除されています。
既存のバイナリ・コードで障害が起きないようにこれらのルーチンは今後も認識されますが,これらのルーチンを呼び出しても,呼び出し側のプログラムに対する即時リターンになります。
pthread_debug_cmd()
ルーチンは,正常終了を示す 0 (ゼロ) を戻します。
これらのルーチンがこれまでに提供していた機能は,Ladebug や TotalView などのデバッガで提供します。
6.2.5 プロセス共有の同期化オブジェクトのデバッグ
POSIX スレッド・ライブラリ (pthread) インタフェースは,複数の協調プロセスで実行されているスレッドで,特定の同期化オブジェクト (相互排除,条件変数,および読み取り書き込みロック) の共有をサポートするようになりました。 このようなオブジェクトを,プロセス共有オブジェクトと呼びます。
本リリースでは,プロセス共有オブジェクトは,Ladebug デバッガでは認識できません。
たとえば,Ladebug の
show mutex
コマンドを実行すると,
プロセス共有の相互排除ではなく,プロセス固有の相互排除がリストされます。
6.2.6 errno の使用
マルチスレッド・アプリケーションの最初のスレッドあるいは省略時のスレッドは,perthread
errno
の代りにグローバル
errno
セルを使用します。
Version 5.1 以降,(たとえば,非スレッド・セーフ呼び出しにより,あるいは
errno
シンボルを使用する間違ったコンパイル済みコードによって) 最初のスレッド以外のスレッドがグローバル
errno
セルを使用すると,最初のスレッドの値を破壊してしまいます。
適切にコンパイルされたバイナリ,あるいは POSIX スレッド・ライブラリを使用する既存のバイナリは,この変更の影響を受けません。
6.3 カーネル・プログラミング
この節では,カーネル・プログラミングに関する注意事項について説明します。
6.3.1 システム・コール・ファネリング
独自のシステム・コール・ハンドラを埋め込んだ他社のカーネル・モジュールを開発あるいは保守しており,そのハンドラがファネリング (プライマリ CPU に限定して実行) を必要とする場合,ハンドラ関数にファネリング・フックを追加する必要があります。
ハンドラの開始点に
unix_master
() 呼び出しを追加し,終了点に
unix_release
() 呼び出しを追加してください。
6.3.2 ATM カーネル・プログラミング・インタフェースの変更
ポイント・ツー・マルチポイント仮想回路 (VC) に必要な機能をサポートし,将来の機能拡張に備えるため,atm_cmm_register_cvg()
および
atm_cmm_register_sig()
ルーチンのパラメータが変更されました。
以前にコンパイルされたモジュールとのバイナリ互換性は維持されています。 収束モジュールおよびシグナル・モジュールについては,本リリースのオペレーティング・システムで再コンパイルする際にソース・コードの一部を少し変更する必要があります。
詳細については,『Asynchronous Transfer Mode』を参照してください。
6.3.3 カーネル内部の例外フレームの変更
カーネルの例外フレームのフォーマットは,スタック・ポインタのレジスタ値を保存するために使用されていて,使用されなくなった 8 バイトのクォドワードを削除することで,264 バイトから 256 バイトにサイズが削減されました。
このレジスタ・レイアウトはカーネル・スタック上での例外にのみ使用されるので,この変更はユーザの領域には影響しません。
ただし,カーネルのクラッシュ・ダンプをデバッグする際に,例外フレームの内容を表示する必要が生じた場合は,新しい 32 レジスタ・フォーマットでデータを解釈する必要があります。
6.3.4 VFS プログラミング・インタフェースの変更
VFS ネーム・キャッシュは,プロセッサ間で複製されるようになり,オーバヘッドが低下しスケーラビリティが向上しました。
他社のファイル・システムを開発する場合は,VFS ネーム・キャッシュとの同期を考慮しなければなりません。
特に,ファイルの削除や名前の変更を行う場合は,そのファイルに対して
cache_purge()
カーネル・コールを呼び出してください。
namei()
カーネル・コールは自分のネーム・キャッシュからエントリを削除するだけです (DELETE
または
RENAME
フラグを付けて呼び出された場合)。
cache_purge()
カーネル・コールはすべてのネーム・キャッシュでそのエントリを無効にします。
ファイルの名前を変更する場合は,ディレクトリに新しい名前のエントリを追加する前に,元のターゲット・エントリに対して
cache_purge()
カーネル・コールを呼び出してください。