le_mutex.h

Go to the documentation of this file.
1 /**
2  * @page c_mutex Mutex API
3  *
4  * @subpage 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 #if LE_CONFIG_MUTEX_NAMES_ENABLED
100 //--------------------------------------------------------------------------------------------------
101 /**
102  * Create a Recursive mutex.
103  *
104  * @param[in] nameStr Name of the mutex
105  *
106  * @return Returns a reference to the mutex.
107  *
108  * @note Terminates the process on failure, no need to check the return value for errors.
109  */
110 //--------------------------------------------------------------------------------------------------
112 (
113  const char *nameStr
114 );
115 #else /* if not LE_CONFIG_MUTEX_NAMES_ENABLED */
116 /// @cond HIDDEN_IN_USER_DOCS
117 //--------------------------------------------------------------------------------------------------
118 /**
119  * Internal function used to implement le_mutex_CreateRecursive().
120  */
121 //--------------------------------------------------------------------------------------------------
122 le_mutex_Ref_t _le_mutex_CreateRecursive(void);
123 /// @endcond
124 //--------------------------------------------------------------------------------------------------
125 /**
126  * Create a Recursive mutex.
127  *
128  * @param[in] nameStr Name of the mutex
129  *
130  * @return Returns a reference to the mutex.
131  *
132  * @note Terminates the process on failure, no need to check the return value for errors.
133  */
134 //--------------------------------------------------------------------------------------------------
136 (
137  const char *nameStr
138 )
139 {
140  return _le_mutex_CreateRecursive();
141 }
142 #endif /* end LE_CONFIG_MUTEX_NAMES_ENABLED */
143 
144 
145 #if LE_CONFIG_MUTEX_NAMES_ENABLED
146 //--------------------------------------------------------------------------------------------------
147 /**
148  * Create a Non-Recursive mutex.
149  *
150  * @param[in] nameStr Name of the mutex
151  *
152  * @return Returns a reference to the mutex.
153  *
154  * @note Terminates the process on failure, no need to check the return value for errors.
155  */
156 //--------------------------------------------------------------------------------------------------
158 (
159  const char *nameStr
160 );
161 #else /* if not LE_CONFIG_MUTEX_NAMES_ENABLED */
162 /// @cond HIDDEN_IN_USER_DOCS
163 //--------------------------------------------------------------------------------------------------
164 /**
165  * Internal function used to implement le_mutex_CreateNonRecursive().
166  */
167 //--------------------------------------------------------------------------------------------------
168 le_mutex_Ref_t _le_mutex_CreateNonRecursive(void);
169 /// @endcond
170 //--------------------------------------------------------------------------------------------------
171 /**
172  * Create a Non-Recursive mutex.
173  *
174  * @param[in] nameStr Name of the mutex
175  *
176  * @return Returns a reference to the mutex.
177  *
178  * @note Terminates the process on failure, no need to check the return value for errors.
179  */
180 //--------------------------------------------------------------------------------------------------
182 (
183  const char *nameStr
184 )
185 {
186  return _le_mutex_CreateNonRecursive();
187 }
188 #endif /* end LE_CONFIG_MUTEX_NAMES_ENABLED */
189 
190 
191 //--------------------------------------------------------------------------------------------------
192 /**
193  * Delete a mutex.
194  *
195  * @return Nothing.
196  */
197 //--------------------------------------------------------------------------------------------------
198 void le_mutex_Delete
199 (
200  le_mutex_Ref_t mutexRef ///< [in] Mutex reference
201 );
202 
203 //--------------------------------------------------------------------------------------------------
204 /**
205  * Lock a mutex.
206  *
207  * @return Nothing.
208  */
209 //--------------------------------------------------------------------------------------------------
210 void le_mutex_Lock
211 (
212  le_mutex_Ref_t mutexRef ///< [in] Mutex reference
213 );
214 
215 //--------------------------------------------------------------------------------------------------
216 /**
217  * Try a lock on a mutex.
218  *
219  * Locks a mutex, if no other thread holds it. Otherwise, returns without locking.
220  *
221  * @return
222  * - LE_OK if mutex was locked.
223  * - LE_WOULD_BLOCK if mutex was already held by someone else.
224  */
225 //--------------------------------------------------------------------------------------------------
227 (
228  le_mutex_Ref_t mutexRef ///< [in] Mutex reference
229 );
230 
231 //--------------------------------------------------------------------------------------------------
232 /**
233  * Unlock a mutex.
234  *
235  * @return Nothing.
236  */
237 //--------------------------------------------------------------------------------------------------
238 void le_mutex_Unlock
239 (
240  le_mutex_Ref_t mutexRef ///< [in] Mutex reference
241 );
242 
243 //--------------------------------------------------------------------------------------------------
244 /**
245  * Declare a static mutex reference variable and accessor functions.
246  *
247  * This is handy when you need a single, file-scope mutex for use inside your module
248  * to protect other file-scope data structures from multi-threaded race conditions.
249  *
250  * Adding the line
251  * @code
252  * LE_MUTEX_DECLARE_REF(MyMutexRef);
253  * @endcode
254  * near the top of your file will create a file-scope variable called "MyMutexRef" of type
255  * le_mutex_Ref_t and functions called "Lock" and "Unlock" that access that variable.
256  *
257  * See @ref c_mutex_locking_tips for more information.
258  *
259  * @param refName Name of the mutex reference variable.
260  *
261  * @return Nothing.
262  */
263 //--------------------------------------------------------------------------------------------------
264 #define LE_MUTEX_DECLARE_REF(refName) \
265  static le_mutex_Ref_t refName; \
266  static inline void Lock(void) { le_mutex_Lock(refName); } \
267  static inline void Unlock(void) { le_mutex_Unlock(refName); }
268 
269 #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)
#define LE_DECLARE_INLINE
Definition: le_basics.h:274