Signal Selector

XWOS Signal Selector

Overview

The signal selector is similar to event flags, using a bitmap to manage a group of synchronization objects. This allows a single thread to wait on multiple synchronization objects simultaneously.

Each synchronization object is bound to a specific bit in the signal selector bitmap.

When these synchronization objects send a select signal, the specific bit in the signal selector bitmap is set to 1, and the thread waiting on the signal selector is awakened. After waking up, the thread can check which bits are set to 1 to determine which synchronization objects sent the select signal.

Signal Selector Object and Object Descriptor

The signal selector object is a derived class of XWOS Object struct xwos_object. Similarly, signal selector objects also use the signal selector object descriptor xwos_sel_d to solve the problems of validity and identity legitimacy.

The signal selector object descriptor is composed of a pointer to the signal selector object and a tag:

typedef struct {
        struct xwos_sel * sel; /**< Pointer to the signal selector object */
        xwsq_t tik; /**< Tag */
} xwos_sel_d;

When referencing an object through the object descriptor, first check the value of obj->magic to see if it is 0x58574F53U, which confirms that the pointer obj points to a valid XWOS object. Then compare the tags obj->tik and tik to see if they are equal, which confirms the object’s identity. Since the object’s tik is globally unique, when the object is released, its tik will be destructed to 0 by the destructor. When the memory address is reconstructed into a new object, its tik will definitely differ from the tik in the object descriptor.

Binding and Unbinding Synchronization Objects

All synchronization objects in XWOS have two similar sets of CAPI:

Synchronization object binding operations are further divided into exclusive binding and non-exclusive binding:

  • Exclusive binding: Once a synchronization object is bound to a certain bit in the signal selector bitmap, no other synchronization object can bind to that bit. The select signal sent is also called an exclusive mode select signal.
  • Non-exclusive binding: Once a synchronization object is bound to a certain bit in the signal selector bitmap, other synchronization objects can still bind to that bit. The select signal sent is also called a non-exclusive mode select signal.

Binding modes used by synchronization objects:

  • Semaphore: exclusive binding
  • Condition Variable: non-exclusive binding
  • Event Flag: non-exclusive binding
  • Thread Barrier: non-exclusive binding
  • Signal Selector: non-exclusive binding

Select Signal

Setting the Select Signal

The setting of the select signal has different interpretations for different synchronization objects:

  • Semaphore
    • The select signal is set when the counter value is greater than 0.
  • Condition Variable
  • Event Flag
  • Thread Barrier
    • All threads arrive at the barrier and are awakened simultaneously;
  • Signal Selector
    • The signal selector itself is also a synchronization object and can be bound to another signal selector. When the source signal selector receives a select signal, it forwards it to the bound destination signal selector.

XWOS Signal Selector Diagram
Photo: xwos.tech / CC-BY

Clearing the Select Signal

Exclusive Mode Select Signal

  • Semaphore: The select signal is only cleared when the counter value in the semaphore is less than or equal to 0.

Non-exclusive Mode Select Signal

After a synchronization object bound in non-exclusive mode sends a select signal to the signal selector, its position in the bitmap is set to 1. All waiting threads are awakened, and they compete to enter the signal selector’s critical section.

The first thread to enter reads the signal selector’s select signal bitmap and compares it with the mask passed during the function call to determine whether any select signals matching the mask exist:

  • If yes, it clears all non-exclusive mode select signals in the signal selector bitmap, including select signals not set in the mask. Therefore, subsequent threads will no longer be able to detect any non-exclusive mode select signals and will re-enter blocking wait. XWOS does not recommend having more than one thread waiting on a signal selector.
  • If no, the thread re-enters blocking wait, and the next thread enters the critical section to check.

Signal Selector Initialization, Destruction and Dynamic Creation, Deletion

Static Initialization and Destruction

  • Static initialization: xwos_sel_init()
    • Static means the user predefines thread structure objects, which are allocated memory by the compiler at compile time.
  • Destroy statically initialized signal selector: xwos_sel_fini()

Dynamic Creation and Deletion

  • Dynamic creation: xwos_sel_create()
    • Dynamic means the program allocates memory through memory allocation functions at runtime and constructs the object on the allocated memory.
  • Delete dynamically created signal selector: xwos_sel_delete()

Waiting for Select Signals

  • xwos_sel_select(): Wait for select signals in the signal selector, can only be used in thread context
  • xwos_sel_select_to(): Timed wait for select signals in the signal selector, can only be used in thread context
  • xwos_sel_tryselect(): Check whether there are select signals in the signal selector, can be used in any context

Binding and Unbinding Other Signal Selectors

A signal selector can be bound to another signal selector via xwos_sel_bind(), forming a forwarding chain. However, signal selectors must not be bound to each other in a circular chain, as this would cause infinite forwarding.

A bound signal selector can be unbound via xwos_sel_unbind().

Signal Selector Object Lifecycle Management

The base class of the signal selector object is XWOS Object struct xwos_object. The signal selector object also has two sets of lifecycle management CAPI:

  • Access lifecycle management CAPI using object pointer: requires ensuring that the object is definitely valid when calling the CAPI, and there is no case of released-then-reallocated as another object.

    • xwos_sel_grab(): Increase reference count.
    • xwos_sel_put(): Decrease reference count. When the reference count drops to 0, the garbage collection function is called to release the object.
  • Access lifecycle management CAPI using object descriptor: used when the user cannot guarantee that the object is definitely valid or cannot guarantee that the object has not become another object.

    • xwos_sel_acquire(): Determine that the object is valid and legitimate through the object descriptor, then increase the reference count.
    • xwos_sel_release(): Determine that the object is valid and legitimate through the object descriptor, then decrease the reference count. When the reference count drops to 0, the garbage collection function is called to release the object.

CAPI Reference