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 > + > +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. > +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? 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? > +.. 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 _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel