Kernel flag

Flag services

An EVL kernel flag is a basic synchronization mechanism based on the EVL wait queue, which can be used to wait for a boolean state to be notified. This is typically used in interrupt to thread synchronization, with the former posting a wakeup event to the latter by mean of raising a flag.

void evl_init_flag(struct evl_flag *wf)

This call initializes a kernel flag.

  • wf

    A flag descriptor is constructed by evl_init_flag(), which contains ancillary information other calls will need. wf is a pointer to such descriptor of type struct evl_flag.


  • void evl_destroy_flag(struct evl_flag *wf)

    This call destroys an existing EVL kernel flag. Any thread which might blocked waiting on the flag is woken up by this call, receiving a ‘resource removed’ status (-EIDRM).

  • wf

    The descriptor of the kernel flag to be destroyed.


  • int evl_wait_flag(struct evl_flag *wf)

    This service waits for the flag to be raised. Until this happens, the caller is blocked until a call to evl_raise_flag() eventually releases it. If the flag was already raised on entry, the caller returns immediately. Waiters are queued by order of scheduling priority.

  • wf

    The flag descriptor constructed by either evl_init_flag(), or statically built with EVL_FLAG_INITIALIZER.

  • Zero is returned on success, otherwise:

    • -EIDRM The flag was deleted while the caller was sleeping on it. When this status is returned, the flag must be considered stale and should not be accessed anymore.

    • -EINTR The sleep was interrupted or forcibly unblocked.


    int evl_wait_flag_timeout(struct evl_flag *wf, ktime_t timeout, enum evl_tmode timeout_mode)

    This call is a variant of evl_wait_flag() which allows specifying a timeout on the operation, so that the caller is automatically unblocked when a time limit is reached.

  • wf

    The flag descriptor constructed by either evl_init_flag(), or statically built with EVL_FLAG_INITIALIZER.

  • timeout

    A time limit for the call. There are two special values: EVL_NONBLOCK tells the core NOT to block the caller if the flag is not raised on entry, EVL_INFINITE means no time limit only if timeout_mode is EVL_REL (See evl_wait_flag()).

  • timeout_mode

    A timeout mode, telling the core whether timeout should be interpreted as a relative value representing a delay (EVL_REL), or an absolute date (EVL_ABS).

  • Zero is returned on success, otherwise:

    • -ETIMEDOUT The timeout fired, after the amount of time specified by timeout.

    • -EAGAIN EVL_NONBLOCK was given in timeout but the flag was not in a signaled state on entry.

    • -EIDRM The flag was deleted while the caller was sleeping on it. When this status is returned, the flag must be considered stale and should not be accessed anymore.

    • -EINTR The sleep was interrupted or forcibly unblocked.


    struct evl_thread *evl_wait_flag_head(struct evl_flag *wf)

    Returns the descriptor of the EVL kernel thread leading the wait queue.

  • wf

    The flag descriptor constructed by either evl_init_flag(), or statically built with EVL_FLAG_INITIALIZER.

  • The flag must have been locked by a call to evl_lock_flag() prior to calling this routine.

    The thread descriptor returned by this call is guaranteed valid only while such lock is held by the caller. A reference can be taken on that thread via a call to evl_get_element() while the flag is locked, in order to extend the guarantee until the last reference is dropped by a call to evl_put_element(). In the meantime, the flag may be unlocked safely, without the thread going stale.

    int peek_at_flag(struct evl_flag *wf)
    {
    	struct evl_thread *t = NULL;
    	unsigned long flags;
    
    	evl_lock_flag(wf, flags);
    
    	t = evl_wait_flag_head(wf);
    	if (t)	/* Prevent 't' from going stale once the flag is unlocked. */
    		evl_get_element(&t->element);
    
    	evl_unlock_flag(wf, flags);
    
    	if (!t)
    		return -EAGAIN;
    
    	do_stuff(t);
    
    	evl_put_element(&t->element); /* Drop the reference. */
    
    	return 0;
    }
    

    evl_wait_flag_head() returns a pointer to the descriptor of the EVL thread currently leading the wait queue, or NULL if none.


    void evl_raise_flag_nosched(struct evl_flag *wf)

    evl_raise_flag_nosched() transitions the flag to the notified state, allowing all waiters to compete for consuming the notification. The thread winning this race resets the flag then unblocks from evl_wait_flag(), others go back sleeping until the next event is signaled. The rescheduling procedure is not called by this routine, which makes it usable in sections of code guarded by spinlocks.

    This call transitions the flag to a notified state until the event is consumed by one of the waiters which is unblocked as a result. If you look for a pulse-mode notification which unblocks all threads waiting for the next notification, you should refer to evl_pulse_flag_nosched() instead.

  • wf

    The flag descriptor constructed by either evl_init_flag(), or statically built with EVL_FLAG_INITIALIZER.

  • The caller MUST call evl_schedule() afterwards, as soon as all locks have been dropped.


    void evl_raise_flag(struct evl_flag *wf)

    evl_raise_flag() has the same synchronization effect than evl_raise_flag_nosched() but does invoke the rescheduling procedure implicitly in case a thread was resumed as a result of the operation.

  • wf

    The flag descriptor constructed by either evl_init_flag(), or statically built with EVL_FLAG_INITIALIZER.


  • void evl_pulse_flag_nosched(struct evl_flag *wf)

    evl_pulse_flag_nosched() broadcasts a notification so that all waiters can consume the same event, differing from evl_raise_flag_nosched() which only allows a single waiter to do so. This operation does not transition the flag to the notified state. The rescheduling procedure is not called by this routine, which makes it usable in sections of code guarded by spinlocks.

  • wf

    The flag descriptor constructed by either evl_init_flag(), or statically built with EVL_FLAG_INITIALIZER.


  • void evl_pulse_flag(struct evl_flag *wf)

    evl_pulse_flag() has the same synchronization effect than evl_pulse_flag_nosched() but does invoke the rescheduling procedure implicitly in case a thread was resumed as a result of the operation.

  • wf

    The flag descriptor constructed by either evl_init_flag(), or statically built with EVL_FLAG_INITIALIZER.


  • void evl_flush_flag_nosched(struct evl_flag *wf, int reason)

    evl_flush_flag_nosched() is a variant of evl_pulse_flag_nosched() which allows the caller to specify the wake up bitmask passed to the underlying wait queue, instead of T_BCAST. This bitmask describes the reason for the wake up.

    This call is part of the inner EVL kernel API, any misusage can lead to serious trouble. If you do not know about the internal wake up logic, then you should refrain from using it.

  • wf

    The flag descriptor constructed by either evl_init_flag(), or statically built with EVL_FLAG_INITIALIZER.

  • reason

    A bitmask which gives additional information to the resuming threads about the reason why they were unblocked. In the common case, reason should be zero. A non-zero value contains a flag bit matching a particular situation, which translates to a specific error status for evl_wait_schedule().


  • void evl_flush_flag(struct evl_flag *wf, int reason)

    evl_flush_flag() has the same synchronization effect than evl_flush_flag_nosched() but does invoke the rescheduling procedure implicitly in case a thread was resumed as a result of the operation.


    void evl_clear_flag(struct evl_flag *wf)

    Reset the flag state to unnotified.

  • wf

    The flag descriptor constructed by either evl_init_flag(), or statically built with EVL_FLAG_INITIALIZER.


  • EVL_FLAG_INITIALIZER(name)

    A macro which expands as a static initializer you can use in a C statement creating an EVL kernel flag.

  • name

    The C variable name to which the initializer should be assigned.

  • struct evl_flag foo = EVL_FLAG_INITIALIZER(foo);
    

    DEFINE_EVL_FLAG(name)

    A macro which expands as a C statement defining an initialized EVL kernel flag.

  • name

    The C variable name of the kernel flag to define.

  • /*
     * The following expands as:
     * static struct evl_flag bar = EVL_FLAG_INITIALIZER(bar);
     */
    static DEFINE_EVL_FLAG(bar);
    

    Last modified: Sun, 21 May 2023 18:02:07 +0200