Module Name: src Committed By: pooka Date: Thu Jan 6 06:57:14 UTC 2011
Modified Files: src/lib/librumpclient: rumpclient.c src/lib/librumpuser: rumpuser_sp.c sp_common.c Log Message: Make rumpclient syscalls safe to call from signal handlers. To generate a diff of this commit: cvs rdiff -u -r1.11 -r1.12 src/lib/librumpclient/rumpclient.c cvs rdiff -u -r1.30 -r1.31 src/lib/librumpuser/rumpuser_sp.c cvs rdiff -u -r1.18 -r1.19 src/lib/librumpuser/sp_common.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/librumpclient/rumpclient.c diff -u src/lib/librumpclient/rumpclient.c:1.11 src/lib/librumpclient/rumpclient.c:1.12 --- src/lib/librumpclient/rumpclient.c:1.11 Wed Jan 5 17:14:50 2011 +++ src/lib/librumpclient/rumpclient.c Thu Jan 6 06:57:14 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: rumpclient.c,v 1.11 2011/01/05 17:14:50 pooka Exp $ */ +/* $NetBSD: rumpclient.c,v 1.12 2011/01/06 06:57:14 pooka Exp $ */ /* * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved. @@ -60,12 +60,95 @@ .spc_fd = -1, }; +/* + * This version of waitresp is optimized for single-threaded clients + * and is required by signal-safe clientside rump syscalls. + */ + +static void +releasercvlock(struct spclient *spc) +{ + + pthread_mutex_lock(&spc->spc_mtx); + if (spc->spc_istatus == SPCSTATUS_WANTED) + kickall(spc); + spc->spc_istatus = SPCSTATUS_FREE; +} + +static sigset_t fullset; +static int +waitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask) +{ + struct pollfd pfd; + int rv = 0; + + sendunlockl(spc); + + rw->rw_error = 0; + while (rw->rw_data == NULL && rw->rw_error == 0 + && spc->spc_state != SPCSTATE_DYING){ + /* are we free to receive? */ + if (spc->spc_istatus == SPCSTATUS_FREE) { + spc->spc_istatus = SPCSTATUS_BUSY; + pthread_mutex_unlock(&spc->spc_mtx); + + pfd.fd = spc->spc_fd; + pfd.events = POLLIN; + + switch (readframe(spc)) { + case 0: + releasercvlock(spc); + pthread_mutex_unlock(&spc->spc_mtx); + pollts(&pfd, 1, NULL, mask); + pthread_mutex_lock(&spc->spc_mtx); + continue; + case -1: + releasercvlock(spc); + rv = errno; + spc->spc_state = SPCSTATE_DYING; + continue; + default: + break; + } + + switch (spc->spc_hdr.rsp_class) { + case RUMPSP_RESP: + case RUMPSP_ERROR: + kickwaiter(spc); + break; + case RUMPSP_REQ: + handlereq(spc); + break; + default: + /* panic */ + break; + } + + releasercvlock(spc); + } else { + spc->spc_istatus = SPCSTATUS_WANTED; + pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx); + } + } + TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries); + pthread_mutex_unlock(&spc->spc_mtx); + pthread_cond_destroy(&rw->rw_cv); + + if (rv) + return rv; + if (spc->spc_state == SPCSTATE_DYING) + return ENOTCONN; + return rw->rw_error; +} + + static int syscall_req(struct spclient *spc, int sysnum, const void *data, size_t dlen, void **resp) { struct rsp_hdr rhdr; struct respwait rw; + sigset_t omask; int rv; rhdr.rsp_len = sizeof(rhdr) + dlen; @@ -73,17 +156,21 @@ rhdr.rsp_type = RUMPSP_SYSCALL; rhdr.rsp_sysnum = sysnum; + pthread_sigmask(SIG_SETMASK, &fullset, &omask); do { + putwait(spc, &rw, &rhdr); rv = dosend(spc, &rhdr, sizeof(rhdr)); rv = dosend(spc, data, dlen); if (rv) { unputwait(spc, &rw); + pthread_sigmask(SIG_SETMASK, &omask, NULL); return rv; } - rv = waitresp(spc, &rw); + rv = waitresp(spc, &rw, &omask); } while (rv == EAGAIN); + pthread_sigmask(SIG_SETMASK, &omask, NULL); *resp = rw.rw_data; return rv; @@ -95,6 +182,7 @@ struct handshake_fork rf; struct rsp_hdr rhdr; struct respwait rw; + sigset_t omask; int rv; /* performs server handshake */ @@ -106,6 +194,7 @@ else rhdr.rsp_handshake = HANDSHAKE_GUEST; + pthread_sigmask(SIG_SETMASK, &fullset, &omask); putwait(spc, &rw, &rhdr); rv = dosend(spc, &rhdr, sizeof(rhdr)); if (auth) { @@ -115,10 +204,12 @@ } if (rv != 0 || cancel) { unputwait(spc, &rw); + pthread_sigmask(SIG_SETMASK, &omask, NULL); return rv; } - rv = waitresp(spc, &rw); + rv = waitresp(spc, &rw, &omask); + pthread_sigmask(SIG_SETMASK, &omask, NULL); if (rv) return rv; @@ -133,6 +224,7 @@ { struct rsp_hdr rhdr; struct respwait rw; + sigset_t omask; int rv; rhdr.rsp_len = sizeof(rhdr); @@ -140,15 +232,17 @@ rhdr.rsp_type = RUMPSP_PREFORK; rhdr.rsp_error = 0; - + pthread_sigmask(SIG_SETMASK, &fullset, &omask); putwait(spc, &rw, &rhdr); rv = dosend(spc, &rhdr, sizeof(rhdr)); if (rv != 0) { unputwait(spc, &rw); + pthread_sigmask(SIG_SETMASK, &omask, NULL); return rv; } - rv = waitresp(spc, &rw); + rv = waitresp(spc, &rw, &omask); + pthread_sigmask(SIG_SETMASK, &omask, NULL); *resp = rw.rw_data; return rv; } @@ -263,7 +357,7 @@ send_anonmmap_resp(spc, spc->spc_hdr.rsp_reqno, mapaddr); break; default: - printf("PANIC: INVALID TYPE\n"); + printf("PANIC: INVALID TYPE %d\n", reqtype); abort(); break; } @@ -351,6 +445,7 @@ return -1; } + sigfillset(&fullset); return 0; } Index: src/lib/librumpuser/rumpuser_sp.c diff -u src/lib/librumpuser/rumpuser_sp.c:1.30 src/lib/librumpuser/rumpuser_sp.c:1.31 --- src/lib/librumpuser/rumpuser_sp.c:1.30 Wed Jan 5 22:57:01 2011 +++ src/lib/librumpuser/rumpuser_sp.c Thu Jan 6 06:57:14 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: rumpuser_sp.c,v 1.30 2011/01/05 22:57:01 pooka Exp $ */ +/* $NetBSD: rumpuser_sp.c,v 1.31 2011/01/06 06:57:14 pooka Exp $ */ /* * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: rumpuser_sp.c,v 1.30 2011/01/05 22:57:01 pooka Exp $"); +__RCSID("$NetBSD: rumpuser_sp.c,v 1.31 2011/01/06 06:57:14 pooka Exp $"); #include <sys/types.h> #include <sys/atomic.h> @@ -98,6 +98,82 @@ static pthread_mutex_t pfmtx; /* + * This version is for the server. It's optimized for multiple threads + * and is *NOT* reentrant wrt to signals + */ +static int +waitresp(struct spclient *spc, struct respwait *rw) +{ + struct pollfd pfd; + int rv = 0; + + sendunlockl(spc); + + rw->rw_error = 0; + while (rw->rw_data == NULL && rw->rw_error == 0 + && spc->spc_state != SPCSTATE_DYING){ + /* are we free to receive? */ + if (spc->spc_istatus == SPCSTATUS_FREE) { + int gotresp; + + spc->spc_istatus = SPCSTATUS_BUSY; + pthread_mutex_unlock(&spc->spc_mtx); + + pfd.fd = spc->spc_fd; + pfd.events = POLLIN; + + for (gotresp = 0; !gotresp; ) { + switch (readframe(spc)) { + case 0: + poll(&pfd, 1, INFTIM); + continue; + case -1: + rv = errno; + spc->spc_state = SPCSTATE_DYING; + goto cleanup; + default: + break; + } + + switch (spc->spc_hdr.rsp_class) { + case RUMPSP_RESP: + case RUMPSP_ERROR: + kickwaiter(spc); + gotresp = spc->spc_hdr.rsp_reqno == + rw->rw_reqno; + break; + case RUMPSP_REQ: + handlereq(spc); + break; + default: + /* panic */ + break; + } + } + cleanup: + pthread_mutex_lock(&spc->spc_mtx); + if (spc->spc_istatus == SPCSTATUS_WANTED) + kickall(spc); + spc->spc_istatus = SPCSTATUS_FREE; + } else { + spc->spc_istatus = SPCSTATUS_WANTED; + pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx); + } + } + + TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries); + pthread_mutex_unlock(&spc->spc_mtx); + + pthread_cond_destroy(&rw->rw_cv); + + if (rv) + return rv; + if (spc->spc_state == SPCSTATE_DYING) + return ENOTCONN; + return rw->rw_error; +} + +/* * Manual wrappers, since librump does not have access to the * user namespace wrapped interfaces. */ Index: src/lib/librumpuser/sp_common.c diff -u src/lib/librumpuser/sp_common.c:1.18 src/lib/librumpuser/sp_common.c:1.19 --- src/lib/librumpuser/sp_common.c:1.18 Wed Jan 5 17:14:50 2011 +++ src/lib/librumpuser/sp_common.c Thu Jan 6 06:57:14 2011 @@ -1,4 +1,4 @@ -/* $NetBSD: sp_common.c,v 1.18 2011/01/05 17:14:50 pooka Exp $ */ +/* $NetBSD: sp_common.c,v 1.19 2011/01/06 06:57:14 pooka Exp $ */ /* * Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved. @@ -347,78 +347,6 @@ } static int -waitresp(struct spclient *spc, struct respwait *rw) -{ - struct pollfd pfd; - int rv = 0; - - sendunlockl(spc); - - rw->rw_error = 0; - while (rw->rw_data == NULL && rw->rw_error == 0 - && spc->spc_state != SPCSTATE_DYING){ - /* are we free to receive? */ - if (spc->spc_istatus == SPCSTATUS_FREE) { - int gotresp; - - spc->spc_istatus = SPCSTATUS_BUSY; - pthread_mutex_unlock(&spc->spc_mtx); - - pfd.fd = spc->spc_fd; - pfd.events = POLLIN; - - for (gotresp = 0; !gotresp; ) { - switch (readframe(spc)) { - case 0: - poll(&pfd, 1, INFTIM); - continue; - case -1: - rv = errno; - spc->spc_state = SPCSTATE_DYING; - goto cleanup; - default: - break; - } - - switch (spc->spc_hdr.rsp_class) { - case RUMPSP_RESP: - case RUMPSP_ERROR: - kickwaiter(spc); - gotresp = spc->spc_hdr.rsp_reqno == - rw->rw_reqno; - break; - case RUMPSP_REQ: - handlereq(spc); - break; - default: - /* panic */ - break; - } - } - cleanup: - pthread_mutex_lock(&spc->spc_mtx); - if (spc->spc_istatus == SPCSTATUS_WANTED) - kickall(spc); - spc->spc_istatus = SPCSTATUS_FREE; - } else { - spc->spc_istatus = SPCSTATUS_WANTED; - pthread_cond_wait(&rw->rw_cv, &spc->spc_mtx); - } - } - - TAILQ_REMOVE(&spc->spc_respwait, rw, rw_entries); - pthread_mutex_unlock(&spc->spc_mtx); - - pthread_cond_destroy(&rw->rw_cv); - - if (rv) - return rv; - if (spc->spc_state == SPCSTATE_DYING) - return ENOTCONN; - return rw->rw_error; -} - -static int readframe(struct spclient *spc) { int fd = spc->spc_fd;