Skip to content

Commit

Permalink
Add info about how named mutexes work on Unix into code from the orgi…
Browse files Browse the repository at this point in the history
…nal PR (#43161)

* Add exception case xml comment for ExecutionContext.Restore

* Add some info about how named mutexes work on Unixes into code from the PR
  • Loading branch information
kouvel authored Oct 27, 2020
1 parent ae9da64 commit f5c17f1
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
54 changes: 54 additions & 0 deletions src/coreclr/src/pal/src/include/pal/mutex.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,60 @@ DWORD SPINLOCKTryAcquire (LONG * lock);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Named mutex

/*
Design
- On systems that support pthread process-shared robust recursive mutexes, they will be used
- On other systems, file locks are used. File locks unfortunately don't have a timeout in the blocking wait call, and I didn't
find any other sync object with a timed wait with the necessary properties, so polling is done for timed waits.
Shared memory files
- Session-scoped mutexes (name not prefixed, or prefixed with Local) go in /tmp/coreclr/shm/session<sessionId>/<mutexName>
- Globally-scoped mutexes (name prefixed with Global) go in /tmp/coreclr/shm/global/<mutexName>
- Contains shared state, and is mmap'ped into the process, see SharedMemorySharedDataHeader and NamedMutexSharedData for data
stored
- Creation and deletion is synchronized using an exclusive file lock on the shm directory
- Any process using the shared memory file holds a shared file lock on the shared memory file
- Upon creation, if the shared memory file already exists, an exclusive file lock is attempted on it, to see if the file data is
valid. If no other processes have the mutex open, the file is reinitialized.
- Upon releasing the last reference to a mutex in a process, it will try to get an exclusive lock on the shared memory file to
see if any other processes have the mutex opened. If not, the file is deleted, along with the session directory if it's empty.
The coreclr and shm directories are not deleted.
- This allows managing the lifetime of mutex state based on active processes that have the mutex open. Depending on how the
process terminated, the file may still be left over in the tmp directory, I haven't found anything that can be done about
that.
Lock files when using file locks:
- In addition to the shared memory file, we need another file for the actual synchronization file lock, since a file lock on the
shared memory file is used for lifetime purposes.
- These files go in /tmp/coreclr/lockfiles/session<sessionId>|global/<mutexName>
- The file is empty, and is only used for file locks
Process data
- See SharedMemoryProcessDataHeader and NamedMutexProcessData for data stored
- Per mutex name, there is only one instance of process data that is ref-counted. They are currently stored in a linked list in
SharedMemoryManager. It should use a hash table, but of the many hash table implementations that are already there, none seem
to be easily usable in the PAL. I'll look into that and will fix later.
- Refers to the associated shared memory, and knows how to clean up both the process data and shared data
- When using file locks for synchronization, a process-local mutex is also created for synchronizing threads, since file locks
are owned at the file descriptor level and there is only one open file descriptor in the process per mutex name. The
process-local mutex is locked around the file lock, so that only one thread per process is ever trying to flock on a given
file descriptor.
Abandon detection
- When a lock is acquired, the process data is added to a linked list on the owning thread
- When a thread exits, the list is walked, each mutex is flagged as abandoned and released
- For detecting process abruptly terminating, pthread robust mutexes give us that. When using file locks, the file lock is
automatically released by the system. Upon acquiring a lock, the lock owner info in the shared memory is checked to see if the
mutex was abandoned.
Miscellaneous
- CreateMutex and OpenMutex both create new handles for each mutex opened. Each handle just refers to the process data header
for the mutex name.
- Some of the above features are already available in the PAL, but not quite in a way that I can use for this purpose. The
existing shared memory, naming, and waiting infrastructure is not suitable for this purpose, and is not used.
*/

// Temporarily disabling usage of pthread process-shared mutexes on ARM/ARM64 due to functional issues that cannot easily be
// detected with code due to hangs. See https://github.com/dotnet/runtime/issues/6014.
#if HAVE_FULLY_FEATURED_PTHREAD_MUTEXES && HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES && !(defined(HOST_ARM) || defined(HOST_ARM64) || defined(__FreeBSD__))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ internal static void RunInternal(ExecutionContext? executionContext, ContextCall
/// It will not automatically be reverted unlike <seealso cref="ExecutionContext.Run"/>.
/// </remarks>
/// <param name="executionContext">The ExecutionContext to set.</param>
/// <exception cref="InvalidOperationException"><paramref name="executionContext"/> is null.</exception>
public static void Restore(ExecutionContext executionContext)
{
if (executionContext == null)
Expand Down

0 comments on commit f5c17f1

Please sign in to comment.