On Thu, Feb 2, 2017 at 10:30 AM, Sebastian Huber <sebastian.hu...@embedded-brains.de> wrote: > > > On 02/02/17 16:26, Gedare Bloom wrote: >> >> On Wed, Feb 1, 2017 at 5:17 AM, Sebastian Huber >> <sebastian.hu...@embedded-brains.de> wrote: >>> >>> Update #2843. >>> --- >>> c-user/index.rst | 1 + >>> c-user/self_contained_objects.rst | 337 >>> ++++++++++++++++++++++++++++++++++++++ >>> 2 files changed, 338 insertions(+) >>> create mode 100644 c-user/self_contained_objects.rst >>> >>> diff --git a/c-user/index.rst b/c-user/index.rst >>> index 7937042..4b7fe22 100644 >>> --- a/c-user/index.rst >>> +++ b/c-user/index.rst >>> @@ -62,6 +62,7 @@ to the Community Project hosted at >>> http://www.rtems.org/. >>> board_support_packages >>> user_extensions >>> configuring_a_system >>> + self_contained_objects >>> multiprocessing >>> symmetric_multiprocessing_services >>> pci_library >>> diff --git a/c-user/self_contained_objects.rst >>> b/c-user/self_contained_objects.rst >>> new file mode 100644 >>> index 0000000..76c2a64 >>> --- /dev/null >>> +++ b/c-user/self_contained_objects.rst >>> @@ -0,0 +1,337 @@ >>> +.. comment SPDX-License-Identifier: CC-BY-SA-4.0 >>> + >>> +.. COMMENT: Copyright (c) 2014, 2017. >>> +.. COMMENT: embedded brains GmbH. >>> +.. COMMENT: All rights reserved. >>> + >>> +Self-Contained Objects >>> +********************** >>> + >>> +Introduction >>> +============ >>> + >>> +One of the original design goals of RTEMS was the support for >>> heterogeneous >>> +computing based on message passing. This was realized by >>> synchronization >>> +objects with an architecture-independent identifier provided by the >>> system >>> +during object creation (a 32-bit unsigned integer used as a bitfield) >>> and a >>> +user-defined four character name. This approach in the so called >>> Classic API >>> +has some weaknesses: >>> + >>> +* Dynamic memory (the workspace) is used to allocate object pools. This >>> + requires a complex configuration with heavy use of the C >>> pre-processor. >>> + Dynamic memory is forbidden by some coding standards, e.g. MISRA >>> C:2012 >>> + :cite:`MISRA:2012:C`. >>> + >>> +* Objects are created via function calls which return an object >>> identifier. >>> + The object operations use this identifier and map it internally to an >>> object >>> + representation. >>> + >>> +* The object identifier is only known at run-time. This hinders >>> compiler >>> + optimizations and static analysis. >>> + >>> +* The objects reside in a table, e.g. they are suspect to false sharing >>> of >>> + cache lines :cite:`Drepper:2007:Memory`. >>> + >>> +* The object operations use a rich set of options and attributes. For >>> each >>> + object operation these parameters must be evaluated and validated at >>> run-time >>> + to figure out what to do exactly for this operation. >>> + >>> +For applications that use fine grained locking the mapping of the >>> identifier to >>> +the object representation and the parameter evaluation are a significant >>> +overhead that may degrade the performance dramatically. An example is >>> the `new >>> +network stack (libbsd) <https://git.rtems.org/rtems-libbsd>`_ which uses >>> +hundreds of locks in a basic setup and the OpenMP support. >>> + >>> +To overcome these issues new self-contained objects are available in >>> RTEMS 4.12 >>> +via the Newlib supplied :file:`<threads.h>`, :file:`<pthread.h>` and >>> +:file:`<sys/lock.h>` header files. The following synchronization >>> objects are >>> +provided >>> + >>> +* POSIX spinlocks, >>> + >>> +* mutexes, >>> + >>> +* recursive mutexes, >>> + >>> +* condition variables, >>> + >>> +* counting semaphores, >>> + >>> +* binary semaphores, and >>> + >>> +* Futex synchronization :cite:`Franke:2002:Futex`. >>> + >>> +This allows much better performance in SMP configurations as well as in >>> +uni-processor configurations. The application configuration is >>> significantly >>> +simplified, since it is no longer necessary to account for lock objects >>> used by >>> +Newlib and GCC. The Newlib defined self-contained objects can be a >>> statically >>> +initialized and reside in the ``.bss`` section. Destruction is a >>> no-operation. >>> + >>> +Self-Contained Objects API >>> +========================== >>> + >>> +To give the RTEMS users access to self-contained objects an API is >>> necessary. >>> +One option is to use the POSIX threads API (pthreads) and change its >>> +implementation to use self-contained objects. However, there are some >>> other >>> +things to consider. Users of the Classic API may want to run their >>> +applications with different RTEMS versions. Since the POSIX threads API >>> is >>> +optional it may be not available at all, for example in a stripped down >>> space >>> +qualified version. The POSIX threads API has a lot of options that need >>> +run-time evaluation, so that optimal performance is not achievable. >>> There are >>> +a variety of error conditions. This is a problem in combination with >>> some >>> +coding standards, e.g. MISRA C:2012. APIs used by Linux (e.g. >>> +`<linux/mutex.h> >>> +<http://lxr.free-electrons.com/source/include/linux/mutex.h>`_) or the >>> FreeBSD >>> +kernel (e.g. >>> +`MUTEX(9) <https://www.freebsd.org/cgi/man.cgi?query=mutex&sektion=9>`_) >>> are >>> +better suited as a template for high-performance synchronization >>> objects. >>> + >>> +The API defined in the following sections should be implementable via >>> the >>> +Classic API, the self-contained objects present in RTEMS 4.12 and the >>> POSIX >>> +API. Timed operations are not available since the timeout semantics of >>> the >>> +Classic API and the POSIX threads API are quite different. >>> + >>> +Mutual Exclusion >>> +================ >>> + >>> +The :c:type:`rtems_mutex` provides mutual-exclusion synchronization >>> using the >>> +:ref:`PriorityInheritance` in uni-processor configurations or the >>> :ref:`OMIP` >>> +in SMP configurations. Recursive locking is not supported >>> +:cite:`Williams:2012:CA`. >>> + >>> +.. c:type:: rtems_mutex >>> + >>> +The ``rtems_mutex`` is the type of a mutual-exclusion synchronization >>> object. >>> +The storage space for this object must be provided by the user. There >>> are no >>> +defined comparison or assignment operators for this type. Only the >>> object >>> +itself may be used for performing synchronization. The result of >>> referring to >>> +copies of the object in calls to :c:func:`rtems_mutex_lock`, >>> +:c:func:`rtems_mutex_unlock`, and :c:func:`rtems_mutex_destroy` is >>> undefined. >>> +Objects of this type must be initialized via >>> :c:func:`RTEMS_MUTEX_INITIALIZER` >>> +or :c:func:`rtems_mutex_init` and must be destroyed via >>> +:c:func:`rtems_mutex_destroy`. >>> + >>> +.. c:function:: RTEMS_MUTEX_INITIALIZER(name) >>> + >>> +An initializer for static initialization. It is equivalent to a call to >>> +:c:func:`rtems_mutex_init`. Global mutexes without a name may reside in >>> the >>> +``.bss`` section. >>> + >>> +.. c:function:: void rtems_mutex_init(rtems_mutex *mutex, const char >>> *name) >>> + >>> +Initializes the ``mutex`` with the specified ``name``. The ``name`` >>> must be >>> +persistent throughout the life-time of the mutex. The mutex is unlocked >>> after >>> +initialization. >>> + >>> +.. c:function:: void rtems_mutex_lock(rtems_mutex *mutex) >>> + >>> +Locks the ``mutex``. In case the mutex is currently locked, then the >>> thread is >>> +blocked until it becomes the mutex owner. Threads wait in priority >>> order. >>> + >>> +This function must be called from thread context with interrupts >>> enabled. >>> + >>> +.. c:function:: void rtems_mutex_unlock(rtems_mutex *mutex) >>> + >>> +Unlocks the ``mutex``. In case the currently executing thread is not >>> the owner >>> +of the ``mutex``, then the result is unpredictable. >>> + >>> +This function must be called from thread context with interrupts >>> enabled. >>> + >>> +.. c:function:: void rtems_mutex_destroy(rtems_mutex *mutex) >>> + >>> +Destroys the ``mutex``. In case the ``mutex`` is locked or still in >>> use, then >>> +the result is unpredictable. >>> + >>> +Condition Variables >>> +=================== >>> + >>> +The :c:type:`rtems_condition` provides a condition variable >>> synchronization >>> +object. >>> + >>> +.. c:type:: rtems_condition >>> + I missed saying this. Maybe 'rtems_condition_variable', or 'rtems_condvar', or 'rtems_condition_var'. Condition is a bit too generic of a term I think.
>>> +The ``rtems_condition`` is the type of a condition variable object. The >>> +storage space for this object must be provided by the user. There are >>> no >>> +defined comparison or assignment operators for this type. Only the >>> object >>> +itself may be used for performing synchronization. The result of >>> referring to >>> +copies of the object in calls to :c:func:`rtems_condition_wait`, >>> +:c:func:`rtems_condition_signal`, :c:func:`rtems_condition_broadcast`, >>> and >>> +:c:func:`rtems_condition_destroy` is undefined. Objects of this type >>> must be >>> +initialized via :c:func:`RTEMS_CONDITION_INITIALIZER` or >>> +:c:func:`rtems_condition_init` and must be destroyed via >>> +:c:func:`rtems_condition_destroy`. >>> + >>> +.. c:function:: RTEMS_CONDITION_INITIALIZER(name) >>> + >>> +An initializer for static initialization. It is equivalent to a call to >>> +:c:func:`rtems_condition_init`. Global condition variables without a >>> name may >>> +reside in the ``.bss`` section. >>> + >>> +.. c:function:: void rtems_condition_init(rtems_condition *condition, >>> const char *name) >>> + >>> +Initializes the ``condition`` with the specified ``name``. The ``name`` >>> must >>> +be persistent throughout the life-time of the condition variable. >>> + >>> +.. c:function:: void rtems_condition_wait(rtems_condition *condition, >>> rtems_mutex *mutex) >>> + >>> +Atomically waits for the condition and unlocks the mutex. Once the >>> condition >>> +is signalled to the thread it wakes up and locks the mutex. Threads >>> wait in >>> +priority order. >>> + >>> +This function must be called from thread context with interrupts >>> enabled. >>> + >>> +.. c:function:: void rtems_condition_signal(rtems_condition *condition) >>> + >>> +Signals the condition to the highest priority waiting thread. If no >>> threads >>> +wait currently for the condition, then nothing happens. >>> + >>> +.. c:function:: void rtems_condition_broadcast(rtems_condition >>> *condition) >>> + >>> +Signals the condition to all waiting threads. If no threads wait >>> currently for >>> +the condition, then nothing happens. >>> + >>> +.. c:function:: void rtems_condition_destroy(rtems_condition *condition) >>> + >>> +Destroys the ``condition``. In case the ``condition`` still in use, >>> then the >>> +result is unpredictable. >>> + >>> +Counting Semaphores >>> +=================== >>> + >>> +The :c:type:`rtems_counting_semaphore` provides a counting semaphore >>> +synchronization object. >>> + >>> +.. c:type:: rtems_counting_semaphore >>> + >>> +The ``rtems_counting_semaphore`` is the type of a counting semaphore >>> object. >>> +The storage space for this object must be provided by the user. There >>> are no >>> +defined comparison or assignment operators for this type. Only the >>> object >>> +itself may be used for performing synchronization. The result of >>> referring to >>> +copies of the object in calls to >>> :c:func:`rtems_counting_semaphore_wait`, >>> +:c:func:`rtems_counting_semaphore_post`, and >>> +:c:func:`rtems_counting_semaphore_destroy` is undefined. Objects of >>> this type >>> +must be initialized via :c:func:`RTEMS_COUNTING_SEMAPHORE_INITIALIZER` >>> or >>> +:c:func:`rtems_counting_semaphore_init` and must be destroyed via >>> +:c:func:`rtems_counting_semaphore_destroy`. >>> + >>> +.. c:function:: RTEMS_COUNTING_SEMAPHORE_INITIALIZER(name, value) >>> + >>> +An initializer for static initialization. It is equivalent to a call to >>> +:c:func:`rtems_counting_semaphore_init`. Global counting semaphores >>> without a >>> +name may reside in the ``.bss`` section. >>> + >>> +.. c:function:: void >>> rtems_counting_semaphore_init(rtems_counting_semaphore *semaphore, const >>> char *name, unsigned int count) >>> + >>> +Initializes the ``semaphore`` with the specified ``name`` and ``count``. >>> The >>> +``name`` must be persistent throughout the life-time of the counting >>> semaphore. >>> +The initial value is set to ``count``. >>> + >>> +.. c:function:: void >>> rtems_counting_semaphore_wait(rtems_counting_semaphore *semaphore) >>> + >>> +Waits for the counting semaphore. In case the current semaphore count >>> is >>> +positive, then the count is decremented and the function returns >>> immediately, >>> +otherwise the thread is blocked waiting for a semaphore post. Threads >>> wait in >>> +priority order. >>> + >>> +This function must be called from thread context with interrupts >>> enabled. >>> + >>> +.. c:function:: void >>> rtems_counting_semaphore_post(rtems_counting_semaphore *semaphore) >>> + >>> +Posts the counting semaphore. In case at least one thread is waiting on >>> the >>> +counting semaphore, then the highest priority thread is woken up, >>> otherwise the >>> +current count is incremented. >>> + >> >> Is there a reason not to use "signal" here? >> >> Typically we will see pairs of wait-signal, pend-post, lock-unlock, >> acquire-release, down-up. It is a little unusual to mix between these. > > > I used the POSIX nomenclature: > > http://pubs.opengroup.org/onlinepubs/009695399/basedefs/semaphore.h.html > OK. > >> >>> +This function may be called from interrupt context. In case it is >>> called from >>> +thread context, then interrupts must be enabled. >>> + >>> +.. c:function:: void >>> rtems_counting_semaphore_destroy(rtems_counting_semaphore *semaphore) >>> + >>> +Destroys the ``semaphore``. In case the ``semaphore`` still in use, >>> then the >>> +result is unpredictable. >>> + >>> +Binary Semaphores >>> +================= >>> + >>> +The :c:type:`rtems_binary_semaphore` provides a binary semaphore >>> +synchronization object. >>> + >>> +.. c:type:: rtems_binary_semaphore >>> + >>> +The ``rtems_binary_semaphore`` is the type of a binary semaphore object. >>> The >>> +storage space for this object must be provided by the user. There are >>> no >>> +defined comparison or assignment operators for this type. Only the >>> object >>> +itself may be used for performing synchronization. The result of >>> referring to >>> +copies of the object in calls to :c:func:`rtems_binary_semaphore_wait`, >>> +:c:func:`rtems_binary_semaphore_post`, and >>> +:c:func:`rtems_binary_semaphore_destroy` is undefined. Objects of this >>> type >>> +must be initialized via :c:func:`RTEMS_BINARY_SEMAPHORE_INITIALIZER` or >>> +:c:func:`rtems_binary_semaphore_init` and must be destroyed via >>> +:c:func:`rtems_binary_semaphore_destroy`. >>> + >>> +.. c:function:: RTEMS_BINARY_SEMAPHORE_INITIALIZER(name) >>> + >>> +An initializer for static initialization. It is equivalent to a call to >>> +:c:func:`rtems_binary_semaphore_init`. Global binary semaphores without >>> a name >>> +may reside in the ``.bss`` section. >>> + >>> +.. c:function:: void rtems_binary_semaphore_init(rtems_binary_semaphore >>> *semaphore, const char *name) >>> + >>> +Initializes the ``semaphore`` with the specified ``name``. The ``name`` >>> must >>> +be persistent throughout the life-time of the binary semaphore. The >>> initial >>> +value is set to zero. >>> + >>> +.. c:function:: void rtems_binary_semaphore_wait(rtems_binary_semaphore >>> *semaphore) >>> + >>> +Waits for the binary semaphore. In case the current semaphore count is >>> +positive, then the count is decremented and the function returns >>> immediately, >>> +otherwise the thread is blocked waiting for a semaphore post. Threads >>> wait in >>> +priority order. >>> + >>> +This function must be called from thread context with interrupts >>> enabled. >>> + >>> +.. c:function:: void rtems_binary_semaphore_post(rtems_binary_semaphore >>> *semaphore) >>> + >>> +Posts the binary semaphore. In case at least one thread is waiting on >>> the >>> +binary semaphore, then the highest priority thread is woken up, >>> otherwise the >>> +current count is set to one. >>> + >>> +This function may be called from interrupt context. In case it is >>> called from >>> +thread context, then interrupts must be enabled. >>> >> What is the difference between mutex and binary semaphore? > > > Yes, there is a big difference. A binary semaphore is a counting semaphore > those values are restricted to 0 and 1. It has no owner. > Whichever thread passes 'wait()' is (implicitly) owning the binary semaphore. Semantically there is very little difference to me. Certainly based on the description here I don't know what the difference is and why if I'm a user I should pick rtems_mutex or rtems_binary_semaphore. Do the counting/binary semaphores also use priority inheritance? If the binary semaphore is identically equal to a counting semaphore initialized to 1, then why even include it in the API? > >> >> I'd prefer lock/unlock for mutexes and binary semaphores unless there >> is a good reason for the wait-post/signal terminology. >> >>> +.. c:function:: void >>> rtems_binary_semaphore_destroy(rtems_binary_semaphore *semaphore) >>> + >>> +Destroys the ``semaphore``. In case the ``semaphore`` still in use, >>> then the >>> +result is unpredictable. >>> + >>> +Threads >>> +======= >>> + >>> +.. warning:: >>> + >>> + The self-contained threads support is work in progress. In contrast >>> to the >>> + synchronization objects the self-contained thread support is not just >>> an API >>> + glue layer to already existing implementations. >>> + >>> +The :c:type:`rtems_thread` provides a thread of execution. >>> + >>> +.. c:type:: rtems_thread >>> + >>> +The ``rtems_thread`` is the type of a thread object. >>> + >>> +.. c:function:: RTEMS_THREAD_INITIALIZER(name, stack_size, priority, >>> flags, entry, arg) >>> + >>> +.. c:function:: void rtems_thread_start(rtems_thread *thread, const char >>> *name, size_t stack_size, uint32_t priority, uint32_t flags, void >>> (*entry)(void *), void *arg) >>> + >>> +.. c:function:: void rtems_thread_restart(rtems_thread *thread, void >>> *arg) >>> + >>> +.. c:function:: void rtems_thread_event_send(rtems_thread *thread, >>> uint32_t events) >>> + >> >> non-blocking send only? > > > Yes, just like rtems_event_send(). > >> >>> +.. c:function:: void rtems_thread_event_poll(rtems_thread *thread, >>> uint32_t events_of_interest, uint32_t *actual_events) >>> + >>> +.. c:function:: void rtems_thread_event_wait_all(rtems_thread *thread, >>> uint32_t events_of_interest, uint32_t *actual_events) >>> + >>> +.. c:function:: void rtems_thread_event_wait_any(rtems_thread *thread, >>> uint32_t events_of_interest, uint32_t *actual_events) >>> + >>> +.. c:function:: void rtems_thread_destroy(rtems_thread *thread) >>> + >>> +.. c:function:: void rtems_thread_self_destroy(void) >>> -- >>> 1.8.4.5 >>> >>> _______________________________________________ >>> devel mailing list >>> devel@rtems.org >>> http://lists.rtems.org/mailman/listinfo/devel > > > -- > Sebastian Huber, embedded brains GmbH > > Address : Dornierstr. 4, D-82178 Puchheim, Germany > Phone : +49 89 189 47 41-16 > Fax : +49 89 189 47 41-09 > E-Mail : sebastian.hu...@embedded-brains.de > PGP : Public key available on request. > > Diese Nachricht ist keine geschäftliche Mitteilung im Sinne des EHUG. > _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel