Change clock source to CLOCK_MONOTONIC in 'pthread_cond_timedwait'
authorpowerctrl <jaymin.1328@gmail.com>
Wed, 26 Oct 2016 15:43:29 +0000 (21:13 +0530)
committerLudovic Henry <ludovic@xamarin.com>
Thu, 2 Mar 2017 19:20:27 +0000 (14:20 -0500)
commitf9e87491df2a7ead48790a36170556c4fde6cebe
tree6167460733fa423b5639a4e0ee9b4906cb6d0764
parenteec02ff9365a824a5db49138bccdf4ea93919308
Change clock source to CLOCK_MONOTONIC in 'pthread_cond_timedwait'

 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 <sudo date -s "Wed Oct 26 20:25:24 IST 2016"> 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);
}
}

This updates and merge https://github.com/mono/mono/pull/3828
mono/utils/mono-os-mutex.h