// mc3_svc.c - Skeleton to invoke the remote procedures /* * This file was generated using rpcgen, then edited to suport * one thread per request and locks to guarantee mutual exclusion * when accesing shared data. */ #include #include #include #include "mc.h" static void mcprog_1(); pthread_mutex_t mutex; /* Used by threads to implement Critical */ /* Regions */ int main() { register SVCXPRT *transp; (void) pmap_unset(MCPROG, MCVERS); transp = svctcp_create(RPC_ANYSOCK, 0, 0); if (transp == 0) { fprintf(stderr, "cannot create tcp service."); exit(1); } if (!svc_register(transp, MCPROG, MCVERS, mcprog_1, IPPROTO_TCP)) { fprintf(stderr, "unable to register (MCPROG, MCVERS, tcp)."); exit(1); } /* Create a mutex */ if (pthread_mutex_init(&mutex, pthread_mutexattr_default)) { perror("pthread_mutex_init"); exit(1);} svc_run(); /* This thread waits here until there is a call from * a client. When there is a call mcprog_1 is called * automatically. When mcprog-1 returns, this thread * waits again in svc_run. */ fprintf(stderr, "svc_run returned"); /*It should not happen.*/ exit(1); /* NOTREACHED */ return 0; } typedef struct { /* Descriptor of a request from client */ pthread_t *threadp; /* Pointer to thread that will handle a request */ /* [There may be multiple active threads. Only */ /* last is kept track of.*/ union { mypair add_1_arg; mypair subtract_1_arg; } argument; char *result; char *(*local)(); struct svc_req *rqstp; SVCXPRT *transp; } request; static void handle(request * b); /* Function executed by thread */ /* mcprog_1 is invoked each time that there is a remote procedure * call from the client. It creates a request structure with * information about the transport used for the request, the * request received, the arguments of the call. It creates a * detached thread to services this request, and it gets out of * the way. Thus the server becomes ready to accept another call * from a client while the threads take care of the previous * client requests. */ static void mcprog_1(struct svc_req *rqstp, register SVCXPRT *transp) { request * requestp; /* * Allocate request structure */ if ((requestp = (request *)malloc(sizeof(request))) == 0) { perror("Malloc request"); exit(1);} requestp->transp = transp; requestp->rqstp = rqstp; bzero((char *)&(requestp->argument), sizeof(requestp->argument)); if (!svc_getargs(transp, (xdrproc_t)xdr_mypair, (char *)&(requestp->argument))) { svcerr_decode(transp); return; } /*create thread */ if ((requestp->threadp = (pthread_t *)malloc(sizeof(pthread_t))) == 0) { perror("Malloc pthread_t"); exit(1);} if (pthread_create(requestp->threadp, pthread_attr_default, (void *) handle, requestp) != 0) { perror("pthread_create"); exit(1);} //printf("thread created\n"); /* Code to reclaim the space allocated for thread objects. */ if (pthread_detach(requestp->threadp) == 0) { //printf("pthread detached\n"); } else { perror("pthread_detach error"); exit(1);} } static void handle( request * b) /* code executed by a thread */ { switch (b->rqstp->rq_proc) { case NULLPROC: (void) svc_sendreply(b->transp, (xdrproc_t)xdr_void, (char *)NULL); return; case ADD: b->local = (char *(*)()) add_1; break; case SUBTRACT: b->local = (char *(*)()) subtract_1; break; default: svcerr_noproc(b->transp); return; } if (pthread_mutex_lock(&mutex)) { perror("pthread_mutex_lock"); exit(1);} sleep(2); // Hack used to increase duration of critical region (b->result) = (*(b->local))(&(b->argument), b->rqstp); if (pthread_mutex_unlock(&mutex)) { perror("pthread_mutex_unlock"); exit(1);} if ((b->result) != NULL && !svc_sendreply(b->transp, (xdrproc_t)xdr_int, (char *)b->result)) { svcerr_systemerr(b->transp); } if (!svc_freeargs(b->transp, (xdrproc_t)xdr_mypair, (char *)&(b->argument))) { fprintf(stderr, "unable to free arguments"); exit(1); } /* Prevent memory leak */ free(b->threadp); free(b); return; }