Reinstate "Fix inaccurate ticks in windows port" (#1198)

Reinstates PR https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/142 that was reverted in https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/143

Co-authored-by: Ben Nicholls <benn@smartbadge.com.au>
diff --git a/portable/MSVC-MingW/port.c b/portable/MSVC-MingW/port.c
index c6ee941..9ce0c1b 100644
--- a/portable/MSVC-MingW/port.c
+++ b/portable/MSVC-MingW/port.c
@@ -141,6 +141,9 @@
 {
     TickType_t xMinimumWindowsBlockTime;
     TIMECAPS xTimeCaps;
+    TickType_t xWaitTimeBetweenTicks = portTICK_PERIOD_MS;
+    HANDLE hTimer = NULL;
+    LARGE_INTEGER liDueTime;
 
     /* Set the timer resolution to the maximum possible. */
     if( timeGetDevCaps( &xTimeCaps, sizeof( xTimeCaps ) ) == MMSYSERR_NOERROR )
@@ -160,22 +163,33 @@
     /* Just to prevent compiler warnings. */
     ( void ) lpParameter;
 
+    /* Tick time for the timer is adjusted with the maximum available
+     resolution. */
+    if( portTICK_PERIOD_MS < xMinimumWindowsBlockTime )
+    {
+        xWaitTimeBetweenTicks = xMinimumWindowsBlockTime;
+    }
+
+    /* Convert the tick time in milliseconds to nanoseconds resolution
+     for the Waitable Timer. */
+    liDueTime.u.LowPart = xWaitTimeBetweenTicks * 1000 * 1000;
+    liDueTime.u.HighPart = 0;
+
+    /* Create a synchronization Waitable Timer.*/
+    hTimer = CreateWaitableTimer( NULL, FALSE, NULL );
+
+    configASSERT( hTimer != NULL );
+
+    /* Set the Waitable Timer. The timer is set to run periodically at every
+    xWaitTimeBetweenTicks milliseconds. */
+    configASSERT( SetWaitableTimer( hTimer, &liDueTime, xWaitTimeBetweenTicks, NULL, NULL, 0 ) );
+
     while( xPortRunning == pdTRUE )
     {
         /* Wait until the timer expires and we can access the simulated interrupt
-         * variables.  *NOTE* this is not a 'real time' way of generating tick
-         * events as the next wake time should be relative to the previous wake
-         * time, not the time that Sleep() is called.  It is done this way to
-         * prevent overruns in this very non real time simulated/emulated
-         * environment. */
-        if( portTICK_PERIOD_MS < xMinimumWindowsBlockTime )
-        {
-            Sleep( xMinimumWindowsBlockTime );
-        }
-        else
-        {
-            Sleep( portTICK_PERIOD_MS );
-        }
+         * variables. */
+
+        WaitForSingleObject( hTimer, INFINITE );
 
         vPortGenerateSimulatedInterruptFromWindowsThread( portINTERRUPT_TICK );
     }