PM アプリケーションプログラムインタフェース Ver. 1.2

[英語版], [日本語版]

  1. 初期化

  2. コンフィギュレーション

  3. メッセージ送信

  4. メッセージ受信
  5. リモートメモリアクセス
  6. ネットワークコンテキストスイッチ

  7. その他

  8. PM v1.0 互換エントリ

  9. サンプルプログラム

  1. 初期化
    NAME
    _pmInit - Myrinet インタフェースの初期化

    SYNOPSYS
    int _pmInit(int unit, char *mcp, char *config)

    DESCRIPTION
    Myrinet インタフェース unit に LANaiプログラム mcp を ロードし、 config ファイルからルーティング情報を初期化します。 ホスト上で最初に一度だけ行なう必要があります。

    RETURN VALUES
    _pmInit は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    unitの値が範囲を越えている。
    ENOENT
    LANai プログラムあるいはコンフィギュレーションファイルがない。
    ENODEV
    ユニット unit の Myrinet デバイスが存在しない。
    Myrinet インタフェースを mmap(2) できない。
    ENOENT
    LANai プログラムあるいはコンフィギュレーションファイルがない。
    ENXIO
    LANai プログラムをロードできない。
    LANai プログラムとライブラリのバージョンが異なる。
    EBUSY
    コンフィギュレーションファイルのノード名/経路に重複がある。
    EHOSTUNREACH
    あるノードへの経路が存在しない。
    EMLINK
    あるノードへのホップ数が 4 を越えている。


    NAME
    _pmOpenContext - コンテキストを開く

    SYNOPSYS
    int _pmOpenContext(int unit, int ctx, pmCtx *pmcp)

    DESCRIPTION
    ユニット unit のコンテキスト ctx を開き、 コンテキストポインタを *pmcp に返します。

    RETURN VALUES
    _pmOpenContext は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    unit または ctx の値が範囲を越えている。
    ENODEV
    ユニット番号 unit の Myriet インタフェースが存在しない。 Myrinet インタフェースを mmap(2) できない。
    ENXIO
    LANai プロセッサが動作していない。


    NAME
    _pmCloseContext - コンテキストを閉じる

    SYNOPSYS
    int _pmCloseContext(pmCtx pmc)

    DESCRIPTION
    コンテキスト pmc を閉じます。

    RETURN VALUES
    _pmCloseContext は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    なし。


    NAME
    _pmInitContext - コンテキストを初期化する

    SYNOPSYS
    int _pmInitContext(int pmdesc, pmCtx *pmcp)

    DESCRIPTION
    デスクリプタ pmdesc で示されたチャネルと そのチャネルにロードされているコンテキストを初期化し、 コンテキストポインタを *pmcp に返します。
    親プロセスから渡されたチャネル/コンテキストの初期化に用います。

    RETURN VALUES
    _pmInitContext は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EBADF
    pmdesc の値が不正である。
    ENODEV
    Myrinet インタフェースが存在しない。
    Myrinet インタフェースを mmap(2) できない。
    ENXIO
    LANai プロセッサが動作していない。


    NAME
    _pmResetContext - コンテキストを初期状態に戻す

    SYNOPSYS
    int _pmResetContext(pmCtx pmc)

    DESCRIPTION
    コンテキスト pmc を初期状態に戻します。
    コンテキストには全物理 PE が論理 PE として割り当てられます。

    NOTICE
    コンテキストは送信不許可、かつ安定状態でなければなりません。

    RETURN VALUES
    _pmResetContext は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EIO
    コンテキストが送信許可状態である。
    EBUSY
    コンテキストが安定状態にない。


    NAME
    _pmLoadContext - コンテキストをチャネルにロードする

    SYNOPSYS
    int _pmLoadContext(pmCtx pmc, int chan)

    DESCRIPTION
    コンテキスト pmc をチャネル chan にロードします。
    コンテキストを用いて通信を行なう場合にはチャネルにロードされている 必要があります。

    RETURN VALUES
    _pmLoadContext は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    chan の値が不正である。
    EBUSY
    コンテキストはすでにいずれかのチャネルにロードされている。


    NAME
    _pmUnloadContext - コンテキストをチャネルからアンロードする

    SYNOPSYS
    int _pmUnloadContext(pmCtx pmc)

    DESCRIPTION
    チャネルにロードされているコンテキスト pmc をアンロードします。

    RETURN VALUES
    _pmUnloadContext は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    コンテキストがチャネルにロードされていない。


  2. コンフィギュレーション
    NAME
    _pmGetConfig - コンフィギュレーション情報を得る

    SYNOPSYS
    int _pmGetConfig(int unit, pmConfig *cfp)

    DESCRIPTION
    Myrinet インタフェース unit の全ノード数、チャネル数、 コンテキスト数などのコンフィギュレーション情報を *cfp の pmConfig 構造体に返します。
    typedef struct pm_config {
    	int	nodes;		/* ノード数 */
    	int	channels;	/* チャネル数 */
    	int	contexts;	/* コンテキスト数 */
    } pmConfig;
    

    RETURN VALUES
    _pmGetConfig は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    unit の値が不正である。


    NAME
    _pmBindPE - コンテキストに物理 PE を割り当てる

    SYNOPSYS
    int _pmBindPE(pmCtx pmc, int pe_base, int pe_num)

    DESCRIPTION
    コンテキスト pmcpe_base から 始まる pe_num 個の物理 PE を論理 PE 番号 0〜(pe_num-1) として 割り当てます。

    RETURN VALUES
    _pmBindPE は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    pe_basepe_num で示される値が 物理 PE の範囲を越えている。


    NAME
    _pmPEs - コンテキストに割り当てられた論理 PE の数を得る

    SYNOPSYS
    int _pmPEs(pmCtx pmc, int *npep)

    DESCRIPTION
    コンテキスト pmc の論理 PE の個数を *npep に返します。

    RETURN VALUES
    _pmPEs は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    なし。


    NAME
    _pmSelf - 自分の論理 PE 番号を得る

    SYNOPSYS
    int _pmSelf(pmCtx pmc, int *selfp)

    DESCRIPTION
    コンテキスト pmc での自分の論理 PE 番号を *selfp に返します。

    RETURN VALUES
    _pmSelf は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    なし。


    NAME
    _pmFd - コンテキストのファイルデスクリプタを得る

    SYNOPSYS
    int _pmFd(pmCtx pmc, int *fdp)

    DESCRIPTION
    コンテキスト pmc のファイルデスクリプタを *fdp に返します。
    このファイルデスクリプタを用いて、 select(2) によってメッセージの到着を待つことができます。

    RETURN VALUES
    _pmFd は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    なし。

    BUGS
    現在の実装では、ファイルデスクリプタはユニット毎に一つなので、 複数のコンテキストを select(2) で待つことはできません。


    NAME
    _pmChanDesc - チャネルデスクリプタを得る

    SYNOPSYS
    int _pmChanDesc(int unit, int chan , int *descp)

    DESCRIPTION
    ユニット unit、チャネル chan のデスクリプタを *descp に返します。
    子プロセスにチャネルを渡す場合に用います。

    RETURN VALUES
    _pmDesc は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    なし。


  3. メッセージ送信
    NAME
    _pmGetSendBuf - 送信バッファを得る

    SYNOPSYS
    int _pmGetSendBuf(pmCtx pmc, caddr_t *bufp, size_t length)

    DESCRIPTION
    コンテキスト pmc の長さ length の送信バッファのアドレスを *bufp に返します。

    RETURN VALUES
    _pmGetSendBuf は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    length の値が範囲を越えている。
    ENOBUFS
    バッファの取得に失敗した。


    NAME
    _pmSend - メッセージを送信する

    SYNOPSYS
    int _pmSend(pmCtx pmc, int dst_node)

    DESCRIPTION
    コンテキスト pmc の論理 PE dst_node にメッセージを送信します。

    RETURN VALUES
    _pmSend は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    dst_node の値が範囲を越えている。
    EHOSTUNREACH
    dst_node への経路がない。


    NAME
    _pmGetMutiBuf - マルチキャスト用の送信バッファを得る

    SYNOPSYS
    int _pmGetMultiBuf(pmCtx pmc, caddr_t *bufp, size_t length, int num_nodes)

    DESCRIPTION
    コンテキスト pmc の長さ length の送信バッファのアドレスを *bufp に返します。 同時に num_nodes 個の PE にマルチキャストするために必要な資源を 確保します。

    RETURN VALUES
    _pmGetMultiBuf は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    length の値が範囲を越えている。
    ENOBUFS
    バッファの取得に失敗した。
    マルチキャスト送信に必要な資源が不足している。


    NAME
    _pmSendMulticast - マルチキャスト送信する

    SYNOPSYS
    int _pmSendMulticast(pmCtx pmc, int *dst_nodes, int num_dst)

    DESCRIPTION
    コンテキスト pmcdst_nodes に格納された num_dest 個の論理 PE 全部に メッセージを送信する。

    RETURN VALUES
    _pmSendMulticast は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    dst_nodes 内の論理PE番号が コンテキストに割り当てられている範囲を越えている。
    EHOSTUNREACH
    宛先の論理 PE のうち、どれかへの経路がない。


    NAME
    _pmSendDone - 送信終了の確認

    SYNOPSYS
    int _pmSendDone(pmCtx pmc)

    DESCRIPTION
    コンテキスト pmc のメッセージがすでに送信されたかどうかを調べます。

    RETURN VALUES
    _pmSendDone は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EBUSY
    まだ送信されていないメッセージがある。


  4. メッセージ受信
    NAME
    _pmReceiveInterrupt - 受信割り込みの制御

    SYNOPSYS
    int _pmReceiveInterrupt(pmCtx pmc, int sw)

    DESCRIPTION
    コンテキスト pmc の受信割り込みを許可(sw != 0)/禁止(sw == 0)します。

    RETURN VALUES
    _pmReceiveInterrupt は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    なし。


    NAME
    _pmSignal - 受信シグナルの制御

    SYNOPSYS
    int _pmSignal(pmCtx pmc, int signum)

    DESCRIPTION
    コンテキスト pmc の受信シグナルを ON (signum > 0) / OFF (signum == 0) します。

    NOTICE
    メッセージの到着によってシグナルを受け取るためには、 _pmReceiveInterrupt によって受信割り込みが 許可されている必要があります。

    RETURN VALUES
    _pmSignal は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    signum の値が不正である。


    NAME
    _pmReceive - メッセージの受信

    SYNOPSYS
    int _pmReceive(pmCtx pmc, caddr_t *bufp, size_t *lengthp)

    DESCRIPTION
    コンテキスト pmc から受信したメッセージのアドレスを *bufp に、長さを *lengthp に返します。

    RETURN VALUES
    _pmReceive は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    ENOBUFS
    メッセージが受信されていない。
    EIO
    CRC エラーが検出された。(Fatal)
    EPIPE
    NRES(Network RESet) が検出された。(Fatal)


    NAME
    _pmReceiveWait - 割り込みによるメッセージの受信

    SYNOPSYS
    int _pmReceiveWait(pmCtx pmc, caddr_t *bufp, size_t *lengthp)

    DESCRIPTION
    コンテキスト pmc へのメッセージの到着までプロセスをブロックして待ち、 メッセージが到着したら、受信メッセージのアドレスを *bufp に, 長さを*lengthpに返します。

    RETURN VALUES
    _pmReceiveWait は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EIO
    CRC エラーが検出された。(Fatal)
    EPIPE
    NRES(Network RESet) が検出された。(Fatal)


    NAME
    _pmPutReceiveBuf - 受信バッファの返却

    SYNOPSYS
    int _pmPutReceiveBuf(pmCtx pmc)

    DESCRIPTION
    コンテキスト pmc の受信バッファを返却します。

    RETURN VALUES
    _pmPutReceiveBuf は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    なし。


  5. リモートメモリアクセス
    NAME
    _pmMLock - メモリのマップおよびピンダウン (i386 のみ)

    SYNOPSYS
    int _pmMLock(pmCtx pmc, caddr_t addr, size_t size, u_int *virtp)

    DESCRIPTION
    アドレス addr から始まる size バイトの領域をマップし、 物理メモリにピンダウンします。 マップされた結果は *virtp に返されます。

    RETURN VALUES
    _pmMLock は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    ENOSPC
    マップするための資源がない。
    EFAULT
    マップしようとする領域が大き過ぎる。
    EAGAIN
    ピンダウンしている領域の合計がが大き過ぎる。
    ENOMEM
    ピンダウンに失敗した。


    NAME
    _pmMUnlock - メモリ領域のロックの解除 (i386 のみ)

    SYNOPSYS
    int _pmMUnlock(pmCtx pmc, caddr_t addr, size_t size)

    DESCRIPTION
    _pmMLock によってピンダウンされた、 アドレス addr から始まる size バイトの領域に 未使用のフラグを立てます。
    実際のピンダウンの解除は _pmMLock の際に資源が不足した場合まで延期されます。

    RETURN VALUES
    _pmMUnlock は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    ENOENT
    指定されたか総アドレスが _pmMLock によって ピンダウンされた領域ではない。


    NAME
    _pmMInvalidate - ピンダウンの強制解除 (i386 のみ)

    SYNOPSYS
    int _pmMInvalidate(pmCtx pmc, caddr_t addr, size_t size)

    DESCRIPTION
    _pmMUnlock された アドレス addr から始まる size バイトの領域の ピンダウンを強制的に解除します。

    RETURN VALUES
    _pmMInvalidate は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    ENOENT
    指定された領域が _pmMLock によって ピンダウンされた領域ではない。
    EBUSY
    指定された領域が _pmMUnlock されていない。


    NAME
    _pmVWrite - 仮想メモリ間データ転送 (i386 のみ)

    SYNOPSYS
    int _pmVWrite(pmCtx pmc, int dst_node, u_int dst_addr, u_int src_addr, size_t length)

    DESCRIPTION
    仮想アドレス src_addr から始まる length バイトを dst_node の仮想アドレス dst_addr に転送します。
    src_addrdst_addr_pmMLock によってマップされた仮想アドレスです。

    NOTICE
    メモリ内容の Myrinet インタフェースへの DMA は非同期に行なわれるため、 _pmWriteDone によって DMA の終了を待たずに内容を書き換えると、受信ノードのメモリに書き込まれる値は 不定となります。

    RETURN VALUES
    _pmVWrite は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    送信側の仮想アドレスが、_pmMLock されていない。
    length が範囲を超えている。
    EHOSTUNREACH
    dst_node への経路がない。
    ENOBUFS
    資源が不足している。


    NAME
    _pmWriteDone - DMA 終了の確認

    SYNOPSYS
    int _pmWriteDone(pmCtx pmc)

    DESCRIPTION
    コンテキスト pmc_pmVWrite の DMA が すでに終了したかどうかを調べます。

    RETURN VALUES
    _pmWriteDone は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EBUSY
    まだ DMA が終了していない。


  6. ネットワークコンテキストスイッチ
    NAME
    _pmSendActivate - 送信の許可/禁止

    SYNOPSYS
    int _pmSendActivate(pmCtx pmc, int sw)

    DESCRIPTION
    コンテキスト pmc のメッセージ送信を許可(sw != 0)/禁止(sw == 0)します。

    RETURN VALUES
    _pmSendActivate は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    なし。


    NAME
    _pmSendStable - 安定状態の検査

    SYNOPSYS
    int _pmSendStable(pmCtx pmc)

    DESCRIPTION
    コンテキスト pmc が安定状態の時にゼロを、 そうでない時に EBUSY を返します。
    「安定状態」とは、送信したすべてのメッセージについて、ACK によって受信が 確認されたか、NACK によって再送が決定している状態を言います。
    NOTICE
    コンテキストは送信が禁止されている必要があります。

    RETURN VALUES
    _pmSendStable は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EIO
    送信が許可されている。
    EBUSY
    定常状態ではない。


    NAME
    _pmSaveContext - コンテキストの退避

    SYNOPSYS
    int _pmSaveContext(pmCtx pmc, caddr_t address)

    DESCRIPTION
    コンテキスト pmcaddress で示される領域に退避します。

    RETURN VALUES
    _pmSaveContext は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EIO
    送信が許可されている。
    EBUSY
    コンテキストが一時的に退避できない状態になっている。


    NAME
    _pmRestoreContext - コンテキストの復帰

    SYNOPSYS
    int _pmRestoreContext(pmCtx pmc, caddr_t address)

    DESCRIPTION
    コンテキスト pmcaddress で示される領域からから復帰します。

    RETURN VALUES
    _pmRestoreContext は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EIO
    送信が許可されている。
    退避されているコンテキストに矛盾がある。


    NAME
    _pmSaveSize - コンテキスト退避領域の大きさを得る

    SYNOPSYS
    int _pmSaveSize(void)

    DESCRIPTION
    コンテキストを退避するのに必要な領域の大きさを返します。

    RETURN VALUES
    _pmSendSize はコンテキスト退避領域の大きさを返します。


  7. その他
    NAME
    _pmGetStatus - コンテキストの状態を得る

    SYNOPSYS
    int _pmGetStatus(pmCtx pmc, pmStatus *statp)

    DESCRIPTION
    コンテキスト pmc の状態を statp の指す pmStatus 構造体に返します。
    typedef struct pm_context_status {
    	int	recv_message;	/* recv. queue にあるメッセージ数 */
    	int	recv_size;	/* recv. queue にあるメッセージの総バイト数 */
    	int	send_message;	/* send queue にあるメッセージ数 */
    	int	send_size;	/* send queue にあるメッセージの総バイト数 */
    	int	pend_message;	/* Ack 待ちまたは retry 中のメッセージ数 */
    	int	pend_size;	/* Ack 待ちまたは retry 中のメッセージの総バイト数*/
    	u_int	resend_count;	/* 今までに再送したメッセージ数 */
    	u_int	double_resend;	/* 2 重に再送したメッセージ数 */
    } pmStatus;
    

    RETURN VALUES
    _pmGetStatus は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    なし。


    NAME
    _pmGetVersion - バージョン文字列を得る

    SYNOPSYS
    int _pmGetVersion(int unit, char **vp)

    DESCRIPTION
    unit の LANai プログラムのバージョン文字列を *vp に返します。

    RETURN VALUES
    _pmVersion は正常終了するとゼロを、 エラーの場合は次のエラーコードを返します。

    ERRORS
    EINVAL
    unit の値が範囲を越えている。
    ENODEV
    Myrinet デバイスがマップされていない。


    NAME
    _pmErrorString - エラー文字列を得る

    SYNOPSYS
    char *_pmErrorString(int error)

    DESCRIPTION
    エラーコード error に対応する文字列を返します。

    RETURN VALUES
    _pmErrorString はエラー文字列を返します。

    ERRORS
    なし。


  8. 互換性のためのエントリ 次のような関数が PM API v1.0 によって書かれたプログラムのために用意されています。
    
    int _pmLANaiInit(int unit, char *mcp, char *config);
    int _pmOpenChannel(int unit, int chan, pmCtx *pmcp);
    int _pmCloseChannel(pmCtx pmc);
    int _pmInitChannel(int pmdesc, pmCtx *pmcp);
    int _pmResetChannel(pmCtx pmc);
    int _pmSaveChannel(pmCtx pmc, caddr_t address);
    int _pmRestoreChannel(pmCtx pmc, caddr_t address);
    int _pmDesc(pmCtx pmc, int *descp);
    
    

  9. サンプルプログラム

    初期化


    
    pmCtx	pmc;
    int	pmdesc;
    
    int
    init_system()
    {
    	int	unit, chan, ctx, error;
    	int	pe_base, pe_num;
    	char	*mcp, *config;
    
    	mcp = "pm.mcp";
    	config = "pm.cnf";
    	if ((error = _pmInit(unit, mcp, config)) != 0)
    		return (error);
    	if ((error = _pmOpenContext(unit, ctx, &pmc)) != 0)
    		return (error);
    	if ((error = _pmLoadContext(pmc, chan)) != 0)
    		return (error);
    	if ((error = _pmBindPE(pmc, pe_base, pe_num)) != 0)
    		return (error);
    	_pmChanDesc(unit, chan, &pmdesc);
    	return (0);
    }
    
    /*
     * pmdesc is passed to user program.
     */
    int
    init_user()
    {
    	int	error;
    
    	if ((error = _pmInitContext(pmdesc, &pmc)) != 0)
    		return (error);
    	return (0);
    }
    
    

    メッセージの送信


    
    int
    send()
    {
    	pmCtx	pmc;
    	caddr_t	buf;
    	size_t	length;
    	int	error;
    
    	while ((error = _pmGetSendBuf(pmc, &buf, length)) == ENOBUFS)
    		;
    	if (error != 0)
    		return (error);
    	/*
    	 * Fill buffer
    	 */
    	if ((error = _pmSend(pmc, dest)) != 0)
    		return (error);
    	return (0);
    }
    
    

    メッセージのマルチキャスト


    
    int
    send_multi()
    {
    	pmCtx	pmc;
    	caddr_t	buf;
    	size_t	length;
    	int	error;
    	int	dest[NDEST];
    
    	while ((error = _pmGetMultiBuf(pmc, &buf, length, NDEST)) == ENOBUFS)
    		;
    	if (error != 0)
    		return (error);
    	/*
    	 * Fill buffer
    	 */
    	dest[0] = dest0;
    	dest[1] = dest1;
    	...
    	dest[NDEST-1] = destN_1;
    	while ((error = _pmSendMulticast(pmc, dest, NDEST)) != ENOBUFS)
    		;
    	if (error != 0)
    		return (error);
    	return (0);
    }
    
    

    メッセージの受信


    
    int
    receive()
    {
    	pmCtx	pmc;
    	caddr_t	buf;
    	size_t	length;
    	int	error;
    
    	while ((error = _pmReceive(pmc, &buf, &length)) == ENOBUFS)
    		;
    	if (error != 0)
    		return (error);
    	/*
    	 * Process Message
    	 */
    	if ((error = _pmPutReceiveBuf(pmc)) != 0)
    		return (error);
    	return (0);
    }
    
    

    ネットワークコンテキストスイッチ


    
    caddr_t	save;
    
    int
    save_context()
    {
    	pmCtx	pmc;
    	int	error;
    
    	save = malloc(_pmSaveSize());
    	if ((error = _pmSendActivate(pmc, 0)) != 0)
    		return (error);
    	while ((error = _pmSendStable(pmc)) == EBUSY)
    		;
    	if (error != 0)
    		return (error);
    	if ((error = _pmSaveContext(pmc, save)) != 0)
    		return (error);
    	return (0);
    }
    
    int
    restore_context()
    {
    	pmCtx	pmc;
    	int	error;
    
    	if ((error = _pmRestoreContext(pmc, save)) != 0)
    		return (error);
    	if ((error = _pmSendActivate(pmc, 1)) != 0)
    		return (error);
    	return (0);
    }
    
    

    ピンポンプログラム


    
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    
    #include "Pm.h"
    
    #ifdef sun
    #define	htonl(x)	(x)
    #define	ntohl(x)	(x)
    
    extern int fprintf(FILE *, char *, ...);
    #endif
    
    void	reply(int);
    void	pingpong(int, int, int, int);
    void	print_error(char *, int);
    
    char	*mcp = "pm.mcp";
    char	*config = "pm.cnf";
    int	unit = 0;
    int	channel = 0;
    int	context = 0;
    int	dest;
    int	length = 8;
    int	iteration = 10000;
    int	reply_flag = 0;
    int	self;
    
    int
    main(int argc, char **argv)
    {
    	int	error;
    	pmCtx	pmc;
    
    	if (argc == 1) {
    		fprintf(stderr, "%s: option\n", argv[0]);
    		exit(1);
    	}
    	for (argc--, argv++; argc > 0; argc--, argv++) {
    		if (strcmp(argv[0], "-reply") == 0) {
    			reply_flag = 1;
    			continue;
    		}
    		if (strcmp(argv[0], "-unit") == 0) {
    			unit = atoi(argv[1]);
    			argc--;
    			argv++;
    			continue;
    		}
    		if (strcmp(argv[0], "-chan") == 0) {
    			channel = atoi(argv[1]);
    			argc--;
    			argv++;
    			continue;
    		}
    		if (strcmp(argv[0], "-ctx") == 0) {
    			context = atoi(argv[1]);
    			argc--;
    			argv++;
    			continue;
    		}
    		if (strcmp(argv[0], "-dest") == 0) {
    			dest = atoi(argv[1]);
    			argc--;
    			argv++;
    			continue;
    		}
    		if (strcmp(argv[0], "-len") == 0) {
    			length = atoi(argv[1]);
    			argc--;
    			argv++;
    			continue;
    		}
    		if (strcmp(argv[0], "-iter") == 0) {
    			iteration = atoi(argv[1]);
    			argc--;
    			argv++;
    			continue;
    		}
    		if (strcmp(argv[0], "-mcp") == 0) {
    			mcp = argv[1];
    			argc--;
    			argv++;
    			continue;
    		}
    		if (strcmp(argv[0], "-conf") == 0) {
    			config = argv[1];
    			argc--;
    			argv++;
    			continue;
    		}
    		fprintf(stderr, "unknown option %s\n", argv[0]);
    		exit(1);
    	}
    	if ((error = _pmInit(unit, mcp, config)) != 0) {
    		print_error("_pmLANaiInit", error);
    		exit(1);
    	}
    	if ((error = _pmOpenContext(unit, context, &pmc)) != 0) {
    		print_error("_pmOpenContext", error);
    		exit(1);
    	}
    	if ((error = _pmLoadContext(pmc, chan)) != 0) {
    		print_error("_pmLoadContext", error);
    		exit(1);
    	}
    
    	if ((error = _pmSelf(pmc, &self)) != 0) {
    		print_error("_pmSelf", error);
    		exit(1);
    	}
    
    	if (reply_flag)
    		reply(pmc);
    	else
    		pingpong(pmc, dest, length, iteration);
    
    	exit(0);
    }
    
    void
    reply(pmCtx pmc)
    {
    	caddr_t	addr, addr2;
    	size_t	length;
    	int	error, dest;
    
    	for (;;) {
    		while ((error = _pmReceive(pmc, &addr, &length)) == ENOBUFS)
    			;
    		if (error != 0) {
    			print_error("_pmReceive", error);
    			exit(1);
    		}
    		dest = ntohl(*(int *)addr);
    		while ((error = _pmGetSendBuf(pmc, &addr2, length)) ==
    		      ENOBUFS)
    			;
    		if (error != 0) {
    			print_error("_pmGetSendBuf", error);
    			exit(1);
    		}
    		*(int *)addr2 = htonl(self);
    		if ((error = _pmSend(pmc, dest)) != 0) {
    			print_error("_pmSend", error);
    			exit(1);
    		}
    		(void) _pmPutReceiveBuf(pmc);
    	}
    }
    
    void
    pingpong(pmCtx pmc, int dest, size_t length, int n)
    {
    	caddr_t	addr, addr2 = NULL;
    	int	i, error, length2;
    
    	for (i = 0; i < n; i++) {
    		while ((error = _pmGetSendBuf(pmc, &addr, length)) ==
    		    ENOBUFS)
    			;
    		if (error != 0) {
    			print_error("_pmGetSendBuf", error);
    			exit(1);
    		}
    		*(int *)addr = htonl(self);
    		if ((error = _pmSend(pmc, dest)) != 0) {
    			print_error("_pmSend", error);
    			exit(1);
    		}
    		if (addr2 != NULL)
    			(void) _pmPutReceiveBuf(pmc);
    		while ((error = _pmReceive(pmc, &addr2, &length2)) ==
    		    ENOBUFS)
    			;
    		if (error != 0) {
    			print_error("_pmReceive", error);
    			exit(1);
    		}
    	}
    	if (addr2 != NULL)
    		(void) _pmPutReceiveBuf(pmc);
    }
    
    void
    print_error(char *msg, int error)
    {
    
    	fprintf(stderr, "%s: %s\n", msg, _pmErrorString(error));
    }