>> However, I do not know if we can have additional threads at all in a >> Win32 process without confusing the win32 processes, or if this needs >> to be solved differently (APC?). >> > > A previous version of my patch used NtTimer/APC: >
I'm attaching a cleaned up version of my APC code. It does get called regularly: 000f:fixme:thread:update_shared_data_time 129768277137647820 0041:fixme:win:GetWindowPlacement not supported on other process window 0x90076 0036:fixme:d3d:query_init Unhandled query type 0xc. 000f:fixme:thread:update_shared_data_time 129768277137814980 Though the interval is not exactly 15.600 ms, as it is with a separate thread and nanosleep. And most importantly, it does not allow SW:TOR to make it to the character selection screen. Could I have initialized the timer with different values to make it more precise? thanks, Joey
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index e328c5f..a4cbdc3 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -23,6 +23,7 @@ #include <assert.h> #include <stdarg.h> +#include <stdint.h> #include <sys/types.h> #ifdef HAVE_SYS_MMAN_H #include <sys/mman.h> @@ -67,6 +68,103 @@ static RTL_BITMAP fls_bitmap; static LIST_ENTRY tls_links; static int nb_threads = 1; +static void CALLBACK shared_data_timer_apc(void* TimerContext, uint32_t TimerLowValue, int32_t TimerHighValue); +static HANDLE create_shared_data_timer(void); +static NTSTATUS set_shared_data_timer(HANDLE handle); + +static void update_shared_data_time(void) +{ + LARGE_INTEGER now, start, irq; + + NtQuerySystemTime( &now ); + + FIXME("%lld\n", now.QuadPart); + + 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 CALLBACK shared_data_timer_apc(void* ctx, uint32_t low, int32_t high) +{ + update_shared_data_time(); + set_shared_data_timer((HANDLE)ctx); +} + +static HANDLE create_shared_data_timer(void) +{ + HANDLE handle; + NTSTATUS status; + OBJECT_ATTRIBUTES attr; + + //FIXME("enter\n"); + + attr.Length = sizeof(attr); + attr.RootDirectory = 0; + attr.ObjectName = NULL; + attr.Attributes = OBJ_OPENIF; + attr.SecurityDescriptor = NULL; + attr.SecurityQualityOfService = NULL; + + status = NtCreateTimer( &handle, TIMER_ALL_ACCESS, &attr, NotificationTimer); + + if (status == STATUS_OBJECT_NAME_EXISTS) + SetLastError( ERROR_ALREADY_EXISTS ); + else + SetLastError( RtlNtStatusToDosError(status) ); + + return handle; +} + +static NTSTATUS set_shared_data_timer(HANDLE handle) +{ + LARGE_INTEGER when; + NTSTATUS status; + + //FIXME("enter\n"); + + NtQuerySystemTime( &when ); + when.QuadPart += 156000; + + status = NtSetTimer(handle, &when, (PTIMER_APC_ROUTINE)shared_data_timer_apc, handle, 0, 0, NULL); + if (status != STATUS_SUCCESS) + { + SetLastError( RtlNtStatusToDosError(status) ); + } + + return status; +} + + +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 +294,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 +387,24 @@ 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(); + HANDLE timer = create_shared_data_timer(); + set_shared_data_timer(timer); + + /* + 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; }