[runtime] add initial changes to support cygwin pthread_mutex_timedwait is not supported on cygwin, so an alternate implementation of UMLRTMutex is required. This version has manifested two known problems to date: 1. Bug 469428: On Linux, deadlock appeared to occur, resulting in two threads waiting on the UMLRTMutexGuard associated with the RTS global lock mutex - one thread while giving the global lock, one thread while taking the global lock. 2. Bug 469429: On Windows, (cygwin version) the rts-computer test model crashes shortly after de-registering the ComputerStatus service port. Change-Id: I7399febb290f97aac3e8abfc3b1d627480d5e87b Signed-off-by: Barry Maher <bmaher@gpinc.ca>
diff --git a/rts/include/umlrtmutex.hh b/rts/include/umlrtmutex.hh index 650695d..3cab899 100644 --- a/rts/include/umlrtmutex.hh +++ b/rts/include/umlrtmutex.hh
@@ -19,6 +19,15 @@ // Currently not os-indepedent. // Bug 32 tracks move of this implementation to +/os/linux. +class UMLRTMutexGuard +{ +public: + UMLRTMutexGuard ( pthread_mutex_t & m_ ) : mutex(m_) { pthread_mutex_lock( &mutex ); } + ~ UMLRTMutexGuard ( ) { pthread_mutex_unlock( &mutex ); } +private: + pthread_mutex_t mutex; +}; + class UMLRTMutex { public: @@ -33,14 +42,16 @@ void take(void); // Wait only so many milliseconds. - // Timed - returns non-zero for success, zero for timeout. - int take( uint32_t msec ); + // Timed - returns true for success, false for timeout. + bool take( uint32_t msec ); // Give it back. void give(void); private: - pthread_mutex_t mutex; + pthread_mutex_t guard; + pthread_cond_t condition; + bool locked; }; #endif // UMLRTMUTEX_HH
diff --git a/rts/umlrt/umlrtmutex.cc b/rts/umlrt/umlrtmutex.cc index 4a24598..513cce2 100644 --- a/rts/umlrt/umlrtmutex.cc +++ b/rts/umlrt/umlrtmutex.cc
@@ -19,31 +19,28 @@ // Bug 32 tracks the move of this implementation to +/os/linux/osmutex.cc -UMLRTMutex::UMLRTMutex() +UMLRTMutex::UMLRTMutex() : guard(), condition(), locked(false) { - pthread_mutex_init(&mutex, NULL); -} - -// Can create a mutex which starts life as taken already. -UMLRTMutex::UMLRTMutex( bool taken ) -{ - if (taken) - { - take(); - } + pthread_mutex_init(&guard, NULL); + pthread_cond_init(&condition, NULL); } UMLRTMutex::~UMLRTMutex() { - pthread_mutex_destroy(&mutex); + pthread_mutex_destroy(&guard); + pthread_cond_destroy(&condition); } + // Wait forever for mutex. void UMLRTMutex::take() { - if (pthread_mutex_lock(&mutex) < 0) + UMLRTMutexGuard g(guard); + + while (locked) { - FATAL_ERRNO("pthread_mutex_lock"); + pthread_cond_wait(&condition, &guard); } + locked = true; } // Timed - returns non-zero for success, zero for timeout. @@ -52,23 +49,29 @@ #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #endif -int UMLRTMutex::take( uint32_t msec ) +bool UMLRTMutex::take( uint32_t msec ) { struct timespec timeout; - int success = !0; - UMLRTTimespec::timespecAbsAddMsec( &timeout, msec ); - if (pthread_mutex_timedlock(&mutex, &timeout) < 0) + + UMLRTMutexGuard g(guard); + + while (locked) { - int errno_ = errno; - if (errno_ != ETIMEDOUT) + if (pthread_cond_timedwait(&condition, &guard, &timeout) != 0) { - FATAL_ERRNO("pthread_mutex_timedlock"); + int errno_ = errno; + if (errno_ != ETIMEDOUT) + { + FATAL_ERRNO("pthread_cond_timedwait"); + } + return false; // Timed out - return error indication. } - success = 0; } - return success; + locked = true; + return true; // Obtained lock within timeout. } + #if (((__GNUC__ * 100) + __GNUC_MINOR__) >= 406) #pragma GCC diagnostic pop #endif @@ -76,9 +79,8 @@ // Give mutex back. void UMLRTMutex::give() { - if (pthread_mutex_unlock(&mutex) < 0) - { - FATAL_ERRNO("pthread_mutex_unlock"); - } + UMLRTMutexGuard g(guard); + locked = false; + pthread_cond_signal(&condition); }
diff --git a/rts/umlrt/umlrtprioritymessagequeue.cc b/rts/umlrt/umlrtprioritymessagequeue.cc index f49ee11..f9e3415 100644 --- a/rts/umlrt/umlrtprioritymessagequeue.cc +++ b/rts/umlrt/umlrtprioritymessagequeue.cc
@@ -22,6 +22,7 @@ #include <stdio.h> #include <fcntl.h> #include <sys/ioctl.h> +#include <sys/socket.h> // See umlrtprioritymessagequeue.hh for documentation.
diff --git a/rts/umlrt/umlrttimerqueue.cc b/rts/umlrt/umlrttimerqueue.cc index 1160758..1d04bc0 100644 --- a/rts/umlrt/umlrttimerqueue.cc +++ b/rts/umlrt/umlrttimerqueue.cc
@@ -18,6 +18,7 @@ #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> +#include <sys/socket.h> // See umlrttimerqueue.hh for documentation.