Kernel thread

Out-of-band capable threads in kernel space

The EVL core can run common kernel threads on the out-of-band stage (i.e. the equivalent of the struct kthread from the regular kernel), which you can use in out-of-band capable drivers when ultra-low response time is required.

The API we are discussing in this page specifically belongs to the kernel thread support for EVL. If you are looking for the public API to deal from a driver with any type of EVL thread - either running in user or kernel space - then this document is appropriate.


int evl_run_kthread(struct evl_kthread *kthread, void (*threadfn)(void *arg), void *arg, int priority, int clone_flags, const char *fmt, ...)

evl_run_kthread() is a macro-definition which spawns an EVL kernel thread, which is the EVL equivalent of its in-band kernel counterpart named kthread_run().

The new thread may be pinned on any of the out-of-band capable CPUs (See the evl.oob_cpus kernel parameter). If you need to spawn a kernel thread on a particular CPU, you may want to use evl_run_kthread_on_cpu() instead.

  • kthread

    A kernel thread descriptor where the core will maintain the per-thread context information. This memory area must remain valid as long as the associated kernel thread runs.

  • threadfn

    The routine to run in the new thread context.

  • arg

    A user-defined opaque pointer which is passed unmodified to threadfn as its sole argument.

  • priority

    If greater than zero, the value is interpreted as the priority of the new thread in the EVL SCHED_FIFO class. Otherwise, the SCHED_WEAK policy is assumed.

  • clone_flags

    A set of creation flags for the new kernel thread, defining its visibility:

    • EVL_CLONE_PUBLIC denotes a public thread which is represented by a device file in the /dev/evl file hierarchy, which makes it visible to application processes for sharing.

    • EVL_CLONE_PRIVATE denotes a thread which is private to the kernel. No device file appears for it in the /dev/evl file hierarchy.

  • fmt

    A ksprintf()-like format string to generate the thread name. Unlike evl_attach_thread() from the user API, evl_run_kthread() does not look for any shorthand defined by the naming convention for application threads. Thread visibility can be set exclusively by using the clone_flags.

  • ...

    The optional variable argument list completing the format.

  • evl_run_kthread() returns zero on success, or a negated error code otherwise:

    • -EEXIST The generated name is conflicting with an existing thread name.

    • -EINVAL Either clone_flags or priority are wrong.

    • -ENAMETOOLONG The overall length of the device element’s file path including the generated name exceeds PATH_MAX.

    • -ENOMEM Not enough memory available. Buckle up.


    int evl_run_kthread_on_cpu(struct evl_kthread *kthread, int cpu, void (*threadfn)(void *arg), void *arg, int priority, int clone_flags, const char *fmt, ...)

    As its name suggests, evl_run_kthread_on_cpu() is a variant of evl_run_kthread() which lets you pick a particular CPU for pinning the new kernel thread.

  • cpu

    The CPU number the new thread should be pinned to, among the out-of-band capable ones (See the evl.oob_cpus kernel parameter).

  • evl_run_kthread_on_cpu() returns zero on success, or a negated error code. The set of error conditions for evl_run_kthread() apply to evl_run_kthread_on_cpu(), plus:

    • -EINVAL cpu is not a valid, out-of-band capable CPU.

    void evl_stop_kthread(struct evl_kthread *kthread)

    This call requests the EVL kernel thread to exit at the first opportunity. It may be called from any stage, but only from a kernel thread context, regular in-band or EVL.

    This is an advisory method for stopping EVL kernel threads, which requires kthread to call evl_kthread_should_stop() as part of its regular work loop, exiting when such test returns true. In other words, evl_stop_kthread() raises the condition which evl_kthread_should_stop() returns to its caller.

    evl_stop_kthread() first unblocks kthread from any blocking call, then waits for kthread to actually exit before returning to the caller. Therefore, an EVL kernel thread which receives a request for termination while sleeping on some EVL call unblocks with -EINTR as a result.

    There is no way to forcibly terminate kernel threads since this would potentially leave the kernel system in a broken, unstable state. Both the requestor and the subject kernel thread must cooperate for the later to follow an orderly process for exiting. The in-band equivalent is achieved with kthread_stop(), kthread_should_stop().

  • kthread

    The EVL kernel thread to send a stop request to. If kthread represents the calling context (i.e. self-termination), the call does not return and the caller is exited immediately. Otherwise, the stop request is left pending until kthread eventually calls evl_kthread_should_stop(), at which point it should act upon this event by exiting.


  • bool evl_kthread_should_stop(void)

    This call is paired with evl_stop_kthread(). It should be called by any EVL kernel thread which intends to accept termination requests from other threads.

    Whenever evl_kthread_should_stop() returns true, the caller should plan for exiting as soon as possible, typically by returning from its entry routine. Otherwise, it may continue.

    A typical usage pattern is as follows:

    
    #include <evl/thread.h>
    #include <evl/flag.h>
    
    static DEFINE_EVL_FLAG(some_flag);
    
    void some_kthread(struct evl_kthread *kthread)
    {
    	int ret;
    
    	for (;;) {
    		if (evl_kthread_should_stop())
    			break;
    
    		/* wait for the next processing signal */
    		ret = evl_wait_flag(&some_flag);
    		if (ret == -EINTR)
    		    	break;
    
    		/* do some useful stuff */
    	}
    
    	/* about to leave, do some cleanup */
    }
    

    int evl_set_kthread_priority(struct evl_kthread *kthread, int priority)

    Change the priority of an EVL kernel thread.

  • kthread

    The descriptor of the EVL kernel thread.

  • priority

    The new priority of kthread, which is assumed to refer to the SCHED_FIFO class.

  • evl_set_kthread_priority() returns zero on success, otherwise a negated error code is returned:

    -EINVAL priority is invalid. Check the documentation of the SCHED_FIFO class for details.

    evl_set_kthread_priority() immediately applies the changes to the scheduling attributes of kthread.


    struct evl_kthread *evl_current_kthread(void)

    Return the descriptor of the current EVL kernel thread. NULL is returned when calling this service from any other type of thread context (i.e. EVL user thread, non-EVL thread).

    evl_current_kthread() does not account for the interrupt context; a non-NULL pointer to the interrupted kernel thread may be returned if called from the IRQ handler.


    int evl_join_kthread(struct evl_kthread *kthread, bool uninterruptible)

    Wait for an EVL kernel thread to exit. The caller returns immediately if kthread is already in a dormant state. Otherwise, it blocks until kthread returns from its base function. This routine may be called only from the in-band stage.

  • kthread

    The descriptor of the EVL kernel thread.

  • uninterruptible

    A boolean telling whether the caller may be interrupted while sleeping, causing the routine to return with -EINTR. If true, the caller cannot be interrupted.

  • Zero is returned on success, otherwise:

    • -EINTR is returned if the caller received a signal while sleeping. This can happen only if uninterruptible is false.

    • -EINVAL is returned if the caller is returned if kthread is the root placeholder for the current CPU. The latter is an internal descriptor which drivers should never have to refer to anyway.

    • -EDEADLK is returned if kthread is mapped to the calling context, meaning the caller attempts to wait for its own exit, which is not going to happen anytime soon.


    struct evl_kthread *evl_current_kthread(void)

    Return the EVL kernel thread descriptor of the caller. NULL is returned if the caller is not an EVL kernel thread.

    Only a kernel space thread started with evl_run_kthread() would receive a non-NULL pointer. EVL user thread and common Linux threads would receive NULL.


    Last modified: Sat, 04 Mar 2023 16:43:20 +0100