Hi everybody,

As originally discovered by Carsten Juttner, Star Wars: The Old Republic
uses the time values in KUSER_SHARED_DATA to trigger network send
buffers.  wine does not currently update these values, so TOR does not
make it past an initial server handshake.

I'm attaching my current patch which fixes this.  It updates the values
every 15600000 nanoseconds as does Windows 7, and presumably all Windows
versions.  The words of the timers are written in the correct order for
applications to detect clock tick.

It uses a separate thread which does nothing else; a previous attempt at
an NtTimer based solution did not work, presumably due to irregularity
in the exact callback times.  Attempts at setting thread priority were
also abandoned after many people were unable to run the code.

The patch does not check the return code of nanosleep; I could add code
to nanosleep again for the remaining time in the case of an interrupt,
but didn't think it was necessary.  I could also change it to use
clock_nanosleep, which would allow for more absolute timing.

Please let me know what you think.

cheers,

Joey
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index e328c5f..e9fdd43 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -67,6 +67,48 @@ static RTL_BITMAP fls_bitmap;
 static LIST_ENTRY tls_links;
 static int nb_threads = 1;
 
+static void update_shared_data_time(void)
+{
+    LARGE_INTEGER now, start, irq;
+
+    NtQuerySystemTime( &now );
+
+    irq.QuadPart = (now.QuadPart - server_start_time);
+
+    user_shared_data->InterruptTime.High2Time = irq.HighPart;
+    user_shared_data->InterruptTime.LowPart = irq.LowPart;
+    user_shared_data->InterruptTime.High1Time = irq.HighPart;
+
+    user_shared_data->SystemTime.High2Time = now.HighPart;
+    user_shared_data->SystemTime.LowPart = now.LowPart;
+    user_shared_data->SystemTime.High1Time = now.HighPart;
+
+    start.QuadPart = irq.QuadPart / 10000;
+
+    user_shared_data->u.TickCount.High2Time = start.HighPart;
+    user_shared_data->u.TickCount.LowPart = start.LowPart;
+    user_shared_data->u.TickCount.High1Time = start.HighPart;
+    user_shared_data->TickCountLowDeprecated = start.LowPart;
+}
+
+
+
+static void* shared_data_thread(void *arg) 
+{
+    struct timespec req, rem;
+
+    req.tv_sec = 0;
+    req.tv_nsec = 15600000;
+
+    while(1) {
+        update_shared_data_time();
+        nanosleep(&req, &rem);
+    }
+
+    return NULL;
+}
+
+
 /***********************************************************************
  *           get_unicode_string
  *
@@ -196,9 +238,10 @@ HANDLE thread_init(void)
     void *addr;
     SIZE_T size, info_size;
     HANDLE exe_file = 0;
-    LARGE_INTEGER now;
     struct ntdll_thread_data *thread_data;
     static struct debug_info debug_info;  /* debug info for initial thread */
+    pthread_t thread;
+    int s;
 
     virtual_init();
 
@@ -288,16 +331,19 @@ HANDLE thread_init(void)
     }
 
     /* initialize time values in user_shared_data */
-    NtQuerySystemTime( &now );
-    user_shared_data->SystemTime.LowPart = now.u.LowPart;
-    user_shared_data->SystemTime.High1Time = user_shared_data->SystemTime.High2Time = now.u.HighPart;
-    user_shared_data->u.TickCountQuad = (now.QuadPart - server_start_time) / 10000;
-    user_shared_data->u.TickCount.High2Time = user_shared_data->u.TickCount.High1Time;
-    user_shared_data->TickCountLowDeprecated = user_shared_data->u.TickCount.LowPart;
     user_shared_data->TickCountMultiplier = 1 << 24;
 
+    update_shared_data_time();
+
     fill_cpu_info();
 
+    if(!(s = pthread_create(&thread, NULL, &shared_data_thread, NULL))) {
+        if(pthread_detach(thread))
+            FIXME("Unable to detach thread\n");
+    } else {
+        FIXME("unable to spawn thread: %s (%d)\n", strerror(s), s);
+    }
+
     return exe_file;
 }
 


Reply via email to