Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/lib Add reconnect code to librumpclient. In case the connec...
details: https://anonhg.NetBSD.org/src/rev/40ef8b11e092
branches: trunk
changeset: 761335:40ef8b11e092
user: pooka <pooka%NetBSD.org@localhost>
date: Mon Jan 24 17:47:51 2011 +0000
description:
Add reconnect code to librumpclient. In case the connection to
the kernel server is lost, the client will now automatically attempt
to reconnect.
Among other things, this makes it possible to "reboot" and restart
the TCP/IP stack from under firefox without any perceivable less
of service. If pages were loading at the time the TCP/IP server
was killed, there may be some broken links, but nothing a ctrl-r
cannot fix.
diffstat:
lib/librumpclient/rumpclient.c | 293 +++++++++++++++++++++++++++++++---------
lib/librumpuser/sp_common.c | 52 ++++++-
2 files changed, 269 insertions(+), 76 deletions(-)
diffs (truncated from 605 to 300 lines):
diff -r c4e187d3bdf1 -r 40ef8b11e092 lib/librumpclient/rumpclient.c
--- a/lib/librumpclient/rumpclient.c Mon Jan 24 17:30:38 2011 +0000
+++ b/lib/librumpclient/rumpclient.c Mon Jan 24 17:47:51 2011 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: rumpclient.c,v 1.17 2011/01/21 10:43:33 pooka Exp $ */
+/* $NetBSD: rumpclient.c,v 1.18 2011/01/24 17:47:51 pooka Exp $ */
/*
* Copyright (c) 2010, 2011 Antti Kantee. All Rights Reserved.
@@ -50,6 +50,7 @@
#include <pthread.h>
#include <signal.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -78,19 +79,51 @@
.spc_fd = -1,
};
-static int kq;
+static int kq = -1;
static sigset_t fullset;
+static int doconnect(int);
+static int handshake_req(struct spclient *, uint32_t *, int, bool);
+
+int didrecon;
+
static int
-waitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask)
+send_with_recon(struct spclient *spc, const void *data, size_t dlen)
{
+ int rv;
+
+ do {
+ rv = dosend(spc, data, dlen);
+ if (__predict_false(rv == ENOTCONN || rv == EBADF)) {
+ if ((rv = doconnect(1)) != 0)
+ continue;
+ if ((rv = handshake_req(&clispc, NULL, 0, true)) != 0)
+ continue;
+ rv = ENOTCONN;
+ break;
+ }
+ } while (__predict_false(rv != 0));
+
+ return rv;
+}
+
+static int
+cliwaitresp(struct spclient *spc, struct respwait *rw, sigset_t *mask,
+ bool keeplock)
+{
+ uint64_t mygen;
+ bool imalive = true;
pthread_mutex_lock(&spc->spc_mtx);
- sendunlockl(spc);
+ if (!keeplock)
+ sendunlockl(spc);
+ mygen = spc->spc_generation;
rw->rw_error = 0;
- while (!rw->rw_done && rw->rw_error == 0
- && spc->spc_state != SPCSTATE_DYING){
+ while (!rw->rw_done && rw->rw_error == 0) {
+ if (__predict_false(spc->spc_generation != mygen || !imalive))
+ break;
+
/* are we free to receive? */
if (spc->spc_istatus == SPCSTATUS_FREE) {
struct kevent kev[8];
@@ -105,7 +138,16 @@
case 0:
rv = host_kevent(kq, NULL, 0,
kev, __arraycount(kev), NULL);
- assert(rv > 0);
+
+ /*
+ * XXX: don't know how this can
+ * happen (timeout cannot expire
+ * since there isn't one), but
+ * it does happen
+ */
+ if (__predict_false(rv == 0))
+ continue;
+
for (i = 0; i < rv; i++) {
if (kev[i].filter
== EVFILT_SIGNAL)
@@ -116,7 +158,7 @@
continue;
case -1:
- spc->spc_state = SPCSTATE_DYING;
+ imalive = false;
goto cleanup;
default:
break;
@@ -160,12 +202,12 @@
pthread_mutex_unlock(&spc->spc_mtx);
pthread_cond_destroy(&rw->rw_cv);
- if (spc->spc_state == SPCSTATE_DYING)
+ if (spc->spc_generation != mygen || !imalive) {
return ENOTCONN;
+ }
return rw->rw_error;
}
-
static int
syscall_req(struct spclient *spc, int sysnum,
const void *data, size_t dlen, void **resp)
@@ -182,18 +224,18 @@
pthread_sigmask(SIG_SETMASK, &fullset, &omask);
do {
-
putwait(spc, &rw, &rhdr);
- rv = dosend(spc, &rhdr, sizeof(rhdr));
- rv = dosend(spc, data, dlen);
- if (rv) {
+ if ((rv = send_with_recon(spc, &rhdr, sizeof(rhdr))) != 0) {
unputwait(spc, &rw);
- pthread_sigmask(SIG_SETMASK, &omask, NULL);
- return rv;
+ continue;
+ }
+ if ((rv = send_with_recon(spc, data, dlen)) != 0) {
+ unputwait(spc, &rw);
+ continue;
}
- rv = waitresp(spc, &rw, &omask);
- } while (rv == EAGAIN);
+ rv = cliwaitresp(spc, &rw, &omask, false);
+ } while (rv == ENOTCONN || rv == EAGAIN);
pthread_sigmask(SIG_SETMASK, &omask, NULL);
*resp = rw.rw_data;
@@ -201,7 +243,7 @@
}
static int
-handshake_req(struct spclient *spc, uint32_t *auth, int cancel)
+handshake_req(struct spclient *spc, uint32_t *auth, int cancel, bool haslock)
{
struct handshake_fork rf;
struct rsp_hdr rhdr;
@@ -219,20 +261,28 @@
rhdr.rsp_handshake = HANDSHAKE_GUEST;
pthread_sigmask(SIG_SETMASK, &fullset, &omask);
- putwait(spc, &rw, &rhdr);
+ if (haslock)
+ putwait_locked(spc, &rw, &rhdr);
+ else
+ putwait(spc, &rw, &rhdr);
rv = dosend(spc, &rhdr, sizeof(rhdr));
if (auth) {
memcpy(rf.rf_auth, auth, AUTHLEN*sizeof(*auth));
rf.rf_cancel = cancel;
- rv = dosend(spc, &rf, sizeof(rf));
+ rv = send_with_recon(spc, &rf, sizeof(rf));
}
- if (rv != 0 || cancel) {
- unputwait(spc, &rw);
- pthread_sigmask(SIG_SETMASK, &omask, NULL);
- return rv;
+ if (rv || cancel) {
+ if (haslock)
+ unputwait_locked(spc, &rw);
+ else
+ unputwait(spc, &rw);
+ if (cancel) {
+ pthread_sigmask(SIG_SETMASK, &omask, NULL);
+ return rv;
+ }
+ } else {
+ rv = cliwaitresp(spc, &rw, &omask, haslock);
}
-
- rv = waitresp(spc, &rw, &omask);
pthread_sigmask(SIG_SETMASK, &omask, NULL);
if (rv)
return rv;
@@ -257,26 +307,51 @@
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;
- }
+ do {
+ putwait(spc, &rw, &rhdr);
+ rv = send_with_recon(spc, &rhdr, sizeof(rhdr));
+ if (rv != 0) {
+ unputwait(spc, &rw);
+ continue;
+ }
- rv = waitresp(spc, &rw, &omask);
+ rv = cliwaitresp(spc, &rw, &omask, false);
+ } while (rv == ENOTCONN || rv == EAGAIN);
pthread_sigmask(SIG_SETMASK, &omask, NULL);
+
*resp = rw.rw_data;
return rv;
}
+/*
+ * prevent response code from deadlocking with reconnect code
+ */
static int
+resp_sendlock(struct spclient *spc)
+{
+ int rv = 0;
+
+ pthread_mutex_lock(&spc->spc_mtx);
+ while (spc->spc_ostatus != SPCSTATUS_FREE) {
+ if (__predict_false(spc->spc_reconnecting)) {
+ rv = EBUSY;
+ goto out;
+ }
+ spc->spc_ostatus = SPCSTATUS_WANTED;
+ pthread_cond_wait(&spc->spc_cv, &spc->spc_mtx);
+ }
+ spc->spc_ostatus = SPCSTATUS_BUSY;
+
+ out:
+ pthread_mutex_unlock(&spc->spc_mtx);
+ return rv;
+}
+
+static void
send_copyin_resp(struct spclient *spc, uint64_t reqno, void *data, size_t dlen,
int wantstr)
{
struct rsp_hdr rhdr;
- int rv;
if (wantstr)
dlen = MIN(dlen, strlen(data)+1);
@@ -287,19 +362,17 @@
rhdr.rsp_type = RUMPSP_COPYIN;
rhdr.rsp_sysnum = 0;
- sendlock(spc);
- rv = dosend(spc, &rhdr, sizeof(rhdr));
- rv = dosend(spc, data, dlen);
+ if (resp_sendlock(spc) != 0)
+ return;
+ (void)dosend(spc, &rhdr, sizeof(rhdr));
+ (void)dosend(spc, data, dlen);
sendunlock(spc);
-
- return rv;
}
-static int
+static void
send_anonmmap_resp(struct spclient *spc, uint64_t reqno, void *addr)
{
struct rsp_hdr rhdr;
- int rv;
rhdr.rsp_len = sizeof(rhdr) + sizeof(addr);
rhdr.rsp_reqno = reqno;
@@ -307,12 +380,11 @@
rhdr.rsp_type = RUMPSP_ANONMMAP;
rhdr.rsp_sysnum = 0;
- sendlock(spc);
- rv = dosend(spc, &rhdr, sizeof(rhdr));
- rv = dosend(spc, &addr, sizeof(addr));
+ if (resp_sendlock(spc) != 0)
+ return;
+ (void)dosend(spc, &rhdr, sizeof(rhdr));
+ (void)dosend(spc, &addr, sizeof(addr));
sendunlock(spc);
-
- return rv;
}
int
@@ -383,7 +455,7 @@
break;
case RUMPSP_RAISE:
DPRINTF(("rump_sp handlereq: raise sig %d\n", rhdr->rsp_signo));
- raise(rhdr->rsp_signo);
+ raise((int)rhdr->rsp_signo);
/*
* We most likely have signals blocked, but the signal
Home |
Main Index |
Thread Index |
Old Index