Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/netbsd-3]: src/sys/arch/xen/xen Pull up revision 1.3 (requested by yamt ...
details: https://anonhg.NetBSD.org/src/rev/340df120fe02
branches: netbsd-3
changeset: 575366:340df120fe02
user: tron <tron%NetBSD.org@localhost>
date: Wed Apr 13 21:38:45 2005 +0000
description:
Pull up revision 1.3 (requested by yamt in ticket #146):
fix a bug which corrupts runqueue.
when dealing with events, which are handed to xenevt pseudo device,
don't call wakeup(9)/selnotify(9) at too high IPL. PR/29792.
diffstat:
sys/arch/xen/xen/xenevt.c | 184 ++++++++++++++++++++++++++++++++++++---------
1 files changed, 145 insertions(+), 39 deletions(-)
diffs (256 lines):
diff -r 862e682dd68c -r 340df120fe02 sys/arch/xen/xen/xenevt.c
--- a/sys/arch/xen/xen/xenevt.c Wed Apr 13 21:38:38 2005 +0000
+++ b/sys/arch/xen/xen/xenevt.c Wed Apr 13 21:38:45 2005 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: xenevt.c,v 1.2 2005/03/09 22:39:21 bouyer Exp $ */
+/* $NetBSD: xenevt.c,v 1.2.2.1 2005/04/13 21:38:45 tron Exp $ */
/*
* Copyright (c) 2005 Manuel Bouyer.
@@ -87,6 +87,9 @@
#define XENEVT_RING_SIZE 2048
#define XENEVT_RING_MASK 2047
struct xenevt_d {
+ struct simplelock lock;
+ STAILQ_ENTRY(xenevt_d) pendingq;
+ boolean_t pending;
u_int16_t ring[2048];
u_int ring_read; /* pointer of the reader */
u_int ring_write; /* pointer of the writer */
@@ -98,6 +101,13 @@
/* event -> user device mapping */
static struct xenevt_d *devevent[NR_EVENT_CHANNELS];
+/* pending events */
+struct simplelock devevent_pending_lock = SIMPLELOCK_INITIALIZER;
+STAILQ_HEAD(, xenevt_d) devevent_pending =
+ STAILQ_HEAD_INITIALIZER(devevent_pending);
+
+static void xenevt_donotify(struct xenevt_d *);
+static void xenevt_record(struct xenevt_d *, int);
/* called at boot time */
void
@@ -110,26 +120,94 @@
void
xenevt_event(int port)
{
+ struct xenevt_d *d;
+ struct cpu_info *ci;
+
hypervisor_mask_event(port);
hypervisor_clear_event(port);
- if (devevent[port] != NULL) {
- /*
- * This algorithm overflows for one less slot than available.
- * Not really an issue, and the correct algorithm would be more
- * complex
- */
-
- if (devevent[port]->ring_read ==
- ((devevent[port]->ring_write + 1) & XENEVT_RING_MASK)) {
- devevent[port]->flags |= XENEVT_F_OVERFLOW;
- printf("xenevt_event: ring overflow port %d\n", port);
+ d = devevent[port];
+ if (d != NULL) {
+ xenevt_record(d, port);
+
+ if (d->pending) {
+ return;
+ }
+
+ ci = curcpu();
+
+ if (ci->ci_ilevel < IPL_SOFTXENEVT) {
+ /* fast and common path */
+ ci->ci_isources[SIR_XENEVT]->is_evcnt.ev_count++;
+ xenevt_donotify(d);
} else {
- devevent[port]->ring[devevent[port]->ring_write] = port;
- devevent[port]->ring_write =
- (devevent[port]->ring_write + 1) & XENEVT_RING_MASK;
+ simple_lock(&devevent_pending_lock);
+ STAILQ_INSERT_TAIL(&devevent_pending, d, pendingq);
+ simple_unlock(&devevent_pending_lock);
+ d->pending = TRUE;
+ softintr(SIR_XENEVT);
+ }
+ }
+}
+
+void
+xenevt_notify()
+{
+
+ cli();
+ simple_lock(&devevent_pending_lock);
+ while (/* CONSTCOND */ 1) {
+ struct xenevt_d *d;
+
+ d = STAILQ_FIRST(&devevent_pending);
+ if (d == NULL) {
+ break;
}
- selnotify(&devevent[port]->sel, 1);
- wakeup(&devevent[port]->ring_read);
+ STAILQ_REMOVE_HEAD(&devevent_pending, pendingq);
+ simple_unlock(&devevent_pending_lock);
+ sti();
+
+ d->pending = FALSE;
+ xenevt_donotify(d);
+
+ cli();
+ simple_lock(&devevent_pending_lock);
+ }
+ simple_unlock(&devevent_pending_lock);
+ sti();
+}
+
+static void
+xenevt_donotify(struct xenevt_d *d)
+{
+ int s;
+
+ s = splsoftxenevt();
+ simple_lock(&d->lock);
+
+ selnotify(&d->sel, 1);
+ wakeup(&d->ring_read);
+
+ simple_unlock(&d->lock);
+ splx(s);
+}
+
+static void
+xenevt_record(struct xenevt_d *d, int port)
+{
+
+ /*
+ * This algorithm overflows for one less slot than available.
+ * Not really an issue, and the correct algorithm would be more
+ * complex
+ */
+
+ if (d->ring_read ==
+ ((d->ring_write + 1) & XENEVT_RING_MASK)) {
+ d->flags |= XENEVT_F_OVERFLOW;
+ printf("xenevt_event: ring overflow port %d\n", port);
+ } else {
+ d->ring[d->ring_write] = port;
+ d->ring_write = (d->ring_write + 1) & XENEVT_RING_MASK;
}
}
@@ -146,6 +224,7 @@
return error;
d = malloc(sizeof(*d), M_DEVBUF, M_WAITOK | M_ZERO);
+ simple_lock_init(&d->lock);
return fdclone(p, fp, fd, flags, &xenevt_fileops, d);
}
@@ -175,45 +254,71 @@
struct xenevt_d *d = fp->f_data;
int error;
size_t len, uio_len;
+ int ring_read;
+ int ring_write;
+ int s;
- while (d->ring_read == d->ring_write) {
- if (d->flags & XENEVT_F_OVERFLOW)
- return EFBIG;
+ error = 0;
+ s = splsoftxenevt();
+ simple_lock(&d->lock);
+ while (error == 0) {
+ ring_read = d->ring_read;
+ ring_write = d->ring_write;
+ if (ring_read != ring_write) {
+ break;
+ }
+ if (d->flags & XENEVT_F_OVERFLOW) {
+ break;
+ }
+
/* nothing to read */
- if (fp->f_flag & FNONBLOCK)
- return (EAGAIN);
- error = tsleep(&d->ring_read, PRIBIO | PCATCH, "xenevt", 0);
- if (error == EINTR || error == ERESTART) {
- return(error);
+ if (fp->f_flag & FNONBLOCK) {
+ error = EAGAIN;
+ } else {
+ error = ltsleep(&d->ring_read, PRIBIO | PCATCH,
+ "xenevt", 0, &d->lock);
}
- if (d->ring_read != d->ring_write)
- break;
+ }
+ if (error == 0 && (d->flags & XENEVT_F_OVERFLOW)) {
+ error = EFBIG;
}
- if (d->flags & XENEVT_F_OVERFLOW)
- return EFBIG;
+ simple_unlock(&d->lock);
+ splx(s);
+
+ if (error) {
+ return error;
+ }
uio_len = uio->uio_resid >> 1;
- if (d->ring_read <= d->ring_write)
- len = d->ring_write - d->ring_read;
+ if (ring_read <= ring_write)
+ len = ring_write - ring_read;
else
- len = XENEVT_RING_SIZE - d->ring_read;
+ len = XENEVT_RING_SIZE - ring_read;
if (len > uio_len)
len = uio_len;
- error = uiomove(&d->ring[d->ring_read], len << 1, uio);
+ error = uiomove(&d->ring[ring_read], len << 1, uio);
if (error)
return error;
- d->ring_read = (d->ring_read + len) & XENEVT_RING_MASK;
+ ring_read = (ring_read + len) & XENEVT_RING_MASK;
uio_len = uio->uio_resid >> 1;
if (uio_len == 0)
- return 0; /* we're done */
+ goto done;
/* ring wrapped, read the second part */
- len = d->ring_write - d->ring_read;
+ len = ring_write - ring_read;
if (len > uio_len)
len = uio_len;
- error = uiomove(&d->ring[d->ring_read], len << 1, uio);
+ error = uiomove(&d->ring[ring_read], len << 1, uio);
if (error)
return error;
- d->ring_read = (d->ring_read + len) & XENEVT_RING_MASK;
+ ring_read = (ring_read + len) & XENEVT_RING_MASK;
+
+done:
+ s = splsoftxenevt();
+ simple_lock(&d->lock);
+ d->ring_read = ring_read;
+ simple_unlock(&d->lock);
+ splx(s);
+
return 0;
}
@@ -235,8 +340,9 @@
return error;
for (i = 0; i < nentries; i++) {
if (chans[i] < NR_EVENT_CHANNELS &&
- devevent[chans[i]] == d)
+ devevent[chans[i]] == d) {
hypervisor_unmask_event(chans[i]);
+ }
}
return 0;
}
Home |
Main Index |
Thread Index |
Old Index