Event and Concurrency Model

Liberty-IoT-OS is an Operating System for IoT. Each Application function is an potential executable on the Liberty-IoT-OS.

Each App Task is a running process (a running instance of a API function) with user defined arguments (through user’s Smartphone GUI).

Task Concurrency

A Task in Liberty-IoT-OS is most likely an infinite loop, which keeps running until being stopped (or being killed by Liberty-IoT-OS if code is bad).

Like processes in any other Operating System, a Task is under illusion that it is the only process that is using CPU resource. It is certainly not true. Task is running in infinite loop, but most of times it is just waiting for some events.

Task is scheduled by Liberty App Engine, which is a LuaJIT Virtual Machine.

Task Thread

Task function is the main thread of the task. A task can create more execution threads.

Libre_NewThread(func, …)

The func is a function as the new thread entry. Addition arguments will be the input argument of the new thread function.

Task threads will be stopped when task is manually stopped by user.

If all task threads terminates without raising error, the task is terminated naturally.

Task Scheduling

Liberty App Engine employs cooperative multi-tasking model, unlike the pre-emptive multi-tasking in modern Windows and Linux.

Each task thread has to voluntarily give up CPU to other threads, by calling Libre_Wait() or Libre_WaitUntil() API.

Libre_Wait() and Libre_WaitUntil() Function

Let’s compare the only two “wait functions” in Liberty-IoT-OS.

Libre_Wait(timeout)

Libre_WaitUntil(timeout)

Both takes one parameter timeout. The “timeout” has complete different meanings.

Timeout for Libre_Wait is an integer in milliseconds. Timeout for Libre_WaitUntil is a UTC time, which is a real number represents seconds since Unix epoch (may have fractions).

Libre_Wait(0)

If timeout is 0, it means the current task thread voluntarily yields CPU to other tasks.

A task thread performing long time consuming work shall insert Libre_Wait(0) in the loop to “play nice” by keeping the system more responsive.

If a task thread takes CPU for too long without yielding (5 seconds), the Task will be killed by Liberty-IoT-OS and will be marked with “Error” state to prevent it from being started again.

Events

If a thread is not subscribing any event, Libre_Wait or Libre_WaitUntil will wait exactly until the specified timeout is reached.

Nevertheless, if a thread subscribed any event, the Libre_Wait or Libre_WaitUntil call may return if a subscribed event arrives before timeout.

Event Subscription

Application can subscribe two types of events.

Typical Event Loop

Below is the code for a typical event loop.

    -- At the start of thread, subscribe events
    Libre_SetWaitXXXX(some_id)
    -- More events may be subscribed ...

    while true do
        -- It is common to change waiting for read/write events of I/O
        Libre_SetWaitIo(fd, mask)

        Libre_Wait(timeout)
        -- or Libre_WaitUntil(timeout)
        -- Make sure all queued events are retrieved and processed
        while (true) do
            -- Get a queued event
            local event = Libre_GetEvent()
            if (event == nil) then  -- No more pending events
                break               -- Break and keep waiting
            end
            -- Process the event
        end
    end

Libre_GetEvent

Libre_GetEvent()

Get a queued event for current thread.

Returns:

  • nil - If no more events
  • event - An event object
    • t - Event type
      • 0 - Device command event
      • 1 - Device attribute report event
      • 2 - Device query event
      • 10 - I/O event
    • id - The object ID of the event. Depending on the event type, the id could be:
      • A device ID
      • An I/O socket
    • ok - The state of the object. If ok is false for a device event, the device is unreachable (some problem happened).
    • c - Cluster of device event
    • d - Command ID of device event; or nil if event is not a device command.
    • v - Value of devie event or I/O event
      • Device events
        • For device command event, it is an array of command values, different command has specific interpretation.
        • For device attribute event, it is hashtable ofkey/value pairs. Each key/value pair is an Attribute ID/Attribute Value.
      • I/O event, the I/O availability mask.
        • 1 - I/O is readable
        • 2 - I/O is writable
        • 3 - I/O is both readable and writable
    • a - For device event, it is a hashtable of attributes changes as the effect of the command; or nil otherwise.
    • s - The event source, i.e. the reason why the event is triggered
      • 0 - No source
      • 1 - Manual local, event is triggered by human manually from local device
      • 2 - Manual remote, event is triggered by human manually from a remote control device
      • 3 - Auto local, event is triggered automatically from local device
      • 4 - Auto remote, event is triggered automatically from a remote control device
      • 5 - App engine, event is triggered by an App Task
      • 6 - Query, event is triggered in response to a query
      • 7 - Report, event is triggered by attribute report

The event object is fairly complex. Nevertheless it is clearly defined from above.