From b67b22dd6148c46f19d719178d257ccf33155255 Mon Sep 17 00:00:00 2001 From: powerctrl Date: Wed, 26 Oct 2016 21:13:29 +0530 Subject: [PATCH 1/3] Update mono-os-mutex.h Wait functions for Mutex, Semaphore and Condition (like pthread_cond_timedwait) for 'task' synchronisation in Linux uses CLOCK_REALTIME by default, this creates many problems where a process changes time. e.g. Command line utility < date -s "desired date and time" > A thread may be blocked for a more\less time depending upon time change. It is always desirable to use clock source immune to such changes However, it is not possible to change clock source for mutex and semaphore wait functions in Linux. So changing it for condition only This can be seen by a simple application if you make a simple timer using System.Timers.Timer and print time stamp every regular interval say 2 seconds, now if time shifts in the system for whatever reason ( you can do this in Linux by put desired time in quotes), this print stops coming for the offset time duration. The reason behind this is the call to 'pthread_cond_timedwait' function, by Timer class which uses it to sleep for timeout duration. Now this function uses CLOCK_REALTIME which can be changed, so if you change this clock, a thread will be blocked for the unexpected time. So using CLOCK_MONOTONIC removes the error. There are many embedded systems which do not have RTC and rely upon the external time like systems using GPS or set top box. So this fix is inevitable for them, at least for condition variable wait. This is the sample code using System; using System.Timers; public class Example { private static System.Timers.Timer aTimer; public static void Main() { SetTimer(); Console.WriteLine("\nPress the Enter key to exit the application...\n"); Console.WriteLine("The application started at {0:HH:mm:ss.fff}", DateTime.Now); Console.ReadLine(); aTimer.Stop(); aTimer.Dispose(); Console.WriteLine("Terminating the application..."); } private static void SetTimer() { // Create a timer with a two second interval. aTimer = new System.Timers.Timer(2000); // Hook up the Elapsed event for the timer. //((System.ComponentModel.ISupportInitialize)(aTimer)).BeginInit(); aTimer.Elapsed += OnTimedEvent; //((System.ComponentModel.ISupportInitialize)(aTimer)).EndInit(); aTimer.AutoReset = true; aTimer.Enabled = true; } private static void OnTimedEvent(Object source, ElapsedEventArgs e) { Console.WriteLine("__The Elapsed event was raised at {0:HH:mm:ss.fff}", e.SignalTime); } } --- mono/utils/mono-os-mutex.h | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/mono/utils/mono-os-mutex.h b/mono/utils/mono-os-mutex.h index cd33375894c1d..d6b9da653a835 100644 --- a/mono/utils/mono-os-mutex.h +++ b/mono/utils/mono-os-mutex.h @@ -118,12 +118,21 @@ mono_os_mutex_unlock (mono_mutex_t *mutex) g_error ("%s: pthread_mutex_unlock failed with \"%s\" (%d)", __func__, g_strerror (res), res); } +#if !defined(PLATFORM_MACOSX) + pthread_condattr_t attr; +#endif + static inline void mono_os_cond_init (mono_cond_t *cond) { int res; - +#if !defined(PLATFORM_MACOSX) + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + res=pthread_cond_init(cond, &attr); +#else res = pthread_cond_init (cond, NULL); +#endif if (G_UNLIKELY (res != 0)) g_error ("%s: pthread_cond_init failed with \"%s\" (%d)", __func__, g_strerror (res), res); } @@ -151,22 +160,36 @@ mono_os_cond_wait (mono_cond_t *cond, mono_mutex_t *mutex) static inline int mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ms) { + +#if defined(PLATFORM_MACOSX) struct timeval tv; - struct timespec ts; gint64 usecs; +#endif + struct timespec ts; int res; - + if (timeout_ms == MONO_INFINITE_WAIT) { mono_os_cond_wait (cond, mutex); return 0; } /* ms = 10^-3, us = 10^-6, ns = 10^-9 */ - +#if !defined(PLATFORM_MACOSX) + res = clock_gettime (CLOCK_MONOTONIC, &ts); +#else res = gettimeofday (&tv, NULL); +#endif if (G_UNLIKELY (res != 0)) g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno); - + +#if !defined(PLATFORM_MACOSX) + ts.tv_sec += timeout_ms / 1000; + ts.tv_nsec = ((timeout_ms % 1000) * 1000) * 1000; + if (ts.tv_nsec >= 1000000000){ + ts.tv_nsec -= 1000000000; + ts.tv_sec ++; + } +#else tv.tv_sec += timeout_ms / 1000; usecs = tv.tv_usec + ((timeout_ms % 1000) * 1000); if (usecs >= 1000000) { @@ -175,6 +198,7 @@ mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ } ts.tv_sec = tv.tv_sec; ts.tv_nsec = usecs * 1000; +#endif res = pthread_cond_timedwait (cond, mutex, &ts); if (G_UNLIKELY (res != 0 && res != ETIMEDOUT)) From 3d8d07f35834d9a71914ccccb5bc88bba0c9ad43 Mon Sep 17 00:00:00 2001 From: powerctrl Date: Wed, 26 Oct 2016 22:08:12 +0530 Subject: [PATCH 2/3] Update mono-os-mutex.h added comments --- mono/utils/mono-os-mutex.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mono/utils/mono-os-mutex.h b/mono/utils/mono-os-mutex.h index d6b9da653a835..f9882c3f70cf1 100644 --- a/mono/utils/mono-os-mutex.h +++ b/mono/utils/mono-os-mutex.h @@ -126,6 +126,7 @@ static inline void mono_os_cond_init (mono_cond_t *cond) { int res; +/* Attach an attribute having CLOCK_MONOTONIC to condition */ #if !defined(PLATFORM_MACOSX) pthread_condattr_init(&attr); pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); @@ -175,8 +176,10 @@ mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ /* ms = 10^-3, us = 10^-6, ns = 10^-9 */ #if !defined(PLATFORM_MACOSX) +/* cond is using CLOCK_MONOTONIC as time source */ res = clock_gettime (CLOCK_MONOTONIC, &ts); #else +/* clock_gettime is not supported in MAC OS x */ res = gettimeofday (&tv, NULL); #endif if (G_UNLIKELY (res != 0)) From 63f3576fa1e3c475c575601a839c48b793027747 Mon Sep 17 00:00:00 2001 From: Jaymin Date: Thu, 27 Oct 2016 04:49:42 +0530 Subject: [PATCH 3/3] formatting changes formatting changes and few changes made but overall logic is same, --- mono/utils/mono-os-mutex.h | 46 +++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/mono/utils/mono-os-mutex.h b/mono/utils/mono-os-mutex.h index f9882c3f70cf1..728b421a2ad04 100644 --- a/mono/utils/mono-os-mutex.h +++ b/mono/utils/mono-os-mutex.h @@ -118,24 +118,32 @@ mono_os_mutex_unlock (mono_mutex_t *mutex) g_error ("%s: pthread_mutex_unlock failed with \"%s\" (%d)", __func__, g_strerror (res), res); } -#if !defined(PLATFORM_MACOSX) - pthread_condattr_t attr; -#endif - static inline void mono_os_cond_init (mono_cond_t *cond) { int res; -/* Attach an attribute having CLOCK_MONOTONIC to condition */ -#if !defined(PLATFORM_MACOSX) - pthread_condattr_init(&attr); - pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); - res=pthread_cond_init(cond, &attr); + /* POSIX standard does not compel to have CLOCK_MONOTONIC */ +#if !defined(PLATFORM_MACOSX) && defined(CLOCK_MONOTONIC) + pthread_condattr_t attr; + + res = pthread_condattr_init (&attr); + if (G_UNLIKELY (res != 0)) + g_error ("%s: pthread_condattr_init failed with \"%s\" (%d)", __func__, g_strerror (res), res); + + res = pthread_condattr_setclock (&attr, CLOCK_MONOTONIC); + if (G_UNLIKELY (res != 0)) + g_error ("%s: pthread_condattr_setclock failed with \"%s\" (%d)", __func__, g_strerror (res), res); + /* Attach an attribute having CLOCK_MONOTONIC to condition */ + res = pthread_cond_init (cond, &attr); #else res = pthread_cond_init (cond, NULL); #endif if (G_UNLIKELY (res != 0)) g_error ("%s: pthread_cond_init failed with \"%s\" (%d)", __func__, g_strerror (res), res); + + res = pthread_condattr_destroy (&attr); + if (G_UNLIKELY (res != 0)) + g_error ("%s: pthread_condattr_destroy failed with \"%s\" (%d)", __func__, g_strerror (res), res); } static inline void @@ -168,31 +176,28 @@ mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ #endif struct timespec ts; int res; - if (timeout_ms == MONO_INFINITE_WAIT) { mono_os_cond_wait (cond, mutex); return 0; } /* ms = 10^-3, us = 10^-6, ns = 10^-9 */ -#if !defined(PLATFORM_MACOSX) -/* cond is using CLOCK_MONOTONIC as time source */ +#if !defined(PLATFORM_MACOSX) && defined(CLOCK_MONOTONIC) + /* cond is using CLOCK_MONOTONIC as time source, & give up rather than screwing if clock_gettime fails */ res = clock_gettime (CLOCK_MONOTONIC, &ts); -#else -/* clock_gettime is not supported in MAC OS x */ - res = gettimeofday (&tv, NULL); -#endif if (G_UNLIKELY (res != 0)) - g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno); - -#if !defined(PLATFORM_MACOSX) + g_error ("%s: clock_gettime failed with \"%s\" (%d)", __func__, g_strerror (errno), errno); ts.tv_sec += timeout_ms / 1000; ts.tv_nsec = ((timeout_ms % 1000) * 1000) * 1000; if (ts.tv_nsec >= 1000000000){ ts.tv_nsec -= 1000000000; ts.tv_sec ++; } -#else +#else + /* clock_gettime is not supported in MAC OS x */ + res = gettimeofday (&tv, NULL); + if (G_UNLIKELY (res != 0)) + g_error ("%s: gettimeofday failed with \"%s\" (%d)", __func__, g_strerror (errno), errno); tv.tv_sec += timeout_ms / 1000; usecs = tv.tv_usec + ((timeout_ms % 1000) * 1000); if (usecs >= 1000000) { @@ -202,7 +207,6 @@ mono_os_cond_timedwait (mono_cond_t *cond, mono_mutex_t *mutex, guint32 timeout_ ts.tv_sec = tv.tv_sec; ts.tv_nsec = usecs * 1000; #endif - res = pthread_cond_timedwait (cond, mutex, &ts); if (G_UNLIKELY (res != 0 && res != ETIMEDOUT)) g_error ("%s: pthread_cond_timedwait failed with \"%s\" (%d)", __func__, g_strerror (res), res);