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 34 namespace Fortran::runtime { 35 36 class Lock { 37 public: 38 #if USE_PTHREADS Lock()39 Lock() { pthread_mutex_init(&mutex_, nullptr); } ~Lock()40 ~Lock() { pthread_mutex_destroy(&mutex_); } Take()41 void Take() { 42 while (pthread_mutex_lock(&mutex_)) { 43 } 44 } Try()45 bool Try() { return pthread_mutex_trylock(&mutex_) == 0; } Drop()46 void Drop() { pthread_mutex_unlock(&mutex_); } 47 #elif defined(_WIN32) 48 Lock() { InitializeCriticalSection(&cs_); } 49 ~Lock() { DeleteCriticalSection(&cs_); } 50 void Take() { EnterCriticalSection(&cs_); } 51 bool Try() { return TryEnterCriticalSection(&cs_); } 52 void Drop() { LeaveCriticalSection(&cs_); } 53 #else 54 void Take() { mutex_.lock(); } 55 bool Try() { return mutex_.try_lock(); } 56 void Drop() { mutex_.unlock(); } 57 #endif 58 CheckLocked(const Terminator & terminator)59 void CheckLocked(const Terminator &terminator) { 60 if (Try()) { 61 Drop(); 62 terminator.Crash("Lock::CheckLocked() failed"); 63 } 64 } 65 66 private: 67 #if USE_PTHREADS 68 pthread_mutex_t mutex_{}; 69 #elif defined(_WIN32) 70 CRITICAL_SECTION cs_; 71 #else 72 std::mutex mutex_; 73 #endif 74 }; 75 76 class CriticalSection { 77 public: CriticalSection(Lock & lock)78 explicit CriticalSection(Lock &lock) : lock_{lock} { lock_.Take(); } ~CriticalSection()79 ~CriticalSection() { lock_.Drop(); } 80 81 private: 82 Lock &lock_; 83 }; 84 } // namespace Fortran::runtime 85 86 #endif // FORTRAN_RUNTIME_LOCK_H_ 87