ONC+ Developer's Guide

Freeing Library Resources in User Mode

In the MT User mode, service procedures must invoke svc_done() before returning. svc_done() frees resources allocated to service a client request directed to the specified service transport handle. This function is invoked after a client request has been serviced, or after an error or abnormal condition that prevents a reply from being sent. After svc_done() is invoked, the service procedure should not reference the service transport handle. The following example shows a server in MT User mode.

Note –

svc_done() must only be called within MT User mode. For more information on this call, see the rpc_svc_calls(3NSL) man page.

Example 7–3 MT User Mode: rpc_test.h

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

	struct intpair {
		u_short	a;
		u_short	b;

	typedef struct intpair intpair;

	struct svc2_add_args {
		int argument;
		SVCXPRT *transp;

	struct svc2_mult_args {
		intpair mult_argument;
		SVCXPRT *transp;

	extern bool_t xdr_intpair();

	#define NTHREADS_CONST 500

The following code example is the client for MT User mode.

Example 7–4 Client for MT User Mode

#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();
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");
	} else
		if (argc == 3) {
			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);
		save_thread[index].client_id = client_id;
	for (index = 0; index < NTHREADS; index++){

		if (thr_join(save_thread[index].client_id, &departedid,	
		(void *)
			printf("thr_join failed for thread %d\n",
		save_thread[index].client_status = thread_status;
	void *doclient(host)
	char *host;
	struct timeval tout;
	enum clnt_stat test;
	int result = 0;
	u_short mult_result = 0;
	int add_arg;
	int 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_int,

		(caddr_t) &add_arg, (xdrproc_t) xdr_int, (caddr_t) &result,
	} else {
		pair.a = (u_short) thr_self();
		pair.b = (u_short) 1;
		EXP_RSLT = pair.a * pair.b;
		test = clnt_call(clnt, SVC2_PROC_MULT, (xdrproc_t)
		(caddr_t) &pair, (xdrproc_t) xdr_u_short,

		(caddr_t) &mult_result, tout);
		result = mult_result;
	if (test != RPC_SUCCESS) {
		printf("THREAD: %d clnt_call hav
		thr_exit((void *) -1);
	thr_exit((void *) 0);

MT performance is enhanced if the function svc_getargs() is called by every procedure other than NULLPROC, even if there are no arguments. xdr_void may be used in this case. This result is true for both the MT Auto and MT User modes. For more information on this call, see the rpc_svc_calls(3NSL) man page.

Note –

You must link in the thread library when writing RPC multithreaded-safe applications. The thread library must be the last named library on the link line. Specify the -lthread option in the compile command.