Zap Execution Contexts
Zap code can execute in several different contexts.
A context refers either to a thread, an IRQ, or an RTOS timer execution context.
A context essentially describes a processor's registers. When one context is swapped for another context, the current context's state (i.e. the processor's registers) is saved and the processor's registers are updated with the new context's previously saved state. Once the processor registers are updated with the new context's state the processor continues executing as if the new context were executing the whole time. In this way multiple independent contexts can exist in ZentriOS.
When in a context, all called functions execute within that context.
However, in one context you can set up an event that is handled in another context when the event takes place.
So, for example, if X is the current context, and functions A thru Z are called, every one of those functions execute in context X.
It's important to note that while executing functions A thru Z, context X could be temporarily suspended, and context Y could begin executing other functions. When context X resumes it continues executing its functions.
Note: By default all Zap code executes in the Zap thread context.
To execute in a different context, specific APIs or flags are required.
For each context below, there are details of the APIs and flags that determine execution in that context.
Context Attributes
A context can be described by the following attributes.
Stack Space
Stack space is the local memory available within the current context. Variables and buffers declared inside a function are considered local and reside 'on the stack'. When a function calls another function, the calling function's local variables are placed on the stack before going into the called function. In this way the stack is implemented as last-in-first-out (LIFO). A context has limited amount of stack space. If a context's stack overflows then hardfaults will likely occur.
Priority
A context has a certain priority in the system. By priority, it is meant the algorithm used to determine which context to execute next. A given context can be 'preempted' by another context with higher priority.
Non-Blocking
Certain contexts must never block. That is, code that executes in a non-blocking context must quickly execute then return. If a context allows for blocking then when a blocking section of code is executed, the blocked context is suspended and another non-blocked context resumes execution.
Initialized
Some contexts are initialized on ZentriOS startup while others are initialized when needed.
Invoked
Contexts are invoked in different ways. Some are event driven while others depend on hardware.
Summary of Context Attributes
The execution contexts in the table below are listed in priority order, with highest priority at the top.
Execution Context | Stack Space | Priority | Non-blocking | Initialized | Invoked |
---|---|---|---|---|---|
Hardware IRQ | 512 | IRQ (above Highest) | ✔ | N/A | When hardware IRQ triggered |
RTOS Timer | 512 | Highest | ✔ | N/A | On RTOS timer time-out |
Network Thread | 6K | High | ❌ | On ZentriOS startup | When network event issued |
Zap Thread | 6K | Medium (configurable) | ❌ | When Zap is loaded | When Zap has event to execute |
System Event Thread | 1K | Medium-High | ✔ | On ZentriOS startup | When system event issued |
HTTP Server Thread | 5K | Medium-High | ❌ | When HTTP Server starts | When HTTP request issued |
Command Thread | 6K | Medium | ❌ | On ZentriOS startup | When external command received |
Available Contexts
The following contexts are available to a Zap.
Zap Thread
- Stack space: 6K (configurable)
- Priority: Medium (configurable)
- Non-blocking : False
- Initialized: When Zap is loaded
- Invoked: when Zap has event to execute
This is the default ZentriOS Application context. Unless otherwise specified, all Zap code executes within this context.
The following ZentriOS APIs issue events that are added to the Zap thread event queue, or register event handlers to be executed when an event is encountered in the event queue:
- Issue Event
- Register Event Handler
- zn_network_register_event_handler()
- zn_network_register_softap_event_handler()
- zn_setup_register_client_event_handler()
- zn_setup_register_finished_event_handler()
- zn_tcp_register_client_event_handlers()
- zn_tcp_register_server_event_handlers()
- zn_udp_register_receive_event_handler()
- zn_websocket_register_server_event_handlers()
- zn_websocket_register_client_event_handlers()
Network Thread
- Stack space: 6K
- Priority: High
- Non-blocking : False
- Initialized: On ZentriOS startup
- Invoked: when network event issued
This is where ZentriOS network related tasks execute. Zap code will execute in this context using the Event API and the ZOS_EVENT_FLAG_NETWORK_THREAD flag.
Zap code executes in the network thread with the following APIs:
- zn_broadcast_set_callback()
- zn_mdns_register_service() using the mdns_txt_record_callback_t callback.
- zn_ntp_update()
Events execute in the network thread if issued or registered with the ZOS_EVENT_FLAG_NETWORK_THREAD flag using the following APIs:
System Event Thread
- Stack space: 1K
- Priority: Medium-High
- Non-blocking : True
- Initialized: On ZentriOS startup
- Invoked: when system event issued
This is where simple ZentriOS tasks execute. For instance, this context is where the LEDs are updated.
Events that execute in the system event thread should be very simple and non-blocking.
Events execute in the system event thread if issued or registered with the ZOS_EVENT_FLAG_SYS_EVENT_THREAD flag using the following APIs:
HTTP Server Thread
- Stack space: 5K
- Priority: Medium-High
- Non-blocking : False
- Initialized: When HTTP server starts
- Invoked: when HTTP request received
This is where HTTP server callbacks are executed. Code in this context may block, but no other HTTP server callbacks can execute until the current callback returns.
Zap code executes in the HTTP Server context with the following APIs:
- Register URI and associated callback
- zn_hs_register_dynamic_page(), called by macro HTTP_SERVER_DYNAMIC_PAGE()
- Other HTTP server callbacks
Command Thread
- Stack space: 6K
- Priority: Medium
- Non-blocking : False
- Initialized: On ZentriOS startup
- Invoked: When external command received
This is where external commands are executed. While this context may block, no other external commands may execute until the current command completes.
External commands are received from:
- Serial console
- HTTP server REST API
- Remote terminal
- Zap API
Zap code executes in the Command Thread context in response to the following APIs:
- Register commands and associated callbacks
- Issue commands
Hardware IRQ
- Stack space: 512
- Priority: IRQ (above 'Highest')
- Non-blocking : True
- Initialized: N/A
- Invoked: When hardware IRQ triggered
This is where an MCU interrupt vector executes. This has extremely high priority. Code in an IRQ must be extremely simple. Furthermore, an IRQ must never block.
When using an IRQ callback, defer heavy processing to the Zap Thread by using an RTOS object such as:
- zos_semaphore_t
- zos_queue_t
- zos_event_flags_t
The Zap Thread should block on the RTOS object and begin executing when the object's state changes.
Another option is to issue an event with a ZOS_EVENT_FLAG_FROM_IRQ flag
Zap code executes in a hardware IRQ context using the following APIs:
RTOS Timer
- Stack space: 512
- Priority: Highest
- Non-blocking : True
- Initialized: N/A
- Invoked: On RTOS timer time-out This is where a RTOS timer callback executes. A RTOS timer callback is very similar to a hardware IRQ callback.
The callback should be extremely simple and never block.
See theHardware IRQ description for recommendations on how to handle a RTOS timer callback.
Zap code executes in a RTOS timer context with the following API: