[PATCH] c-user: Add self-contained objects chapter

Sebastian Huber sebastian.huber at embedded-brains.de
Thu Feb 2 15:30:31 UTC 2017



On 02/02/17 16:26, Gedare Bloom wrote:
> On Wed, Feb 1, 2017 at 5:17 AM, Sebastian Huber
> <sebastian.huber at 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.

I used the POSIX nomenclature:

http://pubs.opengroup.org/onlinepubs/009695399/basedefs/semaphore.h.html

>
>> +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.

>
> 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 at 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.huber at embedded-brains.de
PGP     : Public key available on request.

Diese Nachricht ist keine geschäftliche Mitteilung im Sinne des EHUG.



More information about the devel mailing list