le_mutex.h

Go to the documentation of this file.
1 /**
2  * @page c_mutex Mutex API
3  *
4  * @ref le_mutex.h "API Reference"
5  *
6  * <HR>
7  *
8  * The Mutex API provides standard mutex functionality with added diagnostics capabilities.
9  * These mutexes can be shared by threads within the same process, but can't
10  * be shared by threads in different processes.
11  *
12  * @warning Multithreaded programming is an advanced subject with many pitfalls.
13  * A general discussion of why and how mutexes are used in multithreaded programming is beyond
14  * the scope of this documentation. If you are not familiar with these concepts @e please seek
15  * out training and mentorship before attempting to work on multithreaded production code.
16  *
17  * Two kinds of mutex are supported by Legato:
18  * - @b Recursive or
19  * - @b Non-Recursive
20  *
21  * All mutexes can be locked and unlocked. The same lock, unlock, and delete
22  * functions work for all the mutexes, regardless of what type they are.
23  *
24  * A recursive mutex can be locked again by the same thread that already has the lock, but
25  * a non-recursive mutex can only be locked once before being unlocked.
26  *
27  * If a thread grabs a non-recursive mutex lock and then tries to grab that same lock again, a
28  * deadlock occurs. Legato's non-recursive mutexes will detect this deadlock, log a fatal error
29  * and terminate the process.
30  *
31  * If a thread grabs a recursive mutex, and then the same thread grabs the same lock again, the
32  * mutex's "lock count" is incremented. When the thread unlocks that mutex, the lock count is
33  * decremented. Only when the lock count reaches zero will the mutex actually unlock.
34  *
35  * There's a limit to the number of times the same recursive mutex can be locked by the same
36  * thread without ever unlocking it, but that limit is so high (at least 2 billion), if that
37  * much recursion is going on, there are other, more serious problems with the program.
38  *
39  * @section c_mutex_create Creating a Mutex
40  *
41  * In Legato, mutexes are dynamically allocated objects. Functions that create them
42  * return references to them (of type le_mutex_Ref_t).
43  *
44  * Functions for creating mutexes:
45  * - @c le_mutex_CreateRecursive() - creates a recursive mutex.
46  * - @c le_mutex_CreateNonRecursive() - creates a non-recursive mutex.
47  *
48  * All mutexes have names, required for diagnostic purposes. See
49  * @ref c_mutex_diagnostics below.
50  *
51  * @section c_mutex_locking Using a Mutex
52  *
53  * Functions for locking and unlocking mutexes:
54  * - @c le_mutex_Lock()
55  * - @c le_mutex_Unlock()
56  * - @c le_mutex_TryLock()
57  *
58  * It doesn't matter what type of mutex you are using, you
59  * still use the same functions for locking and unlocking your mutex.
60  *
61  * @section c_mutex_delete Deleting a Mutex
62  *
63  * When you are finished with a mutex, you must delete it by calling le_mutex_Delete().
64  *
65  * There must not be anyone using the mutex when it is deleted (i.e., no one can be holding it).
66  *
67  * @section c_mutex_diagnostics Diagnostics
68  *
69  * The command-line diagnostic tool @ref toolsTarget_inspect can be used to list the mutexes
70  * that currently exist inside a given process. The state of each mutex can be
71  * seen, including a list of any threads that might be waiting for that mutex.
72  *
73  * <HR>
74  *
75  * Copyright (C) Sierra Wireless Inc.
76  */
77 
78 //--------------------------------------------------------------------------------------------------
79 /**
80  * @file le_mutex.h
81  *
82  * Legato @ref c_mutex include file.
83  *
84  * Copyright (C) Sierra Wireless Inc.
85  */
86 //--------------------------------------------------------------------------------------------------
87 
88 #ifndef LEGATO_MUTEX_INCLUDE_GUARD
89 #define LEGATO_MUTEX_INCLUDE_GUARD
90 
91 //--------------------------------------------------------------------------------------------------
92 /**
93  * Reference to a Mutex object.
94  */
95 //--------------------------------------------------------------------------------------------------
96 typedef struct le_mutex* le_mutex_Ref_t;
97 
98 //--------------------------------------------------------------------------------------------------
99 /**
100  * Create a Recursive mutex.
101  *
102  * @return Returns a reference to the mutex.
103  *
104  * @note Terminates the process on failure, no need to check the return value for errors.
105  */
106 //--------------------------------------------------------------------------------------------------
108 (
109  const char* nameStr ///< [in] Name of the mutex
110 );
111 
112 //--------------------------------------------------------------------------------------------------
113 /**
114  * Create a Non-Recursive mutex.
115  *
116  * @return Returns a reference to the mutex.
117  *
118  * @note Terminates the process on failure, no need to check the return value for errors.
119  */
120 //--------------------------------------------------------------------------------------------------
122 (
123  const char* nameStr ///< [in] Name of the mutex
124 );
125 
126 //--------------------------------------------------------------------------------------------------
127 /**
128  * Delete a mutex.
129  *
130  * @return Nothing.
131  */
132 //--------------------------------------------------------------------------------------------------
133 void le_mutex_Delete
134 (
135  le_mutex_Ref_t mutexRef ///< [in] Mutex reference
136 );
137 
138 //--------------------------------------------------------------------------------------------------
139 /**
140  * Lock a mutex.
141  *
142  * @return Nothing.
143  */
144 //--------------------------------------------------------------------------------------------------
145 void le_mutex_Lock
146 (
147  le_mutex_Ref_t mutexRef ///< [in] Mutex reference
148 );
149 
150 //--------------------------------------------------------------------------------------------------
151 /**
152  * Try a lock on a mutex.
153  *
154  * Locks a mutex, if no other thread holds it. Otherwise, returns without locking.
155  *
156  * @return
157  * - LE_OK if mutex was locked.
158  * - LE_WOULD_BLOCK if mutex was already held by someone else.
159  */
160 //--------------------------------------------------------------------------------------------------
162 (
163  le_mutex_Ref_t mutexRef ///< [in] Mutex reference
164 );
165 
166 //--------------------------------------------------------------------------------------------------
167 /**
168  * Unlock a mutex.
169  *
170  * @return Nothing.
171  */
172 //--------------------------------------------------------------------------------------------------
173 void le_mutex_Unlock
174 (
175  le_mutex_Ref_t mutexRef ///< [in] Mutex reference
176 );
177 
178 //--------------------------------------------------------------------------------------------------
179 /**
180  * Declare a static mutex reference variable and accessor functions.
181  *
182  * This is handy when you need a single, file-scope mutex for use inside your module
183  * to protect other file-scope data structures from multi-threaded race conditions.
184  *
185  * Adding the line
186  * @code
187  * LE_MUTEX_DECLARE_REF(MyMutexRef);
188  * @endcode
189  * near the top of your file will create a file-scope variable called "MyMutexRef" of type
190  * le_mutex_Ref_t and functions called "Lock" and "Unlock" that access that variable.
191  *
192  * See @ref c_mutex_locking_tips for more information.
193  *
194  * @param refName Name of the mutex reference variable.
195  *
196  * @return Nothing.
197  */
198 //--------------------------------------------------------------------------------------------------
199 #define LE_MUTEX_DECLARE_REF(refName) \
200  static le_mutex_Ref_t refName; \
201  static inline void Lock(void) { le_mutex_Lock(refName); } \
202  static inline void Unlock(void) { le_mutex_Unlock(refName); }
203 
204 #endif /* LEGATO_MUTEX_INCLUDE_GUARD */
le_result_t
Definition: le_basics.h:35
struct le_mutex * le_mutex_Ref_t
Definition: le_mutex.h:96
le_mutex_Ref_t le_mutex_CreateRecursive(const char *nameStr)
void le_mutex_Lock(le_mutex_Ref_t mutexRef)
le_result_t le_mutex_TryLock(le_mutex_Ref_t mutexRef)
le_mutex_Ref_t le_mutex_CreateNonRecursive(const char *nameStr)
void le_mutex_Delete(le_mutex_Ref_t mutexRef)
void le_mutex_Unlock(le_mutex_Ref_t mutexRef)