.. highlight:: none |me_h| for QNX ============== Introduction ------------ This chapter includes details regarding how |me| is supported on QNX. Please note that this documentation does *not* include information regarding installation of QNX itself. Please consult your QNX documentation for how to install QNX. - `QNX Platform Notes`_ - `OS Resource Usage`_ - `Build environment`_ - `Compiling with rtime-make`_ QNX Platform Notes ------------------ |me| uses an abstract platform API that must be ported to different platforms. This section discusses the impementation of the platform abtractions on the QNX platform. .. contents:: :local: Heap .... |me| allocates memory using the `malloc` API. This memory is managed internally by |me| and is not freed. Mutex ..... |me| uses recursive mutexes to protect its critical sections. Because all |me| APIs are synchronous, a mutex `take` operation blocks until the mutex becomes available. It is unexptected behavior if a mutex does not become available. .. note:: QNX creates all mutexes such that priority inversion does not occur (SSR-3286-0760, Document QMS3286, QNX OS for Safety 2.1). Semaphores .......... |me| uses a semaphore to implement the DDS WaitSet. One semaphore is implemented with a condition variable while another sempahore is implemented with an internal timer (e.g. a *DDS_WaitSet* with a finite duration) that signals the condition variable upon timeout. The resolution of a semaphore is rounded up to the nearest clock tick + 1. Thus, a semaphore may take up to 2 clock ticks (at most) extra to time out. The timeout is tied to the tick-time mentioned in `Timers`_. .. note:: |me| does not support multiple threads blocking on a semaphore. None of the public |me| APIs would cause multiple threads to block on the same semaphore. Timers ...... |me| implements its own software timers to support timed events such as periodic participant announcements and checking for missed deadlines. The timer resolution for |me| timers is 10 milliseonds. This cannot be changed without recompiling |me|. |me| requires an external (to |me|) clock tick to run its internal timers. On QNX, this clock tick is implemented with a POSIX real-time timer and the SIGRTMIN signal. This cannot be changed. When the SIGRTMIN signal is raised, a timer handler signals a semaphore, which wakes up a separate thread that runs the timers. Thus, the timers are updated in a separate thread, not in the context of the signal handler. In addition to runnning the internal timers, |me| maintains an internal clock that is started when |me| is first initialized, and which is incremented in each clock-tick. The clock-tick is maintained as a 32-bit signed second counter and a 32-bit unsigned nanosecond counter. This internal clock is known as the "tick-time" and is a function of the number of clock-ticks, not the actual time. The tick-time is used to control semaphore timeout, deadline, and liveliness. Time .... DDS APIs use the time of day to timestamp samples. On QNX, this timestamp is retrieved using *gettimeofday*. Note that no check is performed on the returned time of day (such as time going backwards). The time is also used to determine the interval between two samples when the sample ordering is per source timestamp on the *DataWriter*. Threads ....... |me| creates threads to run timers and process data received from the network. By default, threads are created with the: - *PTHREAD_EXPLICIT_SCHED* attribute. - *PTHREAD_CREATE_DETACHED* attribute. - OS default stack size. - priority inheritied from spawning thread. If the OSAPI_ThreadOptions *OSAPI_THREAD_REALTIME_PRIORITY* is used, the following attributes are set as well: - *PTHREAD_SCOPE_SYSTEM* - *SCHED_FIFO* Two types of thread priorties can be set: - **Absolute** A priority equal to or larger than zero is used as is, and must be within the range allowed by the OS. - **Calculated** A priority between [*OSAPI_THREAD_PRIORITY_LOW*, *OSAPI_THREAD_PRIORITY_HIGH*] is calculated using the following formula: :: OS.min_priority + (((OS.max_priority - OS.min_priority) * priority_level)/OSAPI_THREAD_PRIORITY_HIGH); Sockets ....... |me| creates a single socket to send data with and one socket for each receive thread created. If a multicast address is specified to receive data on, multicast loopback is automatically enabled. OS Resource Usage ----------------- |me| uses OS resources to implement the |me| abstraction layer. The following table outlines the type and amount of resources used by different entities and objects: +------------------------------+-------+-----------+--------+--------+--------+ | Entity | mutex | condition | timer | socket | threads| +==============================+=======+===========+========+========+========+ | DDS_DomainParticipantFactory | 3 | 0 | 1 | 0 | 1 | +------------------------------+-------+-----------+--------+--------+--------+ | DDS_DomainParticipant | 2 | 0 | 0 | 0 | 0 | +------------------------------+-------+-----------+--------+--------+--------+ | DDS_DataReader | 1 | 0 | 0 | 0 | 0 | +------------------------------+-------+-----------+--------+--------+--------+ | DDS_DataWriter | 1 | 0 | 0 | 0 | 0 | +------------------------------+-------+-----------+--------+--------+--------+ | DDS_Publisher | 1 | 0 | 0 | 0 | 0 | +------------------------------+-------+-----------+--------+--------+--------+ | DDS_Subscriber | 1 | 0 | 0 | 0 | 0 | +------------------------------+-------+-----------+--------+--------+--------+ | DDS_WaitSet | 3 | 2 | 0 | 0 | 0 | +------------------------------+-------+-----------+--------+--------+--------+ | DDS_GuardCondition | 1 | 0 | 0 | 0 | 0 | +------------------------------+-------+-----------+--------+--------+--------+ | UDP Transport Send | 0 | 0 | 0 | 1 | 0 | | (per Participant) | | | | | | +------------------------------+-------+-----------+--------+--------+--------+ | UDP Transport Receive | 0 | 0 | 0 | 1 | 1 per | | (per Receive locator) | | | | | Receive| | | | | | | locator| +------------------------------+-------+-----------+--------+--------+--------+ Resources: - mutex - POSIX mutex created with ``pthread_mutex_init`` - condition - POSIX condition variable created with ``pthread_cond_init`` - timer - POSIX real-time timer create with ``timer_create`` and using the signal SIGMINRT. - socket - socket created with ``socket`` - threads - POSIX thread created with ``pthread_create`` Build environment ----------------- Source is included with |me| and it is possible to compile |me| from source. However, in the case of |me_cert| **only binaries** provided as part of the Certification Data Package are valid with the certification evidence. Compiling the source may be useful for development purposes. |me| is typically cross-compiled for QNX from a Linux host machine. Before |me| can be compiled with the supplied `cmake` files, it is required to run the QNX setup script located in the QNX installation directory. For example, in a Linux environment: :: source qnxsdp-env.sh Compiling with rtime-make ------------------------- |me| includes `cmake` files for the following QNX architectures: - armv8QNX7.0.4qcc_gpp5.4.0 - QNX SDP 7, ARMv8 - armv8QOS2.1qcc_gpp5.4.0 - QNX OS for Safety 2.1, ARMv8 To compile for these architectures, execute the following command: .. highlight:: none .. only:: not cert :: resource/scripts/rtime-make --target --build --config Release .. only:: cert :: resource.1.0/scripts/rtime-make --target --build --config Release