On Mon, Aug 08, 2016 at 04:04:33PM +0200, Alexander Bluhm wrote: > On Mon, Aug 08, 2016 at 12:17:30PM +0200, Martin Pieuchot wrote: > > On 07/30/16 02:41, Alexander Bluhm wrote: > > Are you sure it is not set? Or does the scheduler keeps selecting your > > task? > > After some printf debugging I can say that it is not set. The > scheduler is switching between softnet and sosplice tasks. So > neither of the threads is going through roundrobin() twice. User > land is not scheduled.
The user land was not scheduled as the kernel task priority number is too low. The SPCF_SHOULDYIELD mechanism in roundrobin() did not help as I have two running kernel threads. I think long running kernel threads should have the same priority as user land. Without kernel threads involved, it makes sense to sleep with low priority. But when a thread is bored, it should wake up with user priority. Then it cannot block user processes. So I changed the priority of all kernel tasks and my user land is running fine. bluhm Index: kern/kern_task.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/kern/kern_task.c,v retrieving revision 1.17 diff -u -p -r1.17 kern_task.c --- kern/kern_task.c 8 Dec 2015 11:48:54 -0000 1.17 +++ kern/kern_task.c 11 Aug 2016 23:22:50 -0000 @@ -253,7 +253,7 @@ taskq_next_work(struct taskq *tq, struct return (0); } - tqsleep(tq, &tq->tq_mtx, PWAIT, "bored", 0); + tqsleep(tq, &tq->tq_mtx, PUSER, "bored", 0); } TAILQ_REMOVE(&tq->tq_worklist, next, t_entry); Index: kern/uipc_socket.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/kern/uipc_socket.c,v retrieving revision 1.152 diff -u -p -r1.152 uipc_socket.c --- kern/uipc_socket.c 13 Jun 2016 21:24:43 -0000 1.152 +++ kern/uipc_socket.c 11 Aug 2016 23:22:50 -0000 @@ -59,6 +59,7 @@ void sbsync(struct sockbuf *, struct mbu int sosplice(struct socket *, int, off_t, struct timeval *); void sounsplice(struct socket *, struct socket *, int); void soidle(void *); +void sotask(void *); int somove(struct socket *, int); void filt_sordetach(struct knote *kn); @@ -85,6 +86,7 @@ int sominconn = SOMINCONN; struct pool socket_pool; #ifdef SOCKET_SPLICE struct pool sosplice_pool; +struct taskq *sosplice_taskq; #endif void @@ -1041,6 +1043,7 @@ sorflush(struct socket *so) #define so_splicemax so_sp->ssp_max #define so_idletv so_sp->ssp_idletv #define so_idleto so_sp->ssp_idleto +#define so_splicetask so_sp->ssp_task int sosplice(struct socket *so, int fd, off_t max, struct timeval *tv) @@ -1049,6 +1052,12 @@ sosplice(struct socket *so, int fd, off_ struct socket *sosp; int s, error = 0; + if (sosplice_taskq == NULL) + sosplice_taskq = taskq_create("sosplice", 1, IPL_SOFTNET, + TASKQ_CANTSLEEP); + if (sosplice_taskq == NULL) + return (ENOMEM); + if ((so->so_proto->pr_flags & PR_SPLICE) == 0) return (EPROTONOSUPPORT); if (so->so_options & SO_ACCEPTCONN) @@ -1126,6 +1135,7 @@ sosplice(struct socket *so, int fd, off_ else timerclear(&so->so_idletv); timeout_set(&so->so_idleto, soidle, so); + task_set(&so->so_splicetask, sotask, so); /* * To prevent softnet interrupt from calling somove() while @@ -1149,6 +1159,7 @@ sounsplice(struct socket *so, struct soc { splsoftassert(IPL_SOFTNET); + task_del(sosplice_taskq, &so->so_splicetask); timeout_del(&so->so_idleto); sosp->so_snd.sb_flagsintr &= ~SB_SPLICE; so->so_rcv.sb_flagsintr &= ~SB_SPLICE; @@ -1171,6 +1182,24 @@ soidle(void *arg) splx(s); } +void +sotask(void *arg) +{ + struct socket *so = arg; + int s; + + s = splsoftnet(); + if (so->so_rcv.sb_flagsintr & SB_SPLICE) { + /* + * We may not sleep here as sofree() and unsplice() may be + * called from softnet interrupt context. This would remove + * the socket during somove(). + */ + somove(so, M_DONTWAIT); + } + splx(s); +} + /* * Move data from receive buffer of spliced source socket to send * buffer of drain socket. Try to move as much as possible in one @@ -1444,19 +1473,26 @@ somove(struct socket *so, int wait) return (1); } -#undef so_splicelen -#undef so_splicemax -#undef so_idletv -#undef so_idleto - #endif /* SOCKET_SPLICE */ void sorwakeup(struct socket *so) { #ifdef SOCKET_SPLICE - if (so->so_rcv.sb_flagsintr & SB_SPLICE) - (void) somove(so, M_DONTWAIT); + if (so->so_rcv.sb_flagsintr & SB_SPLICE) { + /* + * TCP has a sendbuffer that can handle multiple packets + * at once. So queue the stream a bit to accumulate data. + * The sosplice thread will call somove() later and send + * the packets calling tcp_output() only once. + * In the UDP case, send out the packets immediately. + * Using a thread would make things slower. + */ + if (so->so_proto->pr_flags & PR_WANTRCVD) + task_add(sosplice_taskq, &so->so_splicetask); + else + somove(so, M_DONTWAIT); + } if (isspliced(so)) return; #endif @@ -1470,7 +1506,7 @@ sowwakeup(struct socket *so) { #ifdef SOCKET_SPLICE if (so->so_snd.sb_flagsintr & SB_SPLICE) - (void) somove(so->so_sp->ssp_soback, M_DONTWAIT); + task_add(sosplice_taskq, &so->so_sp->ssp_soback->so_splicetask); #endif sowakeup(so, &so->so_snd); } Index: sys/socketvar.h =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/sys/socketvar.h,v retrieving revision 1.61 diff -u -p -r1.61 socketvar.h --- sys/socketvar.h 28 Jun 2016 14:47:00 -0000 1.61 +++ sys/socketvar.h 11 Aug 2016 23:21:09 -0000 @@ -34,6 +34,7 @@ #include <sys/selinfo.h> /* for struct selinfo */ #include <sys/queue.h> +#include <sys/task.h> #include <sys/timeout.h> #include <sys/rwlock.h> @@ -92,6 +93,7 @@ struct socket { off_t ssp_max; /* maximum number of bytes */ struct timeval ssp_idletv; /* idle timeout */ struct timeout ssp_idleto; + struct task ssp_task; /* task for somove */ } *so_sp; /* * Variables for socket buffering.