diff options
Diffstat (limited to 'freebsd/sys/kern')
-rw-r--r-- | freebsd/sys/kern/kern_synch.c | 21 | ||||
-rw-r--r-- | freebsd/sys/kern/kern_uuid.c | 2 | ||||
-rw-r--r-- | freebsd/sys/kern/subr_sbuf.c | 15 | ||||
-rw-r--r-- | freebsd/sys/kern/subr_sleepqueue.c | 41 | ||||
-rw-r--r-- | freebsd/sys/kern/subr_taskqueue.c | 2 | ||||
-rwxr-xr-x | freebsd/sys/kern/sys_pipe.c | 30 | ||||
-rw-r--r-- | freebsd/sys/kern/tty.c | 6 | ||||
-rw-r--r-- | freebsd/sys/kern/uipc_socket.c | 2 |
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. */ |