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

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

CVSweb for NetBSD wikisrc <wikimaster@NetBSD.org> software: FreeBSD-CVSweb