On Thu, Sep 15, 2016 at 04:29:45PM +0200, Martin Pieuchot wrote:
> After discussing with a few people about a new "timed task" API I came
> to the conclusion that mixing timeouts and tasks will result in:
> 
>   - always including a 'struct timeout' in a 'struct task', or the other
>     the way around
> or
>   
>   - introducing a new data structure, hence API.
> 
> Since I'd like to keep the change as small as possible when converting
> existing timeout_set(9), neither option seem a good fit.  So I decided
> to add a new kernel thread, curiously named "softclock", that will
> offer his stack to the poor timeout handlers that need one. 
> 
> With this approach, converting a timeout is just a matter of doing:
> 
>       s/timeout_set/timeout_set_proc/
> 
> 
> Diff below includes the conversions I need for the "netlock".  I'm
> waiting for feedbacks and a better name to document the new function.
> 
> Comments?

I like this API, epsecially as we can switch easily between thread
and soft interrupt to try things.

OK bluhm@

> 
> Index: net/if_pflow.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_pflow.c,v
> retrieving revision 1.61
> diff -u -p -r1.61 if_pflow.c
> --- net/if_pflow.c    29 Apr 2016 08:55:03 -0000      1.61
> +++ net/if_pflow.c    15 Sep 2016 14:19:10 -0000
> @@ -548,15 +548,16 @@ pflow_init_timeouts(struct pflow_softc *
>               if (timeout_initialized(&sc->sc_tmo_tmpl))
>                       timeout_del(&sc->sc_tmo_tmpl);
>               if (!timeout_initialized(&sc->sc_tmo))
> -                     timeout_set(&sc->sc_tmo, pflow_timeout, sc);
> +                     timeout_set_proc(&sc->sc_tmo, pflow_timeout, sc);
>               break;
>       case PFLOW_PROTO_10:
>               if (!timeout_initialized(&sc->sc_tmo_tmpl))
> -                     timeout_set(&sc->sc_tmo_tmpl, pflow_timeout_tmpl, sc);
> +                     timeout_set_proc(&sc->sc_tmo_tmpl, pflow_timeout_tmpl,
> +                         sc);
>               if (!timeout_initialized(&sc->sc_tmo))
> -                     timeout_set(&sc->sc_tmo, pflow_timeout, sc);
> +                     timeout_set_proc(&sc->sc_tmo, pflow_timeout, sc);
>               if (!timeout_initialized(&sc->sc_tmo6))
> -                     timeout_set(&sc->sc_tmo6, pflow_timeout6, sc);
> +                     timeout_set_proc(&sc->sc_tmo6, pflow_timeout6, sc);
>  
>               timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT);
>               break;
> Index: net/if_pfsync.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_pfsync.c,v
> retrieving revision 1.231
> diff -u -p -r1.231 if_pfsync.c
> --- net/if_pfsync.c   15 Sep 2016 02:00:18 -0000      1.231
> +++ net/if_pfsync.c   15 Sep 2016 14:19:10 -0000
> @@ -328,9 +328,9 @@ pfsync_clone_create(struct if_clone *ifc
>       IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
>       ifp->if_hdrlen = sizeof(struct pfsync_header);
>       ifp->if_mtu = ETHERMTU;
> -     timeout_set(&sc->sc_tmo, pfsync_timeout, sc);
> -     timeout_set(&sc->sc_bulk_tmo, pfsync_bulk_update, sc);
> -     timeout_set(&sc->sc_bulkfail_tmo, pfsync_bulk_fail, sc);
> +     timeout_set_proc(&sc->sc_tmo, pfsync_timeout, sc);
> +     timeout_set_proc(&sc->sc_bulk_tmo, pfsync_bulk_update, sc);
> +     timeout_set_proc(&sc->sc_bulkfail_tmo, pfsync_bulk_fail, sc);
>  
>       if_attach(ifp);
>       if_alloc_sadl(ifp);
> @@ -1723,7 +1723,7 @@ pfsync_defer(struct pf_state *st, struct
>       sc->sc_deferred++;
>       TAILQ_INSERT_TAIL(&sc->sc_deferrals, pd, pd_entry);
>  
> -     timeout_set(&pd->pd_tmo, pfsync_defer_tmo, pd);
> +     timeout_set_proc(&pd->pd_tmo, pfsync_defer_tmo, pd);
>       timeout_add_msec(&pd->pd_tmo, 20);
>  
>       schednetisr(NETISR_PFSYNC);
> Index: netinet/ip_carp.c
> ===================================================================
> RCS file: /cvs/src/sys/netinet/ip_carp.c,v
> retrieving revision 1.293
> diff -u -p -r1.293 ip_carp.c
> --- netinet/ip_carp.c 25 Jul 2016 16:44:04 -0000      1.293
> +++ netinet/ip_carp.c 15 Sep 2016 14:19:11 -0000
> @@ -831,9 +831,9 @@ carp_new_vhost(struct carp_softc *sc, in
>       vhe->vhid = vhid;
>       vhe->advskew = advskew;
>       vhe->state = INIT;
> -     timeout_set(&vhe->ad_tmo, carp_send_ad, vhe);
> -     timeout_set(&vhe->md_tmo, carp_master_down, vhe);
> -     timeout_set(&vhe->md6_tmo, carp_master_down, vhe);
> +     timeout_set_proc(&vhe->ad_tmo, carp_send_ad, vhe);
> +     timeout_set_proc(&vhe->md_tmo, carp_master_down, vhe);
> +     timeout_set_proc(&vhe->md6_tmo, carp_master_down, vhe);
>  
>       KERNEL_ASSERT_LOCKED(); /* touching carp_vhosts */
>  
> Index: netinet/tcp_timer.h
> ===================================================================
> RCS file: /cvs/src/sys/netinet/tcp_timer.h,v
> retrieving revision 1.13
> diff -u -p -r1.13 tcp_timer.h
> --- netinet/tcp_timer.h       6 Jul 2011 23:44:20 -0000       1.13
> +++ netinet/tcp_timer.h       15 Sep 2016 14:19:11 -0000
> @@ -116,7 +116,7 @@ const char *tcptimers[] =
>   * Init, arm, disarm, and test TCP timers.
>   */
>  #define      TCP_TIMER_INIT(tp, timer)                                       
> \
> -     timeout_set(&(tp)->t_timer[(timer)], tcp_timer_funcs[(timer)], tp)
> +     timeout_set_proc(&(tp)->t_timer[(timer)], tcp_timer_funcs[(timer)], tp)
>  
>  #define      TCP_TIMER_ARM(tp, timer, nticks)                                
> \
>       timeout_add(&(tp)->t_timer[(timer)], (nticks) * (hz / PR_SLOWHZ))
> Index: netinet/tcp_var.h
> ===================================================================
> RCS file: /cvs/src/sys/netinet/tcp_var.h,v
> retrieving revision 1.115
> diff -u -p -r1.115 tcp_var.h
> --- netinet/tcp_var.h 20 Jul 2016 19:57:53 -0000      1.115
> +++ netinet/tcp_var.h 15 Sep 2016 14:19:11 -0000
> @@ -217,7 +217,7 @@ extern int tcp_delack_ticks;
>  void tcp_delack(void *);
>  
>  #define TCP_INIT_DELACK(tp)                                          \
> -     timeout_set(&(tp)->t_delack_to, tcp_delack, tp)
> +     timeout_set_proc(&(tp)->t_delack_to, tcp_delack, tp)
>  
>  #define TCP_RESTART_DELACK(tp)                                               
> \
>       timeout_add(&(tp)->t_delack_to, tcp_delack_ticks)
> Index: kern/init_main.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/init_main.c,v
> retrieving revision 1.257
> diff -u -p -r1.257 init_main.c
> --- kern/init_main.c  4 Sep 2016 09:22:29 -0000       1.257
> +++ kern/init_main.c  15 Sep 2016 14:19:10 -0000
> @@ -143,6 +143,7 @@ void      prof_init(void);
>  void init_exec(void);
>  void kqueue_init(void);
>  void taskq_init(void);
> +void timeout_proc_init(void);
>  void pool_gc_pages(void *);
>  
>  extern char sigcode[], esigcode[], sigcoderet[];
> @@ -334,6 +335,9 @@ main(void *framep)
>       sleep_queue_init();
>       sched_init_cpu(curcpu());
>       p->p_cpu->ci_randseed = (arc4random() & 0x7fffffff) + 1;
> +
> +     /* Initialize timeouts in process context. */
> +     timeout_proc_init();
>  
>       /* Initialize task queues */
>       taskq_init();
> Index: kern/kern_timeout.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/kern_timeout.c,v
> retrieving revision 1.48
> diff -u -p -r1.48 kern_timeout.c
> --- kern/kern_timeout.c       6 Jul 2016 15:53:01 -0000       1.48
> +++ kern/kern_timeout.c       15 Sep 2016 14:19:10 -0000
> @@ -27,7 +27,7 @@
>  
>  #include <sys/param.h>
>  #include <sys/systm.h>
> -#include <sys/lock.h>
> +#include <sys/kthread.h>
>  #include <sys/timeout.h>
>  #include <sys/mutex.h>
>  #include <sys/kernel.h>
> @@ -54,6 +54,7 @@
>  
>  struct circq timeout_wheel[BUCKETS]; /* Queues of timeouts */
>  struct circq timeout_todo;           /* Worklist */
> +struct circq timeout_proc;           /* Due timeouts needing proc. context */
>  
>  #define MASKWHEEL(wheel, time) (((time) >> ((wheel)*WHEELBITS)) & WHEELMASK)
>  
> @@ -127,6 +128,9 @@ struct mutex timeout_mutex = MUTEX_INITI
>  
>  #define CIRCQ_EMPTY(elem) (CIRCQ_FIRST(elem) == (elem))
>  
> +void softclock_thread(void *);
> +void softclock_create_thread(void *);
> +
>  /*
>   * Some of the "math" in here is a bit tricky.
>   *
> @@ -147,11 +151,18 @@ timeout_startup(void)
>       int b;
>  
>       CIRCQ_INIT(&timeout_todo);
> +     CIRCQ_INIT(&timeout_proc);
>       for (b = 0; b < nitems(timeout_wheel); b++)
>               CIRCQ_INIT(&timeout_wheel[b]);
>  }
>  
>  void
> +timeout_proc_init(void)
> +{
> +     kthread_create_deferred(softclock_create_thread, curcpu());
> +}
> +
> +void
>  timeout_set(struct timeout *new, void (*fn)(void *), void *arg)
>  {
>       new->to_func = fn;
> @@ -159,6 +170,12 @@ timeout_set(struct timeout *new, void (*
>       new->to_flags = TIMEOUT_INITIALIZED;
>  }
>  
> +void
> +timeout_set_proc(struct timeout *new, void (*fn)(void *), void *arg)
> +{
> +     timeout_set(new, fn, arg);
> +     new->to_flags |= TIMEOUT_NEEDPROCCTX;
> +}
>  
>  int
>  timeout_add(struct timeout *new, int to_ticks)
> @@ -334,38 +351,84 @@ timeout_hardclock_update(void)
>  }
>  
>  void
> +timeout_run(struct timeout *to)
> +{
> +     void (*fn)(void *);
> +     void *arg;
> +
> +     MUTEX_ASSERT_LOCKED(&timeout_mutex);
> +
> +     to->to_flags &= ~TIMEOUT_ONQUEUE;
> +     to->to_flags |= TIMEOUT_TRIGGERED;
> +
> +     fn = to->to_func;
> +     arg = to->to_arg;
> +
> +     mtx_leave(&timeout_mutex);
> +     fn(arg);
> +     mtx_enter(&timeout_mutex);
> +}
> +
> +void
>  softclock(void *arg)
>  {
>       int delta;
>       struct circq *bucket;
>       struct timeout *to;
> -     void (*fn)(void *);
>  
>       mtx_enter(&timeout_mutex);
>       while (!CIRCQ_EMPTY(&timeout_todo)) {
>               to = timeout_from_circq(CIRCQ_FIRST(&timeout_todo));
>               CIRCQ_REMOVE(&to->to_list);
>  
> -             /* If due run it, otherwise insert it into the right bucket. */
> +             /*
> +              * If due run it or defer execution to the thread,
> +              * otherwise insert it into the right bucket.
> +              */
>               delta = to->to_time - ticks;
>               if (delta > 0) {
>                       bucket = &BUCKET(delta, to->to_time);
>                       CIRCQ_INSERT(&to->to_list, bucket);
> +             } else if (to->to_flags & TIMEOUT_NEEDPROCCTX) {
> +                     CIRCQ_INSERT(&to->to_list, &timeout_proc);
> +                     wakeup(&timeout_proc);
>               } else {
>  #ifdef DEBUG
>                       if (delta < 0)
>                               printf("timeout delayed %d\n", delta);
>  #endif
> -                     to->to_flags &= ~TIMEOUT_ONQUEUE;
> -                     to->to_flags |= TIMEOUT_TRIGGERED;
> +                     timeout_run(to);
> +             }
> +     }
> +     mtx_leave(&timeout_mutex);
> +}
>  
> -                     fn = to->to_func;
> -                     arg = to->to_arg;
> +void
> +softclock_create_thread(void *xci)
> +{
> +     if (kthread_create(softclock_thread, xci, NULL, "softclock"))
> +             panic("fork softclock");
> +}
>  
> -                     mtx_leave(&timeout_mutex);
> -                     fn(arg);
> -                     mtx_enter(&timeout_mutex);
> -             }
> +void
> +softclock_thread(void *xci)
> +{
> +     struct cpu_info *ci = xci;
> +     struct timeout *to;
> +
> +     KERNEL_ASSERT_LOCKED();
> +
> +     /* Be conservative for the moment. */
> +     sched_peg_curproc(ci);
> +
> +     mtx_enter(&timeout_mutex);
> +     for (;;) {
> +             while (CIRCQ_EMPTY(&timeout_proc))
> +                     msleep(&timeout_proc, &timeout_mutex, PSWP, "bored", 0);
> +
> +             to = timeout_from_circq(CIRCQ_FIRST(&timeout_proc));
> +             CIRCQ_REMOVE(&to->to_list);
> +             timeout_run(to);
>       }
>       mtx_leave(&timeout_mutex);
>  }
> Index: sys/timeout.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/timeout.h,v
> retrieving revision 1.25
> diff -u -p -r1.25 timeout.h
> --- sys/timeout.h     22 Dec 2014 04:43:38 -0000      1.25
> +++ sys/timeout.h     15 Sep 2016 14:19:11 -0000
> @@ -67,6 +67,7 @@ struct timeout {
>  /*
>   * flags in the to_flags field.
>   */
> +#define TIMEOUT_NEEDPROCCTX  1       /* timeout needs a process context */
>  #define TIMEOUT_ONQUEUE              2       /* timeout is on the todo queue 
> */
>  #define TIMEOUT_INITIALIZED  4       /* timeout is initialized */
>  #define TIMEOUT_TRIGGERED    8       /* timeout is running or ran */
> @@ -88,6 +89,7 @@ struct timeout {
>  struct bintime;
>  
>  void timeout_set(struct timeout *, void (*)(void *), void *);
> +void timeout_set_proc(struct timeout *, void (*)(void *), void *);
>  int timeout_add(struct timeout *, int);
>  int timeout_add_tv(struct timeout *, const struct timeval *);
>  int timeout_add_ts(struct timeout *, const struct timespec *);

Reply via email to