svn commit: r248649 - in head: share/man/man9 sys/kern sys/sys

Will Andrews will at firepipe.net
Sat Mar 23 16:45:31 UTC 2013


I agree about the name length, it is a bit obnoxious.  However, it is also
descriptive.  TQCB strikes me as perhaps a bit too far in the other
direction.  How about TQ_CALLBACK_?  Is there an existing (pseudo)
convention for callback names?

Thanks,
--Will.


On Sat, Mar 23, 2013 at 10:20 AM, <mdf at freebsd.org> wrote:

> On Sat, Mar 23, 2013 at 8:11 AM, Will Andrews <will at freebsd.org> wrote:
> > Author: will
> > Date: Sat Mar 23 15:11:53 2013
> > New Revision: 248649
> > URL: http://svnweb.freebsd.org/changeset/base/248649
> >
> > Log:
> >   Extend taskqueue(9) to enable per-taskqueue callbacks.
> >
> >   The scope of these callbacks is primarily to support actions that
> affect the
> >   taskqueue's thread environments.  They are entirely optional, and
> >   consequently are introduced as a new API: taskqueue_set_callback().
> >
> >   This interface allows the caller to specify that a taskqueue requires a
> >   callback and optional context pointer for a given callback type.
> >
> >   The callback types included in this commit can be used to register a
> >   constructor and destructor for thread-local storage using osd(9).  This
> >   allows a particular taskqueue to define that its threads require a
> specific
> >   type of TLS, without the need for a specially-orchestrated task-based
> >   mechanism for startup and shutdown in order to accomplish it.
> >
> >   Two callback types are supported at this point:
> >
> >   - TASKQUEUE_CALLBACK_TYPE_INIT, called by every thread when it starts,
> prior
> >     to processing any tasks.
> >   - TASKQUEUE_CALLBACK_TYPE_SHUTDOWN, called by every thread when it
> exits,
> >     after it has processed its last task but before the taskqueue is
> >     reclaimed.
> >
> >   While I'm here:
> >
> >   - Add two new macros, TQ_ASSERT_LOCKED and TQ_ASSERT_UNLOCKED, and use
> them
> >     in appropriate locations.
> >   - Fix taskqueue.9 to mention taskqueue_start_threads(), which is a
> required
> >     interface for all consumers of taskqueue(9).
> >
> >   Reviewed by:  kib (all), eadler (taskqueue.9), brd (taskqueue.9)
> >   Approved by:  ken (mentor)
> >   Sponsored by: Spectra Logic
> >   MFC after:    1 month
> >
> > Modified:
> >   head/share/man/man9/taskqueue.9
> >   head/sys/kern/subr_taskqueue.c
> >   head/sys/sys/taskqueue.h
> >
> > Modified: head/share/man/man9/taskqueue.9
> >
> ==============================================================================
> > --- head/share/man/man9/taskqueue.9     Sat Mar 23 14:52:31 2013
>  (r248648)
> > +++ head/share/man/man9/taskqueue.9     Sat Mar 23 15:11:53 2013
>  (r248649)
> > @@ -53,12 +53,23 @@ struct task {
> >         void                    *ta_context;    /* argument for handler
> */
> >  };
> >
> > +enum taskqueue_callback_type {
> > +       TASKQUEUE_CALLBACK_TYPE_INIT,
> > +       TASKQUEUE_CALLBACK_TYPE_SHUTDOWN,
> > +};
> > +
> > +typedef void (*taskqueue_callback_fn)(void *context);
> > +
> >  struct timeout_task;
> >  .Ed
> >  .Ft struct taskqueue *
> >  .Fn taskqueue_create "const char *name" "int mflags"
> "taskqueue_enqueue_fn enqueue" "void *context"
> >  .Ft struct taskqueue *
> >  .Fn taskqueue_create_fast "const char *name" "int mflags"
> "taskqueue_enqueue_fn enqueue" "void *context"
> > +.Ft int
> > +.Fn taskqueue_start_threads "struct taskqueue **tqp" "int count" "int
> pri" "const char *name" "..."
> > +.Ft void
> > +.Fn taskqueue_set_callback "struct taskqueue *queue" "enum
> taskqueue_callback_type cb_type" "taskqueue_callback_fn callback" "void
> *context"
> >  .Ft void
> >  .Fn taskqueue_free "struct taskqueue *queue"
> >  .Ft int
> > @@ -127,6 +138,23 @@ should be used to free the memory used b
> >  Any tasks that are on the queue will be executed at this time after
> >  which the thread servicing the queue will be signaled that it should
> exit.
> >  .Pp
> > +Once a taskqueue has been created, its threads should be started using
> > +.Fn taskqueue_start_threads .
> > +Callbacks may optionally be registered using
> > +.Fn taskqueue_set_callback .
> > +Currently, callbacks may be registered for the following purposes:
> > +.Bl -tag -width TASKQUEUE_CALLBACK_TYPE_SHUTDOWN
> > +.It Dv TASKQUEUE_CALLBACK_TYPE_INIT
> > +This callback is called by every thread in the taskqueue, before it
> executes
> > +any tasks.
> > +This callback must be set before the taskqueue's threads are started.
> > +.It Dv TASKQUEUE_CALLBACK_TYPE_SHUTDOWN
> > +This callback is called by every thread in the taskqueue, after it
> executes
> > +its last task.
> > +This callback will always be called before the taskqueue structure is
> > +reclaimed.
> > +.El
> > +.Pp
> >  To add a task to the list of tasks queued on a taskqueue, call
> >  .Fn taskqueue_enqueue
> >  with pointers to the queue and task.
> >
> > Modified: head/sys/kern/subr_taskqueue.c
> >
> ==============================================================================
> > --- head/sys/kern/subr_taskqueue.c      Sat Mar 23 14:52:31 2013
>  (r248648)
> > +++ head/sys/kern/subr_taskqueue.c      Sat Mar 23 15:11:53 2013
>  (r248649)
> > @@ -63,6 +63,8 @@ struct taskqueue {
> >         int                     tq_spin;
> >         int                     tq_flags;
> >         int                     tq_callouts;
> > +       taskqueue_callback_fn   tq_callbacks[TASKQUEUE_NUM_CALLBACKS];
> > +       void                    *tq_cb_contexts[TASKQUEUE_NUM_CALLBACKS];
> >  };
> >
> >  #define        TQ_FLAGS_ACTIVE         (1 << 0)
> > @@ -78,6 +80,7 @@ struct taskqueue {
> >                 else                                                    \
> >                         mtx_lock(&(tq)->tq_mutex);                      \
> >         } while (0)
> > +#define        TQ_ASSERT_LOCKED(tq)    mtx_assert(&(tq)->tq_mutex,
> MA_OWNED)
> >
> >  #define        TQ_UNLOCK(tq)
>         \
> >         do {                                                            \
> > @@ -86,6 +89,7 @@ struct taskqueue {
> >                 else                                                    \
> >                         mtx_unlock(&(tq)->tq_mutex);                    \
> >         } while (0)
> > +#define        TQ_ASSERT_UNLOCKED(tq)  mtx_assert(&(tq)->tq_mutex,
> MA_NOTOWNED)
> >
> >  void
> >  _timeout_task_init(struct taskqueue *queue, struct timeout_task
> *timeout_task,
> > @@ -137,6 +141,23 @@ taskqueue_create(const char *name, int m
> >                         MTX_DEF, "taskqueue");
> >  }
> >
> > +void
> > +taskqueue_set_callback(struct taskqueue *queue,
> > +    enum taskqueue_callback_type cb_type, taskqueue_callback_fn
> callback,
> > +    void *context)
> > +{
> > +
> > +       KASSERT(((cb_type >= TASKQUEUE_CALLBACK_TYPE_MIN) &&
> > +           (cb_type <= TASKQUEUE_CALLBACK_TYPE_MAX)),
> > +           ("Callback type %d not valid, must be %d-%d", cb_type,
> > +           TASKQUEUE_CALLBACK_TYPE_MIN, TASKQUEUE_CALLBACK_TYPE_MAX));
> > +       KASSERT((queue->tq_callbacks[cb_type] == NULL),
> > +           ("Re-initialization of taskqueue callback?"));
> > +
> > +       queue->tq_callbacks[cb_type] = callback;
> > +       queue->tq_cb_contexts[cb_type] = context;
> > +}
> > +
> >  /*
> >   * Signal a taskqueue thread to terminate.
> >   */
> > @@ -293,7 +314,7 @@ taskqueue_run_locked(struct taskqueue *q
> >         struct task *task;
> >         int pending;
> >
> > -       mtx_assert(&queue->tq_mutex, MA_OWNED);
> > +       TQ_ASSERT_LOCKED(queue);
> >         tb.tb_running = NULL;
> >         TAILQ_INSERT_TAIL(&queue->tq_active, &tb, tb_link);
> >
> > @@ -332,7 +353,7 @@ task_is_running(struct taskqueue *queue,
> >  {
> >         struct taskqueue_busy *tb;
> >
> > -       mtx_assert(&queue->tq_mutex, MA_OWNED);
> > +       TQ_ASSERT_LOCKED(queue);
> >         TAILQ_FOREACH(tb, &queue->tq_active, tb_link) {
> >                 if (tb->tb_running == task)
> >                         return (1);
> > @@ -489,6 +510,18 @@ taskqueue_start_threads(struct taskqueue
> >         return (0);
> >  }
> >
> > +static inline void
> > +taskqueue_run_callback(struct taskqueue *tq,
> > +    enum taskqueue_callback_type cb_type)
> > +{
> > +       taskqueue_callback_fn tq_callback;
> > +
> > +       TQ_ASSERT_UNLOCKED(tq);
> > +       tq_callback = tq->tq_callbacks[cb_type];
> > +       if (tq_callback != NULL)
> > +               tq_callback(tq->tq_cb_contexts[cb_type]);
> > +}
> > +
> >  void
> >  taskqueue_thread_loop(void *arg)
> >  {
> > @@ -496,6 +529,7 @@ taskqueue_thread_loop(void *arg)
> >
> >         tqp = arg;
> >         tq = *tqp;
> > +       taskqueue_run_callback(tq, TASKQUEUE_CALLBACK_TYPE_INIT);
> >         TQ_LOCK(tq);
> >         while ((tq->tq_flags & TQ_FLAGS_ACTIVE) != 0) {
> >                 taskqueue_run_locked(tq);
> > @@ -510,6 +544,15 @@ taskqueue_thread_loop(void *arg)
> >         }
> >         taskqueue_run_locked(tq);
> >
> > +       /*
> > +        * This thread is on its way out, so just drop the lock
> temporarily
> > +        * in order to call the shutdown callback.  This allows the
> callback
> > +        * to look at the taskqueue, even just before it dies.
> > +        */
> > +       TQ_UNLOCK(tq);
> > +       taskqueue_run_callback(tq, TASKQUEUE_CALLBACK_TYPE_SHUTDOWN);
> > +       TQ_LOCK(tq);
> > +
> >         /* rendezvous with thread that asked us to terminate */
> >         tq->tq_tcount--;
> >         wakeup_one(tq->tq_threads);
> > @@ -525,7 +568,7 @@ taskqueue_thread_enqueue(void *context)
> >         tqp = context;
> >         tq = *tqp;
> >
> > -       mtx_assert(&tq->tq_mutex, MA_OWNED);
> > +       TQ_ASSERT_LOCKED(tq);
> >         wakeup_one(tq);
> >  }
> >
> >
> > Modified: head/sys/sys/taskqueue.h
> >
> ==============================================================================
> > --- head/sys/sys/taskqueue.h    Sat Mar 23 14:52:31 2013        (r248648)
> > +++ head/sys/sys/taskqueue.h    Sat Mar 23 15:11:53 2013        (r248649)
> > @@ -47,6 +47,16 @@ struct timeout_task {
> >         int    f;
> >  };
> >
> > +enum taskqueue_callback_type {
> > +       TASKQUEUE_CALLBACK_TYPE_INIT,
> > +       TASKQUEUE_CALLBACK_TYPE_SHUTDOWN,
> > +};
> > +#define        TASKQUEUE_CALLBACK_TYPE_MIN
> TASKQUEUE_CALLBACK_TYPE_INIT
> > +#define        TASKQUEUE_CALLBACK_TYPE_MAX
> TASKQUEUE_CALLBACK_TYPE_SHUTDOWN
> > +#define        TASKQUEUE_NUM_CALLBACKS
> TASKQUEUE_CALLBACK_TYPE_MAX + 1
>
> This need parentheses to defensively guard against unexpected
> precedence of operators.
>
> While here, TASKQUEUE_CALLBACK_ is a very long prefix (19 characters!)
>  Can this be named TQCB_ instead so it's not so verbose?
>
> Thanks,
> matthew
>


More information about the svn-src-all mailing list