ONC+ 開発ガイド

ユーザモードでのライブラリリソースの解放

マルチスレッド・ユーザ・モードでは、サービスプロシージャは、戻しの前に svc_done() を呼び出さなければなりません。svc_done() は、クライアント要求が指定のサービス・トランスポート・ハンドルに向けたサービスに割り当てたリソースを解放しなければなりません。この機能は、クライアント要求がサービスされた後、あるいは応答の送信を妨げたエラーまたは異常な状態の後に呼び出されます。svc_done() が呼び出された後に、サービス・トランスポート・ハンドルは、サービスプロシージャによって参照されるべきではありません。例 4-36は、マルチスレッド・ユーザ・モードでのサーバを示します。


注 -

svc_done() は、マルチスレッド・ユーザ・モード内でだけ呼び出すことができます。詳細は、rpc_svc_calls(3N) マニュアルページを参照してください。



例 4-36 マルチスレッド・ユーザ・モード : rpc_test.h

	#define	SVC2_PROG 0x30000002
	#define	SVC2_VERS ((u_long) 1)
	#define SVC2_PROC_ADD ((u_long) 1)
	#define SVC2_PROC_MULT ((u_long) 2)

	struct intpair {
		u_short	a;
		u_short b;
	};

	typedef struct intpair intpair;

	struct svc2_add_args {
		long argument;
		SVCXPRT *transp;
	};

	struct svc2_mult_args {
		intpair mult_argument;
		SVCXPRT *transp;
	};

	extern bool_t xdr_intpair();

	#define NTHREADS_CONST 500

例 4-37 は、マルチスレッド・ユーザ・モードに対するクライアントです。


例 4-37 マルチスレッド・ユーザ・モードに対するクライアント

#define	 _REENTRANT
#include <stdio.h>
#include <rpc/rpc.h>
#include <sys/uio.h>
#include <netconfig.h>
#include <netdb.h>
#include <rpc/nettype.h>
#include <thread.h>
#include "rpc_test.h"
void *doclient();
int NTHREADS;
struct thread_info {
	thread_t client_id;
	int client_status;
};
struct thread_info save_thread[NTHREADS_CONST];
main(argc, argv)
	int argc;
	char *argv[];
{
	int index, ret;
	int thread_status;
	thread_t departedid, client_id;
	char *hosts;
	if (argc < 3) {
		printf("Usage: do_operation [n] host¥n");
		printf("¥twhere n is the number of threads¥n");
		exit(1);
	} else
		if (argc == 3) {
			NTHREADS = NTHREADS_CONST;
			hosts = argv[1];  /* live_host */
		} else {
			NTHREADS = atoi(argv[1]);
			hosts = argv[2];
		}
	for (index = 0; index < NTHREADS; index++){
		if (ret = thr_create(NULL, NULL, doclient,
		(void *)  hosts, THR_BOUND, &client_id)){
			printf("thr_create failed: return value %d", ret);
			printf(" for %dth thread¥n", index);
			exit(1);
		}
		save_thread[index].client_id = client_id;
	}
	for (index = 0; index < NTHREADS; index++){
		if (thr_join(save_thread[index].client_id, &departedid,	
		(void *)
		&thread_status)){
			printf("thr_join failed for thread %d¥n",
			save_thread[index].client_id);
			exit(1);
		}
		save_thread[index].client_status = thread_status;
	}
}
	void *doclient(host)
	char *host;
{
	struct timeval tout;
	enum clnt_stat test;
	long result = 0;
	u_short mult_result = 0;
	long add_arg;
	long EXP_RSLT;
	intpair pair;
	CLIENT *clnt;
	if ((clnt = clnt_create(host, SVC2_PROG, SVC2_VERS, "udp"
==NULL) {
		clnt_pcreateerror("clnt_create error: ");
		thr_exit((void *) -1);
	}
	tout.tv_sec = 25;
	tout.tv_usec = 0;
	memset((char *) &result, 0, sizeof (result));
	memset((char *) &mult_result, 0, sizeof (mult_result));
	if (thr_self() % 2){
		EXP_RSLT = thr_self() + 1;
		add_arg = thr_self();
		test = clnt_call(clnt, SVC2_PROC_ADD, (xdrproc_t) xdr_long,
		(caddr_t) &add_arg, (xdrproc_t) xdr_long, (caddr_t) &result,
		tout);
	} else {
		pair.a = (u_short) thr_self();
		pair.b = (u_short) 1;
		EXP_RSLT = (long) pair.a * pair.b;
		test = clnt_call(clnt, SVC2_PROC_MULT, (xdrproc_t)
		xdr_intpair,
		(caddr_t) &pair, (xdrproc_t) xdr_u_short,
		(caddr_t) &mult_result, tout);
		result = (long) mult_result;
	}
	if (test != RPC_SUCCESS) {
		printf("THREAD: %d clnt_call hav
		thr_exit((void *) -1);
	};
	thr_exit((void *) 0);
}

例 4-38 は、マルチスレッド・ユーザ・モードのサーバ側を示します。マルチスレッドパフォーマンスは、関数 svc_getargs()NULLPROC 以外の各プロシージャに呼び出される場合は、引き数 (この場合には xdr_void) がなくても改善されます。これは、マルチスレッド自動モードモードとマルチスレッドユーサモードにおいてです。詳細は、rpc_svc_calls(3N) マニュアルページを参照してください。


注 -

RPC マルチスレッド対応アプリケーションを作成する場合は常に、スレッドライブラリ内でリンクしなければなりません。コンパイルコマンドで -lthread を指定して、スレッドライブラリを最後にリンクするようにしなければなりません。



例 4-38 マルチスレッド・ユーザ・モードのサーバ側

#define 	_REENTRANT
#include <stdio.h>
#include <rpc/rpc.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/uio.h>
#include <signal.h>
#include <thread.h>
#include "operations.h"

SVCXPRT *xprt;
void add_mult_prog();
void *svc2_add_worker();
void *svc2_mult_worker();
main(argc, argv)
	int argc;
	char **argv;
{
	int transpnum;
	char *nettype;
	int mode = RPC_SVC_MT_USER;
       if(rpc_control(RPC_SVC_MTMODE_SET,&mode) == FALSE){
                printf(" rpc_control is failed to set AUTO mode¥n");
                exit(0);
        }
	if (argc > 2) {
		fprintf(stderr, "usage: %s [nettype]¥n", argv[0]);
		exit(1);
	}
	if (argc == 2)
		nettype = argv[1];
	else
		nettype = "netpath";
	transpnum = svc_create(add_mult_prog, SVC2_PROG,
 	SVC2_VERS, nettype);
	if (transpnum == 0) {
		fprintf(stderr, "%s: cannot create %s service.¥n", argv[0],
 		nettype);
		exit(1);
	}
	svc_run();
}
void add_mult_prog (rqstp, transp)
	struct svc_req *rqstp;
	SVCXPRT *transp;
{
	long argument;
	u_short mult_arg();
	intpair mult_argument;
	bool_t (*xdr_argument)();
	struct svc2_mult_args *sw_mult_data;
	struct svc2_add_args *sw_add_data;
	int ret;
	thread_t worker_id;
	switch ((long) rqstp->rq_proc){
		case NULLPROC:
			svc_sendreply(transp, xdr_void, (char *) 0);
			svc_done(transp);
			break;
		case SVC2_PROC_ADD:
			xdr_argument = xdr_long;
			(void) memset((char *) &argument, 0, sizeof (argument));
			if (!svc_getargs(transp, xdr_argument,
			(char *) &argument)){
				printf("problem with getargs¥n");
				svcerr_decode(transp);
				exit(1);
			}
			sw_add_data = (struct svc2_add_args *)
			malloc(sizeof (struct svc2_add_args));
			sw_add_data->transp = transp;
			sw_add_data->argument = argument;
			if (ret = thr_create(NULL, THR_MIN_STACK + 16 * 1024,
			svc2_add_worker, (void *) sw_add_data, THR_DETACHED,
				printf("SERVER: thr_create failed:");
				printf(" return value %d", ret);
				printf(" for add thread¥n");
				exit(1);
			}
			break;
		case SVC2_PROC_MULT:
			xdr_argument = xdr_intpair;
			(void) memset((char *) &mult_argument, 0,
			sizeof (mult_argument));
			if (!svc_getargs(transp, xdr_argument,
			(char *) &mult_argument)){
				printf("problem with getargs¥n");
				svcerr_decode(transp);
				exit(1);
			}
			sw_mult_data = (struct svc2_mult_args *)
			malloc(sizeof (struct svc2_mult_args));
			sw_mult_data->transp = transp;
			sw_mult_data->mult_argument.a = mult_argument.a;
			sw_mult_data->mult_argument.b = mult_argument.b;
			if (ret = thr_create(NULL, THR_MIN_STACK + 16 * 1024,
			svc2_mult_worker, (void *) sw_mult_data, THR_DETACHED,
			&worker_id)){
				printf("SERVER: thr_create failed:");
				printf("return value %d", ret);
				printf("for multiply thread¥n");
				exit(1);

			break;
		default:
			svcerr_noproc(transp);
			svc_done(transp);
			break;
	}
}

u_short mult_arg();
long add_one();
void *svc2_add_worker(add_arg)
struct svc2_add_args *add_arg;
{	long *result;
	bool_t (*xdr_result)();
	xdr_result = xdr_long;
	result = (long *) malloc(sizeof (long));
	*result = add_one(add_arg->argument);
	if (!svc_sendreply(add_arg->transp, xdr_result,
	(caddr_t) result)){
		printf("sendreply failed¥n");
		svcerr_systemerr(add_arg->transp);
		svc_done(add_arg->transp);
		thr_exit((void *) -1);
	}
	svc_done(add_arg->transp);
	thr_exit((void *) 0);
}
void *svc2_mult_worker(m_arg)
struct svc2_mult_args *m_arg;
{
	u_short *result;
	bool_t (*xdr_result)();
	xdr_result = xdr_u_short;
	result = (u_short *) malloc(sizeof (u_short));
	*result = mult_arg(&m_arg->mult_argument);
	if (!svc_sendreply(m_arg->transp, xdr_result,
	(caddr_t) result)){
		printf("sendreply failed¥n");
		svcerr_systemerr(m_arg->transp);
		svc_done(m_arg->transp);
		thr_exit((void *) -1);
	}
	svc_done(m_arg->transp);
	thr_exit((void *) 0);
}
u_short mult_arg(pair)
	intpair *pair;
{
	u_short result;
	result = pair->a * pair->b;
	return (result);}
long add_one(arg)
	long arg;
{
	return (++arg);
}