The following code example shows the time_prot.h
header file for the server.
Example 7-2 MT Auto Mode: time_prot.h
#include <rpc/types.h>
struct timev {
int second;
int minute;
int hour;
};
typedef struct timev timev;
bool_t xdr_timev();
#define TIME_PROG 0x40000001
#define TIME_VERS 1
#define TIME_GET 1
|
MT User Mode
In MT User mode, the RPC library does not create any threads. This mode
works, in principle, like the single-threaded, or default mode. The only difference
is that it passes copies of data structures, such as the transport service
handle to the service-dispatch routine to be MT safe.
The RPC server developer takes the responsibility for creating and managing
threads through the thread library. In the dispatch routine, the service developer
can assign the task of procedure execution to newly created or existing threads.
The thr_create() API is used to create threads having various
attributes. All thread library interfaces are defined in thread.h. See the pthread_create(3THR) man page for more details.
This mode provides flexibility to the service developer. Threads can
now have different stack sizes based on service requirements. Threads can
be bound. Different procedures can be executed by threads with different characteristics.
The service developer might choose to run some services single threaded. The
service developer might choose to do special thread-specific signal processing.
As in the Auto mode, you use the rpc_control() library
call to turn on User mode. Note that the rpc_control()
operations shown in Table 7-1, except for RPC_SVC_MTMODE_GET(), apply only to MT Auto mode. If used in MT User
mode or the single-threaded default mode, the results of the operations can
be undefined.
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();
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;
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,
tout);
} 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)
xdr_intpair,
(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);
}
|