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.

Reply via email to