In the Automatic mode, the RPC library creates and manages threads. The service developer invokes a new interface call, rpc_control(), to put the server into MT Auto mode before invoking the svc_run() call. In this mode, the programmer needs only to ensure that service procedures are MT safe.
rpc_control() allows applications to set and modify global RPC attributes. At present, it supports only server-side operations. Table 4-8 shows the rpc_control() operations defined for Auto mode. See also the rpc_control(3N) man page for additional information.
Table 4-8 rpc_control() Library Routines
Set multithread mode |
|
Get multithread mode |
|
Set Maximum number of threads |
|
Get Maximum number of threads |
|
Total number of threads currently active |
|
Cumulative total number of threads created by the RPC library |
|
Number of thr_create errors within RPC library |
All of the get operations in Table 4-8, except RPC_SVC_MTMODE_GET(), apply only to the Auto MT mode. If used in MT User mode or the single-threaded default mode, the results of the operations may be undefined.
By default, the maximum number of threads that the RPC server library creates at any time is 16. If a server needs to process more than 16 client requests concurrently, the maximum number of threads must be set to the desired number. This parameter may be set at any time by the server, and it allows the service developer to put an upper bound on the thread resources consumed by the server. Failed Cross Reference Format is an example RPC program written in MT Auto mode. In this case, the maximum number of threads is set at 20.
MT performance is enhanced if the function svc_getargs() is called by every procedure other than NULLPROCS, even if there are no arguments (xdr_void() may be used in this case). This is true for both the MT Auto and MT User modes. For more information on this call, see the rpc_svc_calls(3N)man page.
Failed Cross Reference Format illustrates the server in MT Auto mode.
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. To do this, specify the -lthread option in the compile command.
Compile the program in Failed Cross Reference Formatby typing:
$ cc time_svc.c -lnsl -lthread
#include <stdio.h> #include <rpc/rpc.h> #include <synch.h> #include <thread.h> #include "time_prot.h" void time_prog(); main(argc, argv) int argc; char *argv[]; { int transpnum; char *nettype; int mode = RPC_SVC_MT_AUTO; int max = 20; /* Set maximum number of threads to 20 */ if (argc > 2) { fprintf(stderr, "usage: %s [nettype]\n", argv[0]); exit(1); } if (argc == 2) nettype = argv[1]; else nettype = "netpath"; if (!rpc_control(RPC_SVC_MTMODE_SET, &mode)) { printf("RPC_SVC_MTMODE_SET: failed\n"); exit(1); } if (!rpc_control(RPC_SVC_THRMAX_SET, &max)) { printf("RPC_SVC_THRMAX_SET: failed\n"); exit(1); } transpnum = svc_create( time_prog, TIME_PROG, TIME_VERS, nettype); if (transpnum == 0) { fprintf(stderr, "%s: cannot create %s service.\n", argv[0], nettype); exit(1); } svc_run(); } /* * The server dispatch function. * The RPC server library creates a thread which executes * the server dispatcher routine time_prog(). After which * the RPC library will take care of destroying the thread. */ static void time_prog(rqstp, transp) struct svc_req *rqstp; SVCXPRT *transp; { switch (rqstp->rq_proc) { case NULLPROC: svc_sendreply(transp, xdr_void, NULL); return; case TIME_GET: dotime(transp); break; default: svcerr_noproc(transp); return; } } dotime(transp) SVCXPRT *transp; { struct timev rslt; time_t thetime; thetime = time((time_t *)0); rslt.second = thetime % 60; thetime /= 60; rslt.minute = thetime % 60; thetime /= 60; rslt.hour = thetime % 24; if (!svc_sendreply(transp, xdr_timev,(caddr_t) &rslt)) { svcerr_systemerr(transp); } } |
Example 4-35 shows the time_prot.h header file for the server.
#include <rpc/types.h> struct timev { int second; int minute; int hour; }; typedef struct timev timev; bool_t xdr_timev(); #define TIME_PROG ((u_long)0x40000001) #define TIME_VERS ((u_long) 1) #define TIME_GET ((u_long) 1) |