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 #else
27 #include <mutex>
28 #endif
29 
30 namespace Fortran::runtime {
31 
32 class Lock {
33 public:
34 #if USE_PTHREADS
Lock()35   Lock() { pthread_mutex_init(&mutex_, nullptr); }
~Lock()36   ~Lock() { pthread_mutex_destroy(&mutex_); }
Take()37   void Take() {
38     while (pthread_mutex_lock(&mutex_)) {
39     }
40   }
Try()41   bool Try() { return pthread_mutex_trylock(&mutex_) == 0; }
Drop()42   void Drop() { pthread_mutex_unlock(&mutex_); }
43 #else
44   void Take() { mutex_.lock(); }
45   bool Try() { return mutex_.try_lock(); }
46   void Drop() { mutex_.unlock(); }
47 #endif
48 
CheckLocked(const Terminator & terminator)49   void CheckLocked(const Terminator &terminator) {
50     if (Try()) {
51       Drop();
52       terminator.Crash("Lock::CheckLocked() failed");
53     }
54   }
55 
56 private:
57 #if USE_PTHREADS
58   pthread_mutex_t mutex_{};
59 #else
60   std::mutex mutex_;
61 #endif
62 };
63 
64 class CriticalSection {
65 public:
CriticalSection(Lock & lock)66   explicit CriticalSection(Lock &lock) : lock_{lock} { lock_.Take(); }
~CriticalSection()67   ~CriticalSection() { lock_.Drop(); }
68 
69 private:
70   Lock &lock_;
71 };
72 } // namespace Fortran::runtime
73 
74 #endif // FORTRAN_RUNTIME_LOCK_H_
75