Annotation of wikisrc/projects/project/kernel_continuations.mdwn, revision 1.3

1.1       jmmv        1: [[!template id=project
                      3: title="Kernel continuations"
                      5: contact="""
                      6: [tech-kern](,
                      7: [board](,
                      8: [core](
                      9: """
                     11: category="kernel"
                     12: difficulty="hard"
                     13: funded="The NetBSD Foundation"
                     15: description="""
                     16: This project proposal is a subtask of [[smp_networking]] and is elegible
                     17: for funding independently.
                     19: The goal of this project is to implement continuations at the kernel level.
                     20: Most of the pieces are already available in the kernel, so this can be
                     21: reworded as: combine *callouts*, *softints*, and *workqueues* into a single
1.2       plunky     22: framework.  Continuations are meant to be cheap; very cheap.
1.1       jmmv       23: 
1.3     ! dholland   24: These continuations are a dispatching system for making callbacks at
        !            25: scheduled times or in different thread/interrupt contexts.
        !            26: They aren't "continuations" in the usual sense such as you might find
        !            27: in Scheme code.
        !            28: 
1.1       jmmv       29: Please note that the main goal of this project is to simplify the
                     30: implementation of [[SMP networking|smp_networking]], so care must be taken
                     31: in the design of the interface to support all the features required for
                     32: this other project.
                     34: The proposed interface looks like the following.  This interface is mostly
                     35: derived from the `callout(9)` API and is a superset of the softint(9) API.
                     36: The most significant change is that workqueue items are not tied to a
                     37: specific kernel thread.
                     39: * `kcont_t *kcont_create(kcont_wq_t *wq, kmutex_t *lock, void
                     40:   (*func)(void *, kcont_t *), void *arg, int flags);`
                     42:   A `wq` must be supplied.  It may be one returned by
                     43:   `kcont_workqueue_acquire` or a predefined workqueue such as (sorted from
                     44:   highest priority to lowest):
                     46:   * `wq_softserial`, `wq_softnet`, `wq_softbio`, `wq_softclock`
                     47:   * `wq_prihigh`, `wq_primedhigh`, `wq_primedlow`, `wq_prilow`
                     49:   `lock`, if non-NULL, should be locked before calling `func(arg)` and
                     50:   released afterwards.  However, if the lock is released and/or destroyed
                     51:   before the called function returns, then, before returning,
                     52:   `kcont_set_mutex` must be called with either a new mutex to be released
                     53:   or `NULL`.  If acquiring lock would block, other pending kernel
                     54:   continuations which depend on other locks may be dispatched in the
                     55:   meantime.  However, all continuations sharing the same set of `{ wq, lock,
                     56:   [ci] }` need to be processed in the order they were scheduled.
                     58:   `flags` must be 0.  This field is just provided for extensibility.
                     60: * `int kcont_schedule(kcont_t *kc, struct cpu_info *ci, int nticks);`
                     62:   If the continuation is marked as *INVOKING*, an error of `EBUSY` should
                     63:   be returned.  If `nticks` is 0, the continuation is marked as *INVOKING*
                     64:   while *EXPIRED* and *PENDING* are cleared, and the continuation is
                     65:   scheduled to be invoked without delay.  Otherwise, the continuation is
                     66:   marked as *PENDING* while *EXPIRED* status is cleared, and the timer
                     67:   reset to `nticks`.  Once the timer expires, the continuation is marked as
                     68:   *EXPIRED* and *INVOKING*, and the *PENDING* status is cleared.  If `ci`
                     69:   is non-NULL, the continuation is invoked on the specified CPU if the
                     70:   continuations's workqueue has per-cpu queues.  If that workqueue does not
                     71:   provide per-cpu queues, an error of `ENOENT` is returned.  Otherwise when
                     72:   `ci` is `NULL`, the continuation is invoked on either the current CPU or
                     73:   the next available CPU depending on whether the continuation's workqueue
                     74:   has per-cpu queues or not, respectively.
                     76: * `void kcont_destroy(kcont_t *kc);`
                     78: * `kmutex_t *kcont_getmutex(kcont_t *kc);`
                     80:   Returns the lock currently associated with the continuation `kc`.
                     82: * `void kcont_setarg(kcont_t *kc, void *arg);`
                     84:   Updates `arg` in the continuation `kc`.  If no lock is associated with
                     85:   the continuation, then `arg` may be changed at any time; however, if the
                     86:   continuation is being invoked, it may not pick up the change.  Otherwise,
                     87:   `kcont_setarg` must only be called when the associated lock is locked.
                     89: * `kmutex_t *kcont_setmutex(kcont_t *kc, kmutex_t *lock);`
                     91:   Updates the lock associated with the continuation `kc` and returns the
                     92:   previous lock.  If no lock is currently associated with the continuation,
                     93:   then calling this function with a lock other than NULL will trigger an
                     94:   assertion failure.  Otherwise, `kcont_setmutex` must be called only when
                     95:   the existing lock (which will be replaced) is locked.  If
                     96:   `kcont_setmutex` is called as a result of the invokation of func, then
                     97:   after kcont_setmutex has been called but before func returns, the
                     98:   replaced lock must have been released, and the replacement lock, if
                     99:   non-NULL, must be locked upon return.
                    101: * `void kcont_setfunc(kcont_t *kc, void (*func)(void *), void *arg);`
                    103:   Updates `func` and `arg` in the continuation `kc`.  If no lock is
                    104:   associated with the continuation, then only arg may be changed.
                    105:   Otherwise, `kcont_setfunc` must be called only when the associated lock
                    106:   is locked.
                    108: * `bool kcont_stop(kcont_t *kc);`
                    110:   The `kcont_stop function` stops the timer associated the continuation
                    111:   handle kc.  The *PENDING* and *EXPIRED* status for the continuation
                    112:   handle is cleared.  It is safe to call `kcont_stop` on a continuation
                    113:   handle that is not pending, so long as it is initialized.  `kcont_stop`
                    114:   will return a non-zero value if the continuation was *EXPIRED*.
                    116: * `bool kcont_pending(kcont_t *kc);`
                    118:   The `kcont_pending` function tests the *PENDING* status of the
                    119:   continuation handle `kc`.  A *PENDING* continuation is one who's timer
                    120:   has been started and has not expired.  Note that it is possible for a
                    121:   continuation's timer to have expired without being invoked if the
                    122:   continuation's lock could not be acquired or there are higher priority
                    123:   threads preventing its invokation.  Note that it is only safe to test
                    124:   *PENDING* status when holding the continuation's lock.
                    126: * `bool kcont_expired(kcont_t *kc);`
                    128:   Tests to see if the continuation's function has been invoked since the
                    129:   last `kcont_schedule`.
                    131: * `bool kcont_active(kcont_t *kc);`
                    133: * `bool kcont_invoking(kcont_t *kc);`
                    135:   Tests the *INVOKING* status of the handle `kc`.  This flag is set just
                    136:   before a continuation's function is being called.  Since the scheduling
                    137:   of the worker threads may induce delays, other pending higher-priority
                    138:   code may run before the continuation function is allowed to run.  This
                    139:   may create a race condition if this higher-priority code deallocates
                    140:   storage containing one or more continuation structures whose continuation
                    141:   functions are about to be run.  In such cases, one technique to prevent
                    142:   references to deallocated storage would be to test whether any
                    143:   continuation functions are in the *INVOKING* state using
                    144:   `kcont_invoking`, and if so, to mark the data structure and defer storage
                    145:   deallocation until the continuation function is allowed to run.  For this
                    146:   handshake protocol to work, the continuation function will have to use
                    147:   the `kcont_ack` function to clear this flag.
                    149: * `bool kcont_ack(kcont_t *kc);`
                    151:   Clears the *INVOKING* state in the continuation handle `kc`.  This is
                    152:   used in situations where it is necessary to protect against the race
                    153:   condition described under `kcont_invoking`.
                    155: * `kcont_wq_t *kcont_workqueue_acquire(pri_t pri, int flags);`
                    157:   Returns a workqueue that matches the specified criteria.  Thus if
                    158:   multiple requesters ask for the same criteria, they are all returned the
                    159:   same workqueue.  `pri` specifies the priority at which the kernel thread
                    160:   which empties the workqueue should run.
                    162:   If `flags` is 0 then the standard operation is required.  However, the
                    163:   following flag(s) may be bitwise ORed together:
                    165:   * `WQ_PERCPU` specifies that the workqueue should have a separate queue
1.2       plunky    166:     for each CPU, thus allowing continuations to be invoked on specific CPUs.
1.1       jmmv      167: 
                    168: * `int kcont_workqueue_release(kcont_wq_t *wq);`
                    170:   Releases an acquired workqueue.  On the last release, the workqueue's
                    171:   resources are freed and the workqueue is destroyed.
                    172: """
                    173: ]]
                    175: [[!tag smp_networking]]

CVSweb for NetBSD wikisrc <> software: FreeBSD-CVSweb