AIX トランザクション・メモリー・ プログラミング

トランザクション・メモリー (TM) は、その他のプロセス・スレッドや アプリケーションからアトミックに見えるストレージ操作を、 プロセス・スレッドが実行できるようにする共有メモリー同期構造です。

概説

TM は、ロック・ベースのコードのクリティカル・セクションを、ロックをかけずに実行できる構造です。 IBM® POWER 8 プロセッサーは、 TM プログラミングを実装した最初のプロセッサーです。

TM 機能は、 以下の一部のシナリオで使用します。
  • ロック・ベースのアプリケーションのオプティミスティック実行 – TM は、ロックを獲得せずに、コードのクリティカル・セクションの投機的実行をサポートします。 この方法には、パフォーマンスに適した調整がされていない 現行のロックを使用して、アプリケーションにきめ細かくロックをかけられるという利点が あります。
  • 高水準言語でのトランザクションのプログラミング – トランザクション・プログラミング・モデルは、ロック・ベースの共有メモリー・プログラムに比べて高い生産性が得られる、業界全体の標準として普及しつつあります。
  • チェックポイント/ロールバックの使用 – TM は、アーキテクチャーの状態を復元するためのチェックポイントとして使用されます。 この方法を使用して、 ランタイム・コードの最適化または生成時の予測的コンパイラー最適化、およびチェックポイントのシミュレーションを 使用可能にします。

TM 機能を使用するために、プロセス・スレッドは、 ストレージ・アクセスやトランザクションのシーケンスの最初と最後に、tbegin. 命令および tend. 命令を使用してマークを付けます。 tbegin. 命令は、トランザクション実行を開始します。 トランザクション実行中に、ロードおよび保管はアトミックに発生するように見えます。 tend. 命令は、トランザクション実行を終了します。

トランザクションが 完了前に停止すると、tbegin. 命令の 実行後に行われたストレージ更新は ロールバックされます。同様に、レジスターのサブセットの内容も tbegin. 命令が実行される前の状態に ロールバックされます。トランザクションが完了前に停止すると、ソフトウェア障害ハンドラーが 開始されます。障害は、一時的なタイプの可能性または永続的なタイプの 可能性があります。障害ハンドラーは、トランザクションを再試行するか、 障害の性質に応じて異なるロック構造または論理パスの採用を 選択することができます。

AIX® オペレーティング・システムは、 TM の使用をサポートし、これにはコンテキスト・スイッチおよび割り込みを網羅する TM 状態管理処理が 含まれます。

チェックポイント状態

トランザクションが開始されると、 プロセッサーのチェックポイント状態を表すレジスター・セットが 保存されます。トランザクションで障害が発生した場合、レジスター・セットは、 トランザクション開始前の時点に復元されます。プロセッサーのチェックポイント状態は、 トランザクション開始前状態とも 呼ばれます。チェックポイント状態には、問題プログラム状態書き込み可能レジスター (CR0FXCCEBBHREBBRRBESCR のレジスターを除く)、パフォーマンス・モニター・レジスター、および TM SPR が含まれます。

注: 監視プログラム状態または問題プログラム状態を 経由してチェックポイント状態に直接的に至ることは できません。
チェックポイント状態は、 新規の treclaim. 命令が実行されると、それぞれのレジスターに コピーされます。このプロセスを使用して、特権コードは値の保存または変更を 行うことができます。チェックポイント状態は、 新規の trechkpt. 命令が実行されると、ユーザー・アクセス可能なそれぞれのレジスターから 見込みレジスターに再度コピーされます。
以下の TM SPR は、プロセッサーの マシン状態に追加されます。
名前 名称 説明 特権 mtspr 特権 mfspr サイズ (ビット) SPR
FSCR 機能の状況および制御のレジスター 問題プログラム状態にある使用可能な機能を 制御するとともに、機能使用不可割り込みの原因を示します。 yes あり 64 153
TEXASR トランザクションの例外および要約のレジスター トランザクション障害ハンドラーで使用される、 トランザクション・レベル情報および要約情報が入っています。ビット 0 から 31 には、 障害の原因が入っています。 なし なし 64 130
TFHAR トランザクション障害ハンドラー・アドレス・レジスター ソフトウェア障害ハンドラーの EA を記録します。 TFHAR レジスターは、トランザクションを開始した tbegin. 命令用に 常に NIA に設定されます。 なし no 64 128
TFIAR トランザクション障害命令アドレス・レジスター 障害の原因となった命令の正確な EA を 設定します (可能な場合)。TFIAR レジスターの正確性は、 TEXASR レジスターの「正確」フィールド (ビット 37) に記録されます。 なし no 64 129
TEXASRU トランザクションの例外および要約のレジスター (上位半分) TEXASR レジスターの上位半分。 no なし 32 131
新規の TEXASR レジスターには、 トランザクションの状態およびトランザクション障害の原因に関連する情報が入っています。 以下の表では、TEXASR レジスターに含まれるフィールドについて説明します。
名前 フィールド 値の意味 ビット
TEXASR 障害コード (注: ビット 7 は「障害の永続」フィールドと 呼ばれる) トランザクション障害コード 0:7
不許可 0b1 - アクセス・タイプの命令は許可されません。 8
ネスティング・オーバーフロー 0b1 - 最大トランザクション・レベルを超えました。 9
フットプリント・オーバーフロー 0b1 - トランザクション・ストレージ・アクセスのトラッキング限度を 超えました。 10
自己誘発競合 0b1 - 自己誘発競合が中断状態で 発生しました。 11
非トランザクション競合 0b1 - 他のプロセッサーによる非トランザクション・アクセスと 競合が発生しました。 12
トランザクション競合 0b1 - 別のトランザクションと競合が発生しました。 13
変換無効化競合 0b1 - TLB 無効化と競合が発生しました。 14
実装固有 0b1 - トランザクション失敗の原因となった 実装固有の状態。 15
命令取り出し競合 0b1 - スレッドによる命令取り出しまたはトランザクションにより以前書き込まれた ブロックから実行された別のスレッドによる 命令取り出し。 16
今後の障害事例用に予約済み   17:30
異常終了 0b1 – 特定の TM 命令の実行が原因で中止されました。 31
中断状態 0b1 – 中断状態で障害が記録されました。 32
予約済み   33
特権 障害記録時にスレッドは 特権状態 ([MSRHV||PR]) でした。 34:35
障害要約 (FS) 0b1 - 障害が検出されて記録されました。 36
TFIAR 正確

0b0 - 「TFIAR」フィールドの値は概算値です。

0b1 - 「TFIAR」フィールドの値は 正確な値です。

37
ROT

ROT 以外の tbegin. 命令が実行されると、 0b0 に設定されます。

ROT が開始されると 0b1 に設定されます。

38
予約済み   39:51
トランザクション・レベル (TL) アクティブなトランザクションのトランザクション・レベル (ネストの深さ + 1) には、 以下の値が入ります。
  • 最新のトランザクションが正常に終了した場合は 0。
  • 最新のトランザクションが正常に終了しなかった場合は、 そのトランザクションが失敗した時点のトランザクション・レベル。
注: 1 という値は、外部トランザクションに対応します。 1 より大きい値は、ネストされたトランザクションに対応します。
52:63
注:
  • トランザクション障害が記録されると、TEXASR レジスターの 8 ビットから 31 ビットの範囲にある 1 ビットのみが設定されます。 設定される単一ビットは、 特定の命令やイベントが原因で障害が発生したことを示します。
  • トランザクションのみロールバック (ROT) は、1 つの単位としてのみ実行され、それ以外は実行されない一連の命令です。 この構造により、大量の命令を最小のコストで予測的に実行することが可能になります。ROT は、通常のトランザクションとしてのアトミックな性質 (通常のトランザクションの同期化属性および逐次化属性) を完全には備えていません。 したがって、ROT を共有データの操作に使用してはなりません。

ソフトウェア障害ハンドラー

トランザクションが失敗すると、 マシン・ハードウェアは、最外部トランザクションに関連付けられている障害ハンドラーに制御を リダイレクトします。トランザクションが失敗すると、 制御は tbegin. 命令の後の命令にリダイレクトされ、 CR0 は次のように設定されます。
0b101 || 0
または
0b010 || 0
したがって、 tbegin. 命令の後の命令は、 CR0 のビット 2 に指定されたブランチ命令でなければなりません。例えば、 tbegin. 命令が実行されると beq ブランチ命令が CR0 のビット 2 に指定されます。ブランチのターゲットは、トランザクション失敗を処理する コード・セクションにする必要があります。トランザクション開始時に tbegin. 命令が 正常に実行されると、CR0 は 次のいずれかに設定されます。
0b000 || 0 or 0b010 || 0
注: TEXASR の ビット 0 から 31 は、障害の原因を報告します。 ビット 0 から 7 の障害コード (FC) フィールドは、 以下のシナリオで使用されます。
  • treclaim. 命令を使用することにより、特権スーパーバイザー・コードまたは特権ハイパーバイザー・コードで 障害を発生させる。
  • tabort. 命令の形式を使用することにより、問題プログラム状態のコードで障害を発生させる。
TEXASR の ビット 7 に 1 の値がある場合は、障害は永続的であるため、トランザクションが再試行されると 失敗することを表します。AIX オペレーティング・システムで 予約された障害コードは、/usr/include/sys/machine.h. ディレクトリーに定義された 障害の原因を示します。

サンプル・トランザクション

以下のアセンブラー・コード例は、GPR 5 内の値を GPR 4 内のアドレスに書き込む単純なトランザクションを示しており、これは、複数のスレッド実行で共有されるものと想定されています。永続的な原因によりトランザクションが失敗すると、 このコードは lock_based_update ラベルにある別のコード・パスにフォールバックします。 代替パスのコードは表示されていません。
trans_entry:
  tbegin                             # Start transaction
  beq          failure_hdlr          # Handle transaction failure
  stw          r5, 0(r4)             # Write to memory pointed to by r4.
  tend.                              # End transaction
  b            trans_exit
failure_hdlr:                        # Handle transaction failures:
  mfspr        r4, TEXASRU           # Read high-order half of TEXASR
  andis.       r5, r4, 0x0100        # Is the failure persistent?
  bne          lock_based_update     # If persistent, acquire lock and 
                                     # then perform the write.
  b            trans_entry           # If transient, try again.

lock_based_update:

trans_exit:

トランザクション・メモリー機能のランタイム判別

プログラムでは、POWER ISA の TM カテゴリーをシステムがサポートするかどうかを、 getsystemcfg サブルーチンを使用して SC_TM_VER システム変数を読み取ることにより判断できます。 プログラム内の TM 機能を判別するために、__power_tm() マクロが /usr/include/sys/systemcfg.h ファイルに 提供されています。このマクロが役に立つのは、 TM 機能がある時に TM 機能を条件付きで使用するソフトウェア、 または TM 機能がない時にロック・ベースのコード・パスと同等の機能を 使用するソフトウェアの場合です。

拡張コンテキスト構造

ベクトル状態およびユーザー・キーを サポートするための拡張コンテキスト構造のサポートは、 以前のバージョンの AIX オペレーティング・システムで 導入されました。既存の拡張コンテキスト構造の サポートはさらに拡張されて、TM に必要なマシン状態を サポートします。

拡張コンテキストは、トランザクション・プロセス・スレッドが最初に TM を使用する時に、 スレッドごとに割り振られて固定されます。拡張コンテキスト領域の 割り振りおよび固定を行えないと、プロセスは、プロセスを終了させる SIGSEGV シグナルを 受け取ります。

マシン・コンテキスト情報は、シグナル・ハンドラーに提供される sigcontext 構造に 含まれています。シグナル・ハンドラーが戻ると、 sigcontext 構造に存在するマシン・コンテキストが アクティブになります。sigcontext 構造は、実際はより大きな ucontext 構造のサブセットです。 この 2 つの構造は sizeof(struct sigcontext) までに関しては同じです。 AIX オペレーティング・システムがシグナル・コンテキストを 作成してシグナル・ハンドラーに受け渡されるようにすると、ucontext 構造がシグナル・ハンドラーのスタック上に 作成されます。シグナル・コンテキストのマシン・コンテキスト部分には、 アクティブなマシン状態すべて (意識せずに中断された コンテキストの揮発性および不揮発性の状態を 含む) が含まれている必要があります。ucontext 構造には、 拡張コンテキスト情報を使用できるかどうかを判別するインジケーターが 含まれています。

ucontext 構造内の __extctx フィールドは、 /usr/include/sys/context.h ファイルに定義された拡張コンテキスト構造のアドレスです。 ucontext 構造内の __extctx_magic フィールドは、 __extctx_magic フィールドの値が __EXTCTX_MAGIC と等しい場合に 拡張コンテキスト情報が有効かどうかを示します。 TM 機能を使用するスレッドの追加のマシン状態は、コンテキスト拡張のメンバーとして 復元されて、シグナルの引き渡しと戻しの一部である ucontext 構造に 保存されます。

アプリケーションは、トランザクション・メモリーの使用を明示的に使用可能にした場合、コンパイラーによる __EXTABI__ の暗黙的定義によって組み込まれる __extctx フィールド用のスペースを既に持つ、拡張サイズの ucontext 構造を選択します。 拡張 ucontext 構造は、 __AIXEXTABI を明示的に定義することによって選択することもできます。

トランザクション状態または中断状態にある場合、libc のサブルーチンgetcontext()setcontext()makecontext()、 および swapcontext() は、 サポートされません。トランザクション内でサブルーチンが呼び出されると、 サブルーチン getcontext()setcontext()makecontext() では、 TM_LIBC タイプの永続的トランザクション障害が発生します。 この障害は /usr/include/sys/machine.h ファイルに定義されています。

swapcontext() サブルーチンが トランザクション内で呼び出されると、 以下のような動作になります。
  • swapcontext() サブルーチンがトランザクション状態の場合、 TM_LIBC タイプの永続的なトランザクション障害が発生します。
  • swapcontext() サブルーチンが中断状態の場合、 トランザクションは失敗し、指定された ucontext 構造がスワップインされて、 指定された ucontext 構造によりプログラムの実行が再開されます。 swapcontext() サブルーチンが戻った後の結果の状態および後続の動作は 定義されていません。

サブルーチン getcontext()setcontext()、 および swapcontext() がトランザクション状態以外で呼び出されると、 サブルーチンは、ucp または oucp パラメーターで指し示される ucontext 構造との間で拡張 TM コンテキストの 取得も復元も行いません。 現在の拡張 TM コンテキストを使用して setcontext() サブルーチンまたは swapcontext() サブルーチンが 呼び出される場合、エラーは発生しません。

拡張コンテキストについて詳しくは、 /usr/include/sys/context.h ヘッダー・ファイルを参照してください。

シグナルの送達

トランザクション中、アプリケーションが受け取った非同期シグナルは非トランザクション状態で送達されます。トランザクション状態の場合、同期シグナルの送達は 許可されないだけではなく、/usr/include/sys/machine.h ファイルに定義されている TM_SYNC_SIGNAL タイプの永続的トランザクション障害が 発生します。

位置合わせ割り込みおよびプログラム割り込み

トランザクション状態では、 正しくない操作または、 TM_ALIGN_INT タイプまたは TM_INV_OP タイプの 永続的トランザクション障害 (/usr/include/sys/machine.h ファイルに定義) のエミュレーション結果が 要求される操作が原因で、位置合わせ割り込みおよびプログラム割り込みが発生します。 中断状態の場合、位置合わせ割り込みおよびプログラム割り込みは、非推定セマンティクスを使用して正常に処理されます。

システム・コール

システム・コールは、トランザクション内で 起動しないことをお勧めします。システム・コールがトランザクション内でサポートされるのは、 トランザクションが tsuspend. 命令により 中断される場合のみです。

プロセッサーまたはスレッドがトランザクションを処理しており、 そのトランザクションが中断されない間にシステム・コールが呼び出されると、 システム・コールは AIX カーネルによって起動されず、関連するトランザクションは 永続的に失敗します。このエラーが発生すると、TEXASR レジスターの FC フィールドには TM_ILL_SC 障害コードが入ります。このコードは、 /usr/sys/include/machine.h ファイルに定義されています。

アプリケーション・プログラマーが トランザクションを明示的に中断している場合、中断された トランザクション配下で実行されるいずれの操作も持続するものと 見なされます。中断状態の間に起動されたシステム・コールにより実行される操作はいずれも、トランザクションが失敗した場合でもロールバックされません。

AIX オペレーティング・システムは、 トランザクション状態の間のシステム・コールの実行をサポートしていません。これは、システム・コールの背後で AIX により実行されるあらゆる操作 (入出力を含む) をロールバックする方法がないためです。

setjmp() サブルーチンおよび longjmp() サブルーチン

libc の setjmp() サブルーチンおよび longjmp() サブルーチンは、 トランザクション状態または中断状態ではサポートされません。これは、ジャンプ・バッファーの設定およびバッファーへのジャンプ・バックの影響があるためです。 以下のシナリオを考えてみます。
  1. setjmp() サブルーチンがトランザクション内で呼び出され、 対応する longjmp() サブルーチンがトランザクション終了後に 呼び出されると、これは、現在は無効になっている見込み状態に 対してのジャンプです。
  2. setjmp() サブルーチンがトランザクションより前に 呼び出されると、対応する longjmp() サブルーチンは、 トランザクションの実行結果が終了、失敗、または異常終了であるかどうかに 関わらず、トランザクションが開始される前の状態にジャンプします。
  3. setjmp() サブルーチンがトランザクション内で 呼び出され、その後でトランザクションが異常終了すると、setjmp() サブルーチンにより 行われたジャンプ・バッファーへの更新は、行われていないように 見えます。

setjmp() サブルーチンがトランザクション内で 呼び出されると、/usr/include/sys/machine.h ファイルに定義されている TM_LIBC タイプまたは TM_ILL_SC タイプの永続的トランザクション障害が 発生します。

longjmp() サブルーチンがトランザクション内で呼び出されると、以下のような動作になります。
  • longjmp() サブルーチンがトランザクション状態の場合、 /usr/include/sys/machine.h ファイルに定義されている TM_LIBC タイプまたは TM_ILL_SC タイプの永続的トランザクション障害が発生します。
  • longjmp() サブルーチンが中断状態の場合、 トランザクションは失敗し、指定されたジャンプ・バッファーが復元されて、プログラムの実行は 対応する setjmp() サブルーチンに戻ります。 setjmp() サブルーチンが longjmp() サブルーチンから 戻った後の結果の状態および後続の動作は定義されていません。

コンパイラー

トランザクション・メモリーを サポートする AIX オペレーティング・システムのコンパイラーは、 AIX ABI に準拠している必要があります。TM が使用可能な場合、 C または C++ のコンパイラーは、 __EXTABI__ を事前定義する必要があります。 詳しくは、コンパイラーの資料を参照してください。

アセンブラー

AIX オペレーティング・システムの アセンブラーは、/usr/ccs/bin/as にあり、 POWER ISA 内の TM 用に定義され、 POWER8 プロセッサーにより実装された追加の命令セットをサポートします。ソース・ファイル内で –m pwr8 アセンブリー・モードまたは .machine pwr8 疑似 op を使用して、TM 命令のアセンブリーを可能にすることができます。 詳しくは、アセンブリー言語解説書を参照してください。

デバッガー

/usr/ccs/bin/dbx デバッガーは、 TM プログラムのマシン・レベルのデバッグをサポートします。このサポートには、新規のトランザクション・メモリー命令の逆アセンブルと、 TM SPR (TEXASRTEXASRUTFIAR、および TFHAR レジスター) の表示が含まれます。

トランザクション内に ブレークポイントを設定すると、トランザクションは、ブレークポイントが検出されるたびに必ず無条件に失敗します。したがって、推奨される方法は、失敗しているトランザクションをデバッグしてトランザクションの障害ハンドラーにブレークポイントを設定し、ブレークポイントが検出された時点で TEXASR レジスターおよび TFIAR レジスターを表示して障害の原因と場所を特定することです。

dbx では、TEXASRTFIAR、 および TFHAR のレジスターは、$texasr$tfiar、または $tfhar のパラメーターを指定した print サブコマンドを使用して表示することができます。TFIAR レジスター、 および TFHAR レジスターで検出されたアドレスに関連するコード行は、 次の例のような list サブコマンドを使用して表示できます。
(dbx) list at $tfiar
dbx tm_status サブコマンドは、 TEXASR レジスターの内容の 表示および解釈を行うために使用されます。このサブコマンドは、トランザクション障害の 特性を判別するために使用されます。

サード・パーティーのデバッガーは、 スレッドの TM 状態を読み取るための新しい PTT_READ_TM ptrace 操作の形式で使用できます。詳しくは、 ptrace の資料を参照してください。

トレース・サポート

AIX トレース機能は、 AIX オペレーティング・システムで実行される TM 操作用の一連のトレース・イベントを含むように拡張されており、これには、 トランザクション障害の原因となる優先使用およびトランザクション障害の原因になる可能性のある その他のさまざまな操作が含まれています。トレース・イベント ID 675 を trace コマンドおよび trcrpt コマンドへの入力として使用し、 TM 関連のトレース・イベントを表示できます。

コア・ファイル

AIX オペレーティング・システムは、 TM を使用する、プロセス用またはスレッド用コア・ファイルの 一部としての TM マシン状態の取り込みもサポートします。プロセスまたはスレッドが TM を使用している場合、または使用していた場合は、TM マシン状態がそのスレッドの コア・イメージに含まれます。
注: TM 状態は、 AIX オペレーティング・システムの現在のコア・ファイル・フォーマットのみで サポートされます。dbx コマンドを使用して、 TM 対応コア・ファイルの TM マシン状態を読み取って表示することができます。

AIX スレッド・ライブラリー

トランザクション・メモリーの使用は、 M:N スレッドを使用するアプリケーションではサポートされません。複数のスレッドが単一カーネル・スレッドを 共有する環境では、トランザクション・スレッドで未定義の動作が 発生する可能性があります。M:N スレッドを使用するアプリケーションで トランザクション・メモリーを使用すると、 TM_PTH_PREEMPTED の障害コードが TEXASR レジスターに設定されて、 永続的トランザクション障害になるおそれがあります。