Creating a Mutex
Using a Mutex
Deleting a Mutex
Diagnostics
The Mutex API provides standard mutex functionality with added diagnostics capabilities. These mutexes can be shared by threads within the same process, but can't be shared by threads in different processes.
Two kinds of mutex are supported by Legato:
Normal mutexes are faster than traceable mutexes and consume less memory, but still offer some diagnosic capabilities. Traceable mutexes generally behave the same as Normal mutexes, but can also log their activities.
In addition, both Normal and Traceable mutexes can be either
All mutexes can be locked and unlocked. The same lock, unlock, and delete functions work for all the mutexes, regardless of what type they are. his means that a mutex can be changed from Normal to Traceable (or vice versa) by changing the function you use to create it. This helps to troubleshoot race conditions or deadlocks because it's easy to switch one mutex or a select few mutexes to Traceable without suffering the runtime cost of switching all mutexes to the slower Traceable mutexes.
A recursive mutex can be locked again by the same thread that already has the lock, but a non-recursive mutex can only be locked once before being unlocked.
If a thread grabs a non-recursive mutex lock and then tries to grab that same lock again, a deadlock occurs. Legato's non-recursive mutexes will detect this deadlock, log a fatal error and terminate the process.
If a thread grabs a recursive mutex, and then the same thread grabs the same lock again, the mutex's "lock count" is incremented. When the thread unlocks that mutex, the lock count is decremented. Only when the lock count reaches zero will the mutex actually unlock.
There's a limit to the number of times the same recursive mutex can be locked by the same thread without ever unlocking it, but that limit is so high (at least 2 billion), if that much recursion is going on, there are other, more serious problems with the program.
In Legato, mutexes are dynamically allocated objects. Functions that create them return references to them (of type le_mutex_Ref_t).
These are the functions to create mutexes:
le_mutex_CreateRecursive()
- creates a normal, recursive mutex.le_mutex_CreateNonRecursive()
- creates a normal, non-recursive mutex.le_mutex_CreateTraceableRecursive()
- creates a traceable, recursive mutex.le_mutex_CreateTraceableNonRecursive()
- creates a traceable, non-recursive mutex.All mutexes have names, required for diagnostic purposes. See Diagnostics below.
These are the functions to lock and unlock mutexes:
It doesn't matter what type of mutex you are using, you still use the same functions for locking and unlocking your mutex.
A common case is often where a module has a single mutex it uses for some data structure that may get accessed by multiple threads. To make the locking and unlocking of that mutex jump out at readers of the code (and to make coding a little easier too), the following can be created in that module:
This results in code that looks like this:
To make this easier, the Mutex API provides the LE_MUTEX_DECLARE_REF() macro. Using that macro, the three declaration lines
can be replaced with one:
When you are finished with a mutex, you must delete it by calling le_mutex_Delete().
There must not be anyone using the mutex when it is deleted (i.e., no one can be holding it).
Both Normal and Traceable mutexes have some diagnostics capabilities.
The command-line diagnostic tool lsmutex can be used to list the mutexes that currently exist inside a given process. The state of each mutex can be seen, including a list of any threads that might be waiting for that mutex.
The tool threadlook will report if a given thread is currently holding the lock on a mutex or waiting for a mutex along with the mutex name.
If there are Traceable mutexes in a process, it's possible to use the log tool to enable or disable tracing on that mutex. The trace keyword name is the name of the process, the name of the component, and the name of the mutex, separated by slashes (e.g., "process/component/mutex").
Copyright (C) Sierra Wireless, Inc. 2014. All rights reserved. Use of this work is subject to license.