The server-side code should not use statics to store returned results.
A pointer to the result is passed in and this should be used to pass the result
back to the calling routine. A return value of 1 indicates success to the
calling routine, while 0 indicates a failure.
In addition, the code generated by rpcgen also generates
a call to a routine to free any memory that might have been allocated when
the procedure was called. To prevent memory leaks, any memory allocated in
the service routine needs to be freed in this routine. messageprog_1_freeresult() frees the memory.
Normally, xdr_free() frees any allocated memory for
you. In this example, no memory was allocated, so no freeing needs to take
place.
The following add.x file shows the use of the -M flag with the C-style and ANSI C flag.
Example 3-18 MT-Safe Program: add.x
program ADDPROG {
version ADDVER {
int add(int, int) = 1;
} = 1;
}= 199;
|
This program adds two numbers and returns its result to the client.
rpcgen is invoked on it, with the rpcgen -N
-M -C add.x command. The following example shows the multithreaded
client code to call this code.
Example 3-19 MT-Safe Client: add.x
/*
* This client-side main routine
* starts up a number of threads,
* each of which calls the server
* concurrently.
*/
#include "add.h"
CLIENT *clnt;
#define NUMCLIENTS 5
struct argrec {
int arg1;
int arg2;
};
/* Keeps count of number of
* threads running
*/
int numrunning;
mutex_t numrun_lock;
cond_t condnum;
void
addprog(struct argrec *args)
{
enum clnt_stat retval;
int result;
/* call server code */
retval = add_1(args->arg1, args->arg2,
&result, clnt);
if (retval != RPC_SUCCESS) {
clnt_perror(clnt, "call failed");
} else
printf("thread #%x call succeeded,
result = %d\n", thr_getself(),
result);
/* decrement the number of running
* threads
*/
mutex_lock(&numrun_lock);
numrunning--;
cond_signal(&condnum);
mutex_unlock(&numrun_lock);
thr_exit(NULL);
}
main(int argc, char *argv[])
{
char *host;
struct argrec args[NUMCLIENTS];
int i;
thread_t mt;
int ret;
if (argc < 2) {
printf("usage: %s server_host\n",
argv[0]);
exit(1);
}
host = argv[1];
clnt = clnt_create(host, ADDPROG, ADDVER,
"netpath");
if (clnt == (CLIENT *) NULL) {
clnt_pcreateerror(host);
exit(1);
};
mutex_init(&numrun_lock, USYNC_THREAD, NULL);
cond_init(&condnum, USYNC_THREAD, NULL);
numrunning = 0;
/* Start up separate threads */
for (i = 0; i < NUMCLIENTS; i++) {
args[i].arg1 = i;
args[i].arg2 = i + 1;
ret = thr_create(NULL, NULL, addprog,
(char *) &args[i],
THR_NEW_LWP, &mt);
if (ret == 0)
numrunning++;
}
mutex_lock(&numrun_lock);
/* are any threads still running ? */
while (numrunning != 0)
cond_wait(&condnum, &numrun_lock);
mutex_unlock(&numrun_lock);
clnt_destroy(clnt);}
|
The server-side procedure is shown in the following example.
Note - When compiling a server that uses MT-safe mode, you must link
in the threads library. To do so, specify the -lthread option
in the compile command.
Example 3-20 MT-Safe Server: add.x
add_1_svc(int arg1, int arg2,
int *result, struct svc_req *rqstp)
{
bool_t retval;
/* Compute result */
*result = arg1 + arg2;
retval = 1;
return (retval);
}
/* Routine for freeing memory that may
* be allocated in the server procedure
*/
int
addprog_1_freeresult(SVCXPRT *transp,
xdrproc_t xdr_result,
caddr_t result)
{
(void) xdr_free(xdr_result, result);
}
|