You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by we...@apache.org on 2016/01/06 19:42:11 UTC

incubator-mynewt-site git commit: Add mutex and semaphore documentation

Repository: incubator-mynewt-site
Updated Branches:
  refs/heads/master 53f53619b -> 0d1d4fc9a


Add mutex and semaphore documentation


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/commit/0d1d4fc9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/tree/0d1d4fc9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/diff/0d1d4fc9

Branch: refs/heads/master
Commit: 0d1d4fc9aff099295aa3f001e190966c0ee6b823
Parents: 53f5361
Author: wes3 <wi...@micosa.io>
Authored: Wed Jan 6 10:42:03 2016 -0800
Committer: wes3 <wi...@micosa.io>
Committed: Wed Jan 6 10:42:03 2016 -0800

----------------------------------------------------------------------
 docs/os/mutex.md     | 158 ++++++++++++++++++++++++++++++++++------------
 docs/os/semaphore.md | 158 ++++++++++++++++++++++++++++++++++------------
 2 files changed, 235 insertions(+), 81 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/0d1d4fc9/docs/os/mutex.md
----------------------------------------------------------------------
diff --git a/docs/os/mutex.md b/docs/os/mutex.md
index 0e0c329..d11fcf8 100644
--- a/docs/os/mutex.md
+++ b/docs/os/mutex.md
@@ -6,11 +6,34 @@ Mutex is short for "mutual exclusion"; a mutex provides mutually exclusive acces
 
 ## Description
 
-Describe OS feature here 
+The first order of business when using a mutex is to declare the mutex globally. The mutex needs to be initialized before it is used (see the examples). It is generally a good idea to initialize the mutex before tasks start running in order to avoid a task possibly using the mutex before it is initialized.
+
+When a task wants exclusive access to a shared resource it needs to obtain the mutex by calling *os_mutex_pend*. If the mutex is currently owned by a different task (a lower priority task), the requesting task will be put to sleep and the owners priority will be elevated to the priority of the requesting task. Note that multiple tasks can request ownership and the current owner is elevated to the highest priority of any task waitin on the mutex. When the task is done using the shared resource, it needs to release the mutex by called *os_mutex_release*. There needs to be one release per call to pend. Note that nested calls to *os_mutex_pend* are allowed but there needs to be one release per pend.
+
+The following example will illustrate how priority inheritance works. In this example, the task number is the same as its priority. Remember that the lower the number, the higher the priority (i.e. priority 0 is higher priority than priority 1). Suppose that task 5 gets ownership of a mutex but is preempted by task 4. Task 4 attempts to gain ownership of the mutex but cannot as it is owned by task 5. Task 4 is put to sleep and task 5 is temporarily raised to priority 4. Before task 5 can release the mutex, task 3 runs and attempts to acquire the mutex. At this point, both task 3 and task 4 are waiting on the mutex (sleeping). Task 5 now runs at priority 3 (the highest priority of all the tasks waiting on the mutex). When task 5 finally releases the mutex it will be preempted as two higher priority tasks are waiting for it. 
+
+Note that when multiple tasks are waiting on a mutex owned by another task, once the mutex is released the highest priority task waiting on the mutex is run. 
 
 ## Data structures
 
-Replace this with the list of data structures used, why, any neat features
+```
+struct os_mutex
+{
+    SLIST_HEAD(, os_task) mu_head;
+    uint8_t     _pad;
+    uint8_t     mu_prio;
+    uint16_t    mu_level;
+    struct os_task *mu_owner;
+};
+
+```
+| Element | Description |
+|-----------|-------------|
+| mu_head |  Queue head for list of tasks waiting on mutex  |
+| _pad |  Padding  |
+| mu_prio |  Default priority of owner of mutex. Used to reset priority of task when mutex released  |
+| mu_level | Call nesting level (for nested calls) |
+| mu_owner | Pointer to task structure which owns mutex |
 
 ## List of Functions
 
@@ -20,8 +43,8 @@ The functions available in this OS feature are:
 
 * [os_mutex_init](#function-os_mutex_init)
 * [os_mutex_release](#function-os_mutex_release)
-* add the rest
-
+* [os_mutex_pend](#function-os_mutex_pend)
+* [os_mutex_delete](#function-os_mutex_delete)
 
 ## Function Reference
 
@@ -30,39 +53,39 @@ The functions available in this OS feature are:
 ### <font color="2980b9">function os_mutex_init</font>
 
 ```
-    os_error_t
-    os_mutex_init(struct os_mutex *mu)
+os_error_t os_mutex_init(struct os_mutex *mu)
     
 ```
 
-<Insert short description>
-
+Initialize the mutex. Must be called before the mutex can be used.
 
 #### Arguments
 
 | Arguments | Description |
 |-----------|-------------|
-| xx |  explain argument xx  |
-| yy |  explain argument yy  |
+| *mu|  Pointer to mutex  |
 
 #### Returned values
 
-List any values returned.
-Error codes?
+OS_INVALID_PARM: returned when *mu is NULL on entry.
+
+OS_OK: mutex initialized successfully.
 
 #### Notes 
 
-Any special feature/special benefit that we want to tout. 
+<Any special feature/special benefit that we want to tout. 
 Does it need to be used with some other specific functions?
-Any caveats to be careful about (e.g. high memory requirements).
+Any caveats to be careful about (e.g. high memory requirements).>
 
 #### Example
 
-<Add text to set up the context for the example here>
 
 ```
+struct os_mutex g_mutex1;
+os_error_t err;
 
-<Insert the code snippet here>
+err = os_mutex_init(&g_mutex1);
+assert(err == OS_OK);
 
 ```
 
@@ -71,80 +94,135 @@ Any caveats to be careful about (e.g. high memory requirements).
 ### <font color="#2980b9"> function os_mutex_release</font>
 
 ```
-   <Insert function callout here >
+os_error_t os_mutex_release(struct os_mutex *mu)
+
    
 ```
 
-<Insert short description>
+Release ownership of a mutex
 
 
 #### Arguments
 
 | Arguments | Description |
 |-----------|-------------|
-| xx |  explain argument xx  |
-| yy |  explain argument yy  |
+| *mu|  Pointer to mutex  |
 
 #### Returned values
+OS_INVALID_PARM: returned when *mu is NULL on entry.
 
-List any values returned.
-Error codes?
+OS_OK: mutex initialized successfully.
 
-#### Notes 
+OS_BAD_MUTEX: The mutex was not owned by the task attempting to release it.
+
+OS_NOT_STARTED: Attempt to release a mutex before the os has been started.
 
-Any special feature/special benefit that we want to tout. 
-Does it need to be used with some other specific functions?
-Any caveats to be careful about (e.g. high memory requirements).
 
 #### Example
 
-<Add text to set up the context for the example here>
 
 ```
+struct os_mutex g_mutex1;
+os_error_t err;
+
+err = os_mutex_pend(&g_mutex1, 0);
+assert(err == OS_OK);
+
+/* Perform operations requiring exclusive access */
 
-<Insert the code snippet here>
+err = os_mutex_release(&g_mutex1);
+assert(err == OS_OK);
 
 ```
 
 ---------------------
    
-### <font color="#2980b9"> function next_one </font>
+### <font color="#2980b9"> function os_mutex_pend </font>
 
 ```
-   <Insert function callout here >
+os_error_t os_mutex_pend(struct os_mutex *mu, uint32_t timeout)
    
 ```
 
-<Insert short description>
+Acquire ownership of a mutex.
 
 
 #### Arguments
 
 | Arguments | Description |
 |-----------|-------------|
-| xx |  explain argument xx  |
-| yy |  explain argument yy  |
+| *mu |  Pointer to mutex  |
+| timeout | Timeout, in os ticks. A value of 0 means no timeout. A value of 0xFFFFFFFF means to wait forever.   |
 
 #### Returned values
 
-List any values returned.
-Error codes?
+OS_INVALID_PARM: returned when *mu is NULL on entry.
+
+OS_OK: mutex was successfully acquired.
+
+OS_TIMEOUT: the mutex was not available within the timeout specified.
+
+OS_NOT_STARTED: Attempt to release a mutex before the os has been started.
+
 
 #### Notes 
 
-Any special feature/special benefit that we want to tout. 
-Does it need to be used with some other specific functions?
-Any caveats to be careful about (e.g. high memory requirements).
+If the mutex is owned by another task and the timeout is 0 the function returns immediately with the error code OS_TIMEOUT. The calling task *does not* own the mutex when this occurs.
 
 #### Example
 
-<Add text to set up the context for the example here>
+
 
 ```
+struct os_mutex g_mutex1;
+os_error_t err;
+
+err = os_mutex_pend(&g_mutex1, 0);
+assert(err == OS_OK);
+
+/* Perform operations requiring exclusive access */
+
+err = os_mutex_release(&g_mutex1);
+assert(err == OS_OK);
 
-<Insert the code snippet here>
 
 ```
 
 ---------------------
 
+### <font color="#2980b9"> function os_mutex_delete </font>
+
+```
+os_error_t os_mutex_pend(struct os_mutex *mu)
+   
+```
+
+Delete a mutex
+
+#### Arguments
+
+| Arguments | Description |
+|-----------|-------------|
+| *mu |  Pointer to mutex  |
+
+#### Returned values
+
+OS_INVALID_PARM: returned when *mu is NULL on entry.
+
+OS_OK: mutex initialized successfully.
+
+OS_NOT_STARTED: Attempt to release a mutex before the os has been started.
+
+#### Example
+
+```
+struct os_mutex g_mutex1;
+os_error_t err;
+
+err = os_mutex_delete(&g_mutex1);
+assert(err == OS_OK);
+
+
+```
+
+---------------------

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-site/blob/0d1d4fc9/docs/os/semaphore.md
----------------------------------------------------------------------
diff --git a/docs/os/semaphore.md b/docs/os/semaphore.md
index c05a1a8..fe69644 100644
--- a/docs/os/semaphore.md
+++ b/docs/os/semaphore.md
@@ -1,16 +1,34 @@
 # Semaphore
 
-
-Insert synopsis here
+A semaphore is a structure used for gaining exclusive access (much like a mutex), synchronizing task operations and/or use in a "producer/consumer" roles. Semaphores like the ones used by the myNewt OS are called "counting" semaphores as they are allowed to have more than one token (explained below).
 
 
 ## Description
 
-Describe OS feature here 
+A semaphore is a fairly simple construct consisting of a queue for waiting tasks and the number of tokens currently owned by the semaphore. A semaphore can be obtained as long as there are tokens in the semaphore. Any task can add tokens to the semaphore and any task can request the semaphore, thereby removing tokens. When creating the semaphore, the initial number of tokens can be set as well.
+
+When used for exclusive access to a shared resource the semaphore only needs a single token. In this case, a single task "creates" the semaphore by calling *os_sem_init* with a value of one (1) for the token. When a task desires exclusive access to the shared resource it requests the semaphore by calling *os_sem_pend*. If there is a token the requesting task will acquire the semaphore and continue operation. If no tokens are available the task will be put to sleep until there is a token. A common "problem" with using a semaphore for exclusive access is called *priority inversion*. Consider the following scenario: a high and low priority task both share a resource which is locked using a semaphore. If the low priority task obtains the semaphore and then the high priority task requests the semaphore, the high priority task is now blocked until the low priority task releases the semaphore. Now suppose that there are tasks between the low priority task and the high priority task that wa
 nt to run. These tasks will preempt the low priority task which owns the semaphore. Thus, the high priority task is blocked waiting for the low priority task to finish using the semaphore but the low priority task cannot run since other tasks are running. Thus, the high priority tasks is "inverted" in priority; in effect running at a much lower priority as normally it would preempt the other (lower priority) tasks. If this is an issue a mutex should be used instead of a semaphore.
+
+Semaphores can also be used for task synchronization. A simple example of this would be the following. A task creates a semaphore and initializes it with no tokens. The task then waits on the semaphore, and since there are no tokens, the task is put to sleep. When other tasks want to wake up the sleeping task they simply add a token by calling *os_sem_release*. This will cause the sleeping task to wake up (instantly if no other higher priority tasks want to run).
+
+The other common use of a counting semaphore is in what is commonly called a "producer/consumer" relationship. The producer adds tokens (by calling *os_sem_release*) and the consumer consumes them by calling *os_sem_pend*. In this relationship, the producer has work for the consumer to do. Each token added to the semaphore will cause the consumer to do whatever work is required. A simple example could be the following: every time a button is pressed there is some work to do (ring a bell). Each button press causes the producer to add a token. Each token consumed rings the bell. There will exactly the same number of bell rings as there are button presses. In other words, each call to *os_sem_pend* subtracts exactly one token and each call to *os_sem_release* adds exactly one token.
 
 ## Data structures
+```
 
-Replace this with the list of data structures used, why, any neat features
+struct os_sem
+{
+    SLIST_HEAD(, os_task) sem_head;     /* chain of waiting tasks */
+    uint16_t    _pad;
+    uint16_t    sem_tokens;             /* # of tokens */
+};
+```
+
+| Element | Description |
+|-----------|-------------|
+| sem_head |  Queue head for list of tasks waiting on semaphore |
+| _pad |  Padding for alignment  |
+| sem_tokens | Current number of tokens |
 
 ## List of Functions
 
@@ -20,7 +38,8 @@ The functions available in this OS feature are:
 
 * [os_sem_init](#function-os_sem_init)
 * [os_sem_release](#function-os_sem_release)
-* add the rest
+* [os_sem_pend](#function-os_sem_pend)
+* [os_sem_delete](#function-os_sem_delete)
 
 
 ## Function Reference
@@ -30,39 +49,42 @@ The functions available in this OS feature are:
 ### <font color="2980b9">function os_sem_init</font>
 
 ```
-    os_error_t
-    os_sem_init(struct os_sem *sem, uint16_t tokens)    
+    os_error_t os_sem_init(struct os_sem *sem, uint16_t tokens)    
 
 ```
 
-<Insert short description>
+Initialize a semaphore with a given number of tokens. Should be called before the semaphore is used.
 
 
 #### Arguments
 
 | Arguments | Description |
 |-----------|-------------|
-| xx |  explain argument xx  |
-| yy |  explain argument yy  |
+| *sem |  Pointer to semaphore  |
+| tokens |  Initial number of tokens allocated to semaphore  |
 
 #### Returned values
 
-List any values returned.
-Error codes?
+OS_INVALID_PARM: returned when *sem is NULL on entry.
+
+OS_OK: semaphore initialized successfully.
 
 #### Notes 
 
-Any special feature/special benefit that we want to tout. 
+<Any special feature/special benefit that we want to tout. 
 Does it need to be used with some other specific functions?
-Any caveats to be careful about (e.g. high memory requirements).
+Any caveats to be careful about (e.g. high memory requirements).>
 
 #### Example
 
-<Add text to set up the context for the example here>
+The following example shows how to initialize a semaphore used for exclusive access.
 
 ```
+struct os_mutex g_os_sem;
+os_error_t err;
 
-<Insert the code snippet here>
+err = os_sem_init(&g_os_sem, 1);
+assert(err == OS_OK);
 
 ```
 
@@ -71,78 +93,132 @@ Any caveats to be careful about (e.g. high memory requirements).
 ### <font color="#2980b9"> function os_sem_release </font>
 
 ```
-   <Insert function callout here >
+os_error_t os_sem_release(struct os_sem *sem)
    
 ```
 
-<Insert short description>
+Release a semaphore that you are holding. This adds a token to the semaphore.
 
 
 #### Arguments
 
 | Arguments | Description |
 |-----------|-------------|
-| xx |  explain argument xx  |
-| yy |  explain argument yy  |
+| *sem |  Pointer to semaphore  |
 
 #### Returned values
 
-List any values returned.
-Error codes?
+OS_NOT_STARTED: Called before os has been started.
+
+OS_INVALID_PARM: returned when *sem is NULL on entry.
+
+OS_OK: semaphore released successfully.
 
 #### Notes 
 
-Any special feature/special benefit that we want to tout. 
-Does it need to be used with some other specific functions?
-Any caveats to be careful about (e.g. high memory requirements).
 
 #### Example
 
-<Add text to set up the context for the example here>
-
 ```
+struct os_sem g_os_sem;
+os_error_t err;
 
-<Insert the code snippet here>
+err = os_sem_pend(&g_os_sem, OS_TIMEOUT_NEVER);
+assert(err == OS_OK);
+
+/* Perform operations requiring semaphore lock */
+
+err = os_sem_release(&g_os_sem);
+assert(err == OS_OK);
 
 ```
 
 ---------------------
    
-### <font color="#2980b9"> function next_one </font>
+### <font color="#2980b9"> function os_sem_pend </font>
 
 ```
-   <Insert function callout here >
+os_error_t os_sem_pend(struct os_sem *sem, uint32_t timeout)
    
 ```
 
-<Insert short description>
-
+Wait for a semaphore for a given amount of time.
 
 #### Arguments
 
 | Arguments | Description |
 |-----------|-------------|
-| xx |  explain argument xx  |
-| yy |  explain argument yy  |
+| *sem |  Pointer to semaphore  |
+| timeout |  Amount of time, in os ticks, to wait for semaphore. A value of 0 means no wait. A value of 0xFFFFFFFF means wait forever.  |
 
 #### Returned values
 
-List any values returned.
-Error codes?
+OS_INVALID_PARM: returned when *sem is NULL on entry.
+
+OS_OK: semaphore acquired successfully.
+
+OS_TIMEOUT: the semaphore was not available within the timeout specified.
+
+OS_NOT_STARTED: Attempt to release a semaphore before os started.
 
 #### Notes 
 
-Any special feature/special benefit that we want to tout. 
-Does it need to be used with some other specific functions?
-Any caveats to be careful about (e.g. high memory requirements).
+If a timeout of 0 is used and the function returns OS_TIMEOUT, the semaphore was not available and was not acquired. No release of the semaphore should occur and the calling task does not own the semaphore.
 
 #### Example
 
-<Add text to set up the context for the example here>
+```
+struct os_sem g_os_sem;
+os_error_t err;
+
+err = os_sem_pend(&g_os_sem, OS_TIMEOUT_NEVER);
+assert(err == OS_OK);
+
+/* Perform operations requiring semaphore lock */
+
+err = os_sem_release(&g_os_sem);
+assert(err == OS_OK);
+
+```
+
+---------------------
+
+### <font color="#2980b9"> function os_sem_delete </font>
 
 ```
+os_error_t os_sem_delete(struct os_sem *sem)
+   
+```
+
+Delete a semaphore
+
+#### Arguments
+
+| Arguments | Description |
+|-----------|-------------|
+| *sem |  Pointer to semaphore  |
+
+#### Returned values
+
+OS_INVALID_PARM: returned when *sem is NULL on entry.
+
+OS_OK: semaphore deleted successfully.
+
+OS_NOT_STARTED: Attempt to release a semaphore before os started.
+
+#### Notes 
+
+Care must be taken when deleting a semaphore as deleting a semaphore used by other tasks could causes unexpected/unwanted behavior.
+
+#### Example
+
+```
+struct os_sem g_os_sem;
+os_error_t err;
+
+err = os_sem_delete(&g_os_sem);
+assert(err == OS_OK);
 
-<Insert the code snippet here>
 
 ```