summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/kern')
-rw-r--r--freebsd/sys/kern/kern_synch.c21
-rw-r--r--freebsd/sys/kern/kern_uuid.c2
-rw-r--r--freebsd/sys/kern/subr_sbuf.c15
-rw-r--r--freebsd/sys/kern/subr_sleepqueue.c41
-rw-r--r--freebsd/sys/kern/subr_taskqueue.c2
-rwxr-xr-xfreebsd/sys/kern/sys_pipe.c30
-rw-r--r--freebsd/sys/kern/tty.c6
-rw-r--r--freebsd/sys/kern/uipc_socket.c2
8 files changed, 89 insertions, 30 deletions
diff --git a/freebsd/sys/kern/kern_synch.c b/freebsd/sys/kern/kern_synch.c
index 9c0d1206..0335b269 100644
--- a/freebsd/sys/kern/kern_synch.c
+++ b/freebsd/sys/kern/kern_synch.c
@@ -138,7 +138,9 @@ int
_sleep(void *ident, struct lock_object *lock, int priority,
const char *wmesg, sbintime_t sbt, sbintime_t pr, int flags)
{
+#ifndef __rtems__
struct thread *td;
+#endif /* __rtems__ */
struct lock_class *class;
uintptr_t lock_state;
#ifndef __rtems__
@@ -148,7 +150,9 @@ _sleep(void *ident, struct lock_object *lock, int priority,
#endif /* __rtems__ */
WITNESS_SAVE_DECL(lock_witness);
+#ifndef __rtems__
td = curthread;
+#endif /* __rtems__ */
#ifdef KTRACE
if (KTRPOINT(td, KTR_CSW))
ktrcsw(1, 0, wmesg);
@@ -402,6 +406,23 @@ wakeup_one(void *ident)
kick_proc0();
}
+void
+wakeup_any(void *ident)
+#ifndef __rtems__
+{
+ int wakeup_swapper;
+
+ sleepq_lock(ident);
+ wakeup_swapper = sleepq_signal(ident, SLEEPQ_SLEEP | SLEEPQ_UNFAIR,
+ 0, 0);
+ sleepq_release(ident);
+ if (wakeup_swapper)
+ kick_proc0();
+}
+#else /* __rtems__ */
+RTEMS_ALIAS(_bsd_wakeup_one);
+#endif /* __rtems__ */
+
#ifndef __rtems__
static void
kdb_switch(void)
diff --git a/freebsd/sys/kern/kern_uuid.c b/freebsd/sys/kern/kern_uuid.c
index a2316b16..c2a5986a 100644
--- a/freebsd/sys/kern/kern_uuid.c
+++ b/freebsd/sys/kern/kern_uuid.c
@@ -301,7 +301,7 @@ sbuf_printf_uuid(struct sbuf *sb, struct uuid *uuid)
char buf[38];
snprintf_uuid(buf, sizeof(buf), uuid);
- return (sbuf_printf(sb, "%s", buf));
+ return (sbuf_cat(sb, buf));
}
/*
diff --git a/freebsd/sys/kern/subr_sbuf.c b/freebsd/sys/kern/subr_sbuf.c
index b51ed52c..c9696ab7 100644
--- a/freebsd/sys/kern/subr_sbuf.c
+++ b/freebsd/sys/kern/subr_sbuf.c
@@ -344,6 +344,21 @@ sbuf_setpos(struct sbuf *s, ssize_t pos)
}
/*
+ * Drain into a counter. Counts amount of data without producing output.
+ * Useful for cases like sysctl, where user may first request only size.
+ * This allows to avoid pointless allocation/freeing of large buffers.
+ */
+int
+sbuf_count_drain(void *arg, const char *data __unused, int len)
+{
+ size_t *sizep;
+
+ sizep = (size_t *)arg;
+ *sizep += len;
+ return (len);
+}
+
+/*
* Set up a drain function and argument on an sbuf to flush data to
* when the sbuf buffer overflows.
*/
diff --git a/freebsd/sys/kern/subr_sleepqueue.c b/freebsd/sys/kern/subr_sleepqueue.c
index 042c0b0d..537206fd 100644
--- a/freebsd/sys/kern/subr_sleepqueue.c
+++ b/freebsd/sys/kern/subr_sleepqueue.c
@@ -132,7 +132,7 @@ CTASSERT(powerof2(SC_TABLESIZE));
* c - sleep queue chain lock
*/
struct sleepqueue {
- TAILQ_HEAD(, thread) sq_blocked[NR_SLEEPQS]; /* (c) Blocked threads. */
+ struct threadqueue sq_blocked[NR_SLEEPQS]; /* (c) Blocked threads. */
u_int sq_blockedcnt[NR_SLEEPQS]; /* (c) N. of blocked threads. */
LIST_ENTRY(sleepqueue) sq_hash; /* (c) Chain and free list. */
LIST_HEAD(, sleepqueue) sq_free; /* (c) Free queues. */
@@ -1139,13 +1139,15 @@ sleepq_init(void *mem, int size, int flags)
}
/*
- * Find the highest priority thread sleeping on a wait channel and resume it.
+ * Find thread sleeping on a wait channel and resume it.
*/
int
sleepq_signal(void *wchan, int flags, int pri, int queue)
{
+ struct sleepqueue_chain *sc;
struct sleepqueue *sq;
#ifndef __rtems__
+ struct threadqueue *head;
struct thread *td, *besttd;
#else /* __rtems__ */
struct thread *besttd;
@@ -1162,16 +1164,33 @@ sleepq_signal(void *wchan, int flags, int pri, int queue)
("%s: mismatch between sleep/wakeup and cv_*", __func__));
#ifndef __rtems__
- /*
- * Find the highest priority thread on the queue. If there is a
- * tie, use the thread that first appears in the queue as it has
- * been sleeping the longest since threads are always added to
- * the tail of sleep queues.
- */
- besttd = TAILQ_FIRST(&sq->sq_blocked[queue]);
- TAILQ_FOREACH(td, &sq->sq_blocked[queue], td_slpq) {
- if (td->td_priority < besttd->td_priority)
+ head = &sq->sq_blocked[queue];
+ if (flags & SLEEPQ_UNFAIR) {
+ /*
+ * Find the most recently sleeping thread, but try to
+ * skip threads still in process of context switch to
+ * avoid spinning on the thread lock.
+ */
+ sc = SC_LOOKUP(wchan);
+ besttd = TAILQ_LAST_FAST(head, thread, td_slpq);
+ while (besttd->td_lock != &sc->sc_lock) {
+ td = TAILQ_PREV_FAST(besttd, head, thread, td_slpq);
+ if (td == NULL)
+ break;
besttd = td;
+ }
+ } else {
+ /*
+ * Find the highest priority thread on the queue. If there
+ * is a tie, use the thread that first appears in the queue
+ * as it has been sleeping the longest since threads are
+ * always added to the tail of sleep queues.
+ */
+ besttd = td = TAILQ_FIRST(head);
+ while ((td = TAILQ_NEXT(td, td_slpq)) != NULL) {
+ if (td->td_priority < besttd->td_priority)
+ besttd = td;
+ }
}
#else /* __rtems__ */
besttd = TAILQ_FIRST(&sq->sq_blocked[queue]);
diff --git a/freebsd/sys/kern/subr_taskqueue.c b/freebsd/sys/kern/subr_taskqueue.c
index 39d9f939..67e62fc8 100644
--- a/freebsd/sys/kern/subr_taskqueue.c
+++ b/freebsd/sys/kern/subr_taskqueue.c
@@ -841,7 +841,7 @@ taskqueue_thread_enqueue(void *context)
tqp = context;
tq = *tqp;
- wakeup_one(tq);
+ wakeup_any(tq);
}
TASKQUEUE_DEFINE(swi, taskqueue_swi_enqueue, NULL,
diff --git a/freebsd/sys/kern/sys_pipe.c b/freebsd/sys/kern/sys_pipe.c
index 817190b7..d714af89 100755
--- a/freebsd/sys/kern/sys_pipe.c
+++ b/freebsd/sys/kern/sys_pipe.c
@@ -817,7 +817,7 @@ pipe_read(struct file *fp, struct uio *uio, struct ucred *active_cred,
rpipe->pipe_map.pos += size;
rpipe->pipe_map.cnt -= size;
if (rpipe->pipe_map.cnt == 0) {
- rpipe->pipe_state &= ~(PIPE_DIRECTW|PIPE_WANTW);
+ rpipe->pipe_state &= ~PIPE_WANTW;
wakeup(rpipe);
}
#endif
@@ -1020,13 +1020,17 @@ pipe_build_write_buffer(struct pipe *wpipe, struct uio *uio)
}
/*
- * unmap and unwire the process buffer
+ * Unwire the process buffer.
*/
static void
pipe_destroy_write_buffer(struct pipe *wpipe)
{
PIPE_LOCK_ASSERT(wpipe, MA_OWNED);
+ KASSERT((wpipe->pipe_state & PIPE_DIRECTW) != 0,
+ ("%s: PIPE_DIRECTW not set on %p", __func__, wpipe));
+
+ wpipe->pipe_state &= ~PIPE_DIRECTW;
vm_page_unhold_pages(wpipe->pipe_map.ms, wpipe->pipe_map.npages);
wpipe->pipe_map.npages = 0;
}
@@ -1045,13 +1049,15 @@ pipe_clone_write_buffer(struct pipe *wpipe)
int pos;
PIPE_LOCK_ASSERT(wpipe, MA_OWNED);
+ KASSERT((wpipe->pipe_state & PIPE_DIRECTW) != 0,
+ ("%s: PIPE_DIRECTW not set on %p", __func__, wpipe));
+
size = wpipe->pipe_map.cnt;
pos = wpipe->pipe_map.pos;
wpipe->pipe_buffer.in = size;
wpipe->pipe_buffer.out = 0;
wpipe->pipe_buffer.cnt = size;
- wpipe->pipe_state &= ~PIPE_DIRECTW;
PIPE_UNLOCK(wpipe);
iov.iov_base = wpipe->pipe_buffer.buffer;
@@ -1090,7 +1096,7 @@ retry:
pipeunlock(wpipe);
goto error1;
}
- while (wpipe->pipe_state & PIPE_DIRECTW) {
+ if (wpipe->pipe_state & PIPE_DIRECTW) {
if (wpipe->pipe_state & PIPE_WANTR) {
wpipe->pipe_state &= ~PIPE_WANTR;
wakeup(wpipe);
@@ -1133,8 +1139,7 @@ retry:
goto error1;
}
- error = 0;
- while (!error && (wpipe->pipe_state & PIPE_DIRECTW)) {
+ while (wpipe->pipe_map.cnt != 0) {
if (wpipe->pipe_state & PIPE_EOF) {
pipe_destroy_write_buffer(wpipe);
pipeselwakeup(wpipe);
@@ -1152,20 +1157,19 @@ retry:
error = msleep(wpipe, PIPE_MTX(wpipe), PRIBIO | PCATCH,
"pipdwt", 0);
pipelock(wpipe, 0);
+ if (error != 0)
+ break;
}
if (wpipe->pipe_state & PIPE_EOF)
error = EPIPE;
- if (wpipe->pipe_state & PIPE_DIRECTW) {
- /*
- * this bit of trickery substitutes a kernel buffer for
- * the process that might be going away.
- */
+ if (error == EINTR || error == ERESTART)
pipe_clone_write_buffer(wpipe);
- } else {
+ else
pipe_destroy_write_buffer(wpipe);
- }
pipeunlock(wpipe);
+ KASSERT((wpipe->pipe_state & PIPE_DIRECTW) == 0,
+ ("pipe %p leaked PIPE_DIRECTW", wpipe));
return (error);
error1:
diff --git a/freebsd/sys/kern/tty.c b/freebsd/sys/kern/tty.c
index f4a2b01f..cce61944 100644
--- a/freebsd/sys/kern/tty.c
+++ b/freebsd/sys/kern/tty.c
@@ -233,9 +233,6 @@ ttydev_leave(struct tty *tp)
tp->t_flags |= TF_OPENCLOSE;
- /* Stop asynchronous I/O. */
- funsetown(&tp->t_sigio);
-
#ifndef __rtems__
/* Remove console TTY. */
if (constty == tp)
@@ -1138,6 +1135,9 @@ tty_rel_free(struct tty *tp)
return;
}
+ /* Stop asynchronous I/O. */
+ funsetown(&tp->t_sigio);
+
/* TTY can be deallocated. */
dev = tp->t_dev;
tp->t_dev = NULL;
diff --git a/freebsd/sys/kern/uipc_socket.c b/freebsd/sys/kern/uipc_socket.c
index 77356b83..762dfb56 100644
--- a/freebsd/sys/kern/uipc_socket.c
+++ b/freebsd/sys/kern/uipc_socket.c
@@ -2227,7 +2227,7 @@ soreceive_stream(struct socket *so, struct sockaddr **psa, struct uio *uio,
/* Prevent other readers from entering the socket. */
error = sblock(sb, SBLOCKWAIT(flags));
if (error)
- goto out;
+ return (error);
SOCKBUF_LOCK(sb);
/* Easy one, no space to copyout anything. */