1//===-- runtime/lock.h ------------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// Wraps a mutex
10
11#ifndef FORTRAN_RUNTIME_LOCK_H_
12#define FORTRAN_RUNTIME_LOCK_H_
13
14#include "terminator.h"
15
16// Avoid <mutex> if possible to avoid introduction of C++ runtime
17// library dependence.
18#ifndef _WIN32
19#define USE_PTHREADS 1
20#else
21#undef USE_PTHREADS
22#endif
23
24#if USE_PTHREADS
25#include <pthread.h>
26#elif defined(_WIN32)
27// Do not define macros for "min" and "max"
28#define NOMINMAX
29#include <windows.h>
30#else
31#include <mutex>
32#endif
33
34namespace Fortran::runtime {
35
36class Lock {
37public:
38#if USE_PTHREADS
39 Lock() { pthread_mutex_init(mutex: &mutex_, mutexattr: nullptr); }
40 ~Lock() { pthread_mutex_destroy(mutex: &mutex_); }
41 void Take() {
42 while (pthread_mutex_lock(mutex: &mutex_)) {
43 }
44 holder_ = pthread_self();
45 isBusy_ = true;
46 }
47 bool TakeIfNoDeadlock() {
48 if (isBusy_) {
49 auto thisThread{pthread_self()};
50 if (pthread_equal(thread1: thisThread, thread2: holder_)) {
51 return false;
52 }
53 }
54 Take();
55 return true;
56 }
57 bool Try() { return pthread_mutex_trylock(mutex: &mutex_) == 0; }
58 void Drop() {
59 isBusy_ = false;
60 pthread_mutex_unlock(mutex: &mutex_);
61 }
62#elif defined(_WIN32)
63 Lock() { InitializeCriticalSection(&cs_); }
64 ~Lock() { DeleteCriticalSection(&cs_); }
65 void Take() { EnterCriticalSection(&cs_); }
66 bool Try() { return TryEnterCriticalSection(&cs_); }
67 void Drop() { LeaveCriticalSection(&cs_); }
68#else
69 void Take() { mutex_.lock(); }
70 bool Try() { return mutex_.try_lock(); }
71 void Drop() { mutex_.unlock(); }
72#endif
73
74 void CheckLocked(const Terminator &terminator) {
75 if (Try()) {
76 Drop();
77 terminator.Crash("Lock::CheckLocked() failed");
78 }
79 }
80
81private:
82#if USE_PTHREADS
83 pthread_mutex_t mutex_{};
84 volatile bool isBusy_{false};
85 volatile pthread_t holder_;
86#elif defined(_WIN32)
87 CRITICAL_SECTION cs_;
88#else
89 std::mutex mutex_;
90#endif
91};
92
93class CriticalSection {
94public:
95 explicit CriticalSection(Lock &lock) : lock_{lock} { lock_.Take(); }
96 ~CriticalSection() { lock_.Drop(); }
97
98private:
99 Lock &lock_;
100};
101} // namespace Fortran::runtime
102
103#endif // FORTRAN_RUNTIME_LOCK_H_
104

source code of flang/runtime/lock.h