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