ntdll: Add some more tests for NtNotifyChangeDirectoryFile.
[wine] / dlls / ntdll / thread.c
1 /*
2  * NT threads support
3  *
4  * Copyright 1996, 2003 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <sys/types.h>
25 #ifdef HAVE_SYS_MMAN_H
26 #include <sys/mman.h>
27 #endif
28 #ifdef HAVE_SYS_TIMES_H
29 #include <sys/times.h>
30 #endif
31
32 #define NONAMELESSUNION
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "thread.h"
36 #include "winternl.h"
37 #include "wine/library.h"
38 #include "wine/server.h"
39 #include "wine/pthread.h"
40 #include "wine/debug.h"
41 #include "ntdll_misc.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(thread);
44
45 /* info passed to a starting thread */
46 struct startup_info
47 {
48     struct wine_pthread_thread_info pthread_info;
49     PRTL_THREAD_START_ROUTINE       entry_point;
50     void                           *entry_arg;
51 };
52
53 static PEB peb;
54 static PEB_LDR_DATA ldr;
55 static RTL_USER_PROCESS_PARAMETERS params;  /* default parameters if no parent */
56 static WCHAR current_dir[MAX_NT_PATH_LENGTH];
57 static RTL_BITMAP tls_bitmap;
58 static RTL_BITMAP tls_expansion_bitmap;
59 static LIST_ENTRY tls_links;
60 static size_t sigstack_total_size;
61
62 struct wine_pthread_functions pthread_functions = { NULL };
63
64 /***********************************************************************
65  *           init_teb
66  */
67 static inline NTSTATUS init_teb( TEB *teb )
68 {
69     struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
70     struct ntdll_thread_regs *thread_regs = (struct ntdll_thread_regs *)teb->SpareBytes1;
71
72     teb->Tib.ExceptionList = (void *)~0UL;
73     teb->Tib.StackBase     = (void *)~0UL;
74     teb->Tib.Self          = &teb->Tib;
75     teb->Peb               = &peb;
76     teb->StaticUnicodeString.Buffer        = teb->StaticUnicodeBuffer;
77     teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
78
79     if (!(thread_regs->fs = wine_ldt_alloc_fs())) return STATUS_TOO_MANY_THREADS;
80     thread_data->request_fd = -1;
81     thread_data->reply_fd   = -1;
82     thread_data->wait_fd[0] = -1;
83     thread_data->wait_fd[1] = -1;
84
85     return STATUS_SUCCESS;
86 }
87
88
89 /***********************************************************************
90  *           free_teb
91  */
92 static inline void free_teb( TEB *teb )
93 {
94     SIZE_T size = 0;
95     void *addr = teb;
96     struct ntdll_thread_regs *thread_regs = (struct ntdll_thread_regs *)teb->SpareBytes1;
97
98     NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE );
99     wine_ldt_free_fs( thread_regs->fs );
100     munmap( teb, sigstack_total_size );
101 }
102
103
104 /***********************************************************************
105  *           thread_init
106  *
107  * Setup the initial thread.
108  *
109  * NOTES: The first allocated TEB on NT is at 0x7ffde000.
110  */
111 void thread_init(void)
112 {
113     TEB *teb;
114     void *addr;
115     SIZE_T info_size;
116     struct ntdll_thread_data *thread_data;
117     struct ntdll_thread_regs *thread_regs;
118     struct wine_pthread_thread_info thread_info;
119     static struct debug_info debug_info;  /* debug info for initial thread */
120
121     peb.NumberOfProcessors = 1;
122     peb.ProcessParameters  = &params;
123     peb.TlsBitmap          = &tls_bitmap;
124     peb.TlsExpansionBitmap = &tls_expansion_bitmap;
125     peb.LdrData            = &ldr;
126     params.CurrentDirectory.DosPath.Buffer = current_dir;
127     params.CurrentDirectory.DosPath.MaximumLength = sizeof(current_dir);
128     params.wShowWindow = 1; /* SW_SHOWNORMAL */
129     RtlInitializeBitMap( &tls_bitmap, peb.TlsBitmapBits, sizeof(peb.TlsBitmapBits) * 8 );
130     RtlInitializeBitMap( &tls_expansion_bitmap, peb.TlsExpansionBitmapBits,
131                          sizeof(peb.TlsExpansionBitmapBits) * 8 );
132     InitializeListHead( &ldr.InLoadOrderModuleList );
133     InitializeListHead( &ldr.InMemoryOrderModuleList );
134     InitializeListHead( &ldr.InInitializationOrderModuleList );
135     InitializeListHead( &tls_links );
136
137     sigstack_total_size = get_signal_stack_total_size();
138     thread_info.teb_size = sigstack_total_size;
139     VIRTUAL_alloc_teb( &addr, thread_info.teb_size, TRUE );
140     teb = addr;
141     init_teb( teb );
142     thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
143     thread_regs = (struct ntdll_thread_regs *)teb->SpareBytes1;
144     thread_data->debug_info = &debug_info;
145     InsertHeadList( &tls_links, &teb->TlsLinks );
146
147     thread_info.stack_base = NULL;
148     thread_info.stack_size = 0;
149     thread_info.teb_base   = teb;
150     thread_info.teb_sel    = thread_regs->fs;
151     wine_pthread_get_functions( &pthread_functions, sizeof(pthread_functions) );
152     pthread_functions.init_current_teb( &thread_info );
153     pthread_functions.init_thread( &thread_info );
154
155     debug_info.str_pos = debug_info.strings;
156     debug_info.out_pos = debug_info.output;
157     debug_init();
158
159     /* setup the server connection */
160     server_init_process();
161     info_size = server_init_thread( thread_info.pid, thread_info.tid, NULL );
162
163     /* create the process heap */
164     if (!(peb.ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL )))
165     {
166         MESSAGE( "wine: failed to create the process heap\n" );
167         exit(1);
168     }
169
170     /* allocate user parameters */
171     if (info_size)
172     {
173         RTL_USER_PROCESS_PARAMETERS *params = NULL;
174
175         if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&params, 0, &info_size,
176                                      MEM_COMMIT, PAGE_READWRITE ) == STATUS_SUCCESS)
177         {
178             params->AllocationSize = info_size;
179             NtCurrentTeb()->Peb->ProcessParameters = params;
180         }
181     }
182     else
183     {
184         /* This is wine specific: we have no parent (we're started from unix)
185          * so, create a simple console with bare handles to unix stdio
186          */
187         wine_server_fd_to_handle( 0, GENERIC_READ|SYNCHRONIZE,  OBJ_INHERIT, &params.hStdInput );
188         wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, &params.hStdOutput );
189         wine_server_fd_to_handle( 2, GENERIC_WRITE|SYNCHRONIZE, OBJ_INHERIT, &params.hStdError );
190     }
191 }
192
193
194 /***********************************************************************
195  *           start_thread
196  *
197  * Startup routine for a newly created thread.
198  */
199 static void start_thread( struct wine_pthread_thread_info *info )
200 {
201     TEB *teb = info->teb_base;
202     struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
203     struct startup_info *startup_info = (struct startup_info *)info;
204     PRTL_THREAD_START_ROUTINE func = startup_info->entry_point;
205     void *arg = startup_info->entry_arg;
206     struct debug_info debug_info;
207     SIZE_T size, page_size = getpagesize();
208
209     debug_info.str_pos = debug_info.strings;
210     debug_info.out_pos = debug_info.output;
211     thread_data->debug_info = &debug_info;
212
213     pthread_functions.init_current_teb( info );
214     SIGNAL_Init();
215     server_init_thread( info->pid, info->tid, func );
216     pthread_functions.init_thread( info );
217
218     /* allocate a memory view for the stack */
219     size = info->stack_size;
220     teb->DeallocationStack = info->stack_base;
221     NtAllocateVirtualMemory( NtCurrentProcess(), &teb->DeallocationStack, 0,
222                              &size, MEM_SYSTEM, PAGE_READWRITE );
223     /* limit is lower than base since the stack grows down */
224     teb->Tib.StackBase  = (char *)info->stack_base + info->stack_size;
225     teb->Tib.StackLimit = (char *)info->stack_base + page_size;
226
227     /* setup the guard page */
228     size = page_size;
229     NtProtectVirtualMemory( NtCurrentProcess(), &teb->DeallocationStack, &size, PAGE_NOACCESS, NULL );
230     RtlFreeHeap( GetProcessHeap(), 0, info );
231
232     RtlAcquirePebLock();
233     InsertHeadList( &tls_links, &teb->TlsLinks );
234     RtlReleasePebLock();
235
236     func( arg );
237 }
238
239
240 /***********************************************************************
241  *              RtlCreateUserThread   (NTDLL.@)
242  */
243 NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *descr,
244                                      BOOLEAN suspended, PVOID stack_addr,
245                                      SIZE_T stack_reserve, SIZE_T stack_commit,
246                                      PRTL_THREAD_START_ROUTINE start, void *param,
247                                      HANDLE *handle_ptr, CLIENT_ID *id )
248 {
249     struct ntdll_thread_data *thread_data;
250     struct ntdll_thread_regs *thread_regs = NULL;
251     struct startup_info *info = NULL;
252     void *addr;
253     HANDLE handle = 0;
254     TEB *teb;
255     DWORD tid = 0;
256     int request_pipe[2];
257     NTSTATUS status;
258     SIZE_T page_size = getpagesize();
259
260     if( ! is_current_process( process ) )
261     {
262         ERR("Unsupported on other process\n");
263         return STATUS_ACCESS_DENIED;
264     }
265
266     if (pipe( request_pipe ) == -1) return STATUS_TOO_MANY_OPENED_FILES;
267     fcntl( request_pipe[1], F_SETFD, 1 ); /* set close on exec flag */
268     wine_server_send_fd( request_pipe[0] );
269
270     SERVER_START_REQ( new_thread )
271     {
272         req->access     = THREAD_ALL_ACCESS;
273         req->attributes = 0;  /* FIXME */
274         req->suspend    = suspended;
275         req->request_fd = request_pipe[0];
276         if (!(status = wine_server_call( req )))
277         {
278             handle = reply->handle;
279             tid = reply->tid;
280         }
281         close( request_pipe[0] );
282     }
283     SERVER_END_REQ;
284
285     if (status) goto error;
286
287     if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) )))
288     {
289         status = STATUS_NO_MEMORY;
290         goto error;
291     }
292
293     info->pthread_info.teb_size = sigstack_total_size;
294     if ((status = VIRTUAL_alloc_teb( &addr, info->pthread_info.teb_size, FALSE ))) goto error;
295     teb = addr;
296     if ((status = init_teb( teb ))) goto error;
297
298     teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId();
299     teb->ClientId.UniqueThread  = (HANDLE)tid;
300
301     thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
302     thread_regs = (struct ntdll_thread_regs *)teb->SpareBytes1;
303     thread_data->request_fd  = request_pipe[1];
304
305     info->pthread_info.teb_base = teb;
306     info->pthread_info.teb_sel  = thread_regs->fs;
307
308     /* inherit debug registers from parent thread */
309     thread_regs->dr0 = ntdll_get_thread_regs()->dr0;
310     thread_regs->dr1 = ntdll_get_thread_regs()->dr1;
311     thread_regs->dr2 = ntdll_get_thread_regs()->dr2;
312     thread_regs->dr3 = ntdll_get_thread_regs()->dr3;
313     thread_regs->dr6 = ntdll_get_thread_regs()->dr6;
314     thread_regs->dr7 = ntdll_get_thread_regs()->dr7;
315
316     if (!stack_reserve || !stack_commit)
317     {
318         IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
319         if (!stack_reserve) stack_reserve = nt->OptionalHeader.SizeOfStackReserve;
320         if (!stack_commit) stack_commit = nt->OptionalHeader.SizeOfStackCommit;
321     }
322     if (stack_reserve < stack_commit) stack_reserve = stack_commit;
323     stack_reserve += page_size;  /* for the guard page */
324     stack_reserve = (stack_reserve + 0xffff) & ~0xffff;  /* round to 64K boundary */
325     if (stack_reserve < 1024 * 1024) stack_reserve = 1024 * 1024;  /* Xlib needs a large stack */
326
327     info->pthread_info.stack_base = NULL;
328     info->pthread_info.stack_size = stack_reserve;
329     info->pthread_info.entry      = start_thread;
330     info->entry_point             = start;
331     info->entry_arg               = param;
332
333     if (pthread_functions.create_thread( &info->pthread_info ) == -1)
334     {
335         status = STATUS_NO_MEMORY;
336         goto error;
337     }
338
339     if (id) id->UniqueThread = (HANDLE)tid;
340     if (handle_ptr) *handle_ptr = handle;
341     else NtClose( handle );
342
343     return STATUS_SUCCESS;
344
345 error:
346     if (thread_regs) wine_ldt_free_fs( thread_regs->fs );
347     if (addr)
348     {
349         SIZE_T size = 0;
350         NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE );
351     }
352     if (info) RtlFreeHeap( GetProcessHeap(), 0, info );
353     if (handle) NtClose( handle );
354     close( request_pipe[1] );
355     return status;
356 }
357
358
359 /***********************************************************************
360  *           RtlExitUserThread  (NTDLL.@)
361  */
362 void WINAPI RtlExitUserThread( ULONG status )
363 {
364     LdrShutdownThread();
365     server_exit_thread( status );
366 }
367
368
369 /***********************************************************************
370  *              NtOpenThread   (NTDLL.@)
371  *              ZwOpenThread   (NTDLL.@)
372  */
373 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
374                               const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
375 {
376     NTSTATUS ret;
377
378     SERVER_START_REQ( open_thread )
379     {
380         req->tid        = (thread_id_t)id->UniqueThread;
381         req->access     = access;
382         req->attributes = attr ? attr->Attributes : 0;
383         ret = wine_server_call( req );
384         *handle = reply->handle;
385     }
386     SERVER_END_REQ;
387     return ret;
388 }
389
390
391 /******************************************************************************
392  *              NtSuspendThread   (NTDLL.@)
393  *              ZwSuspendThread   (NTDLL.@)
394  */
395 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, PULONG count )
396 {
397     NTSTATUS ret;
398
399     SERVER_START_REQ( suspend_thread )
400     {
401         req->handle = handle;
402         if (!(ret = wine_server_call( req ))) *count = reply->count;
403     }
404     SERVER_END_REQ;
405     return ret;
406 }
407
408
409 /******************************************************************************
410  *              NtResumeThread   (NTDLL.@)
411  *              ZwResumeThread   (NTDLL.@)
412  */
413 NTSTATUS WINAPI NtResumeThread( HANDLE handle, PULONG count )
414 {
415     NTSTATUS ret;
416
417     SERVER_START_REQ( resume_thread )
418     {
419         req->handle = handle;
420         if (!(ret = wine_server_call( req ))) *count = reply->count;
421     }
422     SERVER_END_REQ;
423     return ret;
424 }
425
426
427 /******************************************************************************
428  *              NtAlertResumeThread   (NTDLL.@)
429  *              ZwAlertResumeThread   (NTDLL.@)
430  */
431 NTSTATUS WINAPI NtAlertResumeThread( HANDLE handle, PULONG count )
432 {
433     FIXME( "stub: should alert thread %p\n", handle );
434     return NtResumeThread( handle, count );
435 }
436
437
438 /******************************************************************************
439  *              NtAlertThread   (NTDLL.@)
440  *              ZwAlertThread   (NTDLL.@)
441  */
442 NTSTATUS WINAPI NtAlertThread( HANDLE handle )
443 {
444     FIXME( "stub: %p\n", handle );
445     return STATUS_NOT_IMPLEMENTED;
446 }
447
448
449 /******************************************************************************
450  *              NtTerminateThread  (NTDLL.@)
451  *              ZwTerminateThread  (NTDLL.@)
452  */
453 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
454 {
455     NTSTATUS ret;
456     BOOL self, last;
457
458     SERVER_START_REQ( terminate_thread )
459     {
460         req->handle    = handle;
461         req->exit_code = exit_code;
462         ret = wine_server_call( req );
463         self = !ret && reply->self;
464         last = reply->last;
465     }
466     SERVER_END_REQ;
467
468     if (self)
469     {
470         if (last) exit( exit_code );
471         else server_abort_thread( exit_code );
472     }
473     return ret;
474 }
475
476
477 /******************************************************************************
478  *              NtQueueApcThread  (NTDLL.@)
479  */
480 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
481                                   ULONG_PTR arg2, ULONG_PTR arg3 )
482 {
483     NTSTATUS ret;
484     SERVER_START_REQ( queue_apc )
485     {
486         req->handle = handle;
487         req->user   = 1;
488         req->func   = func;
489         req->arg1   = (void *)arg1;
490         req->arg2   = (void *)arg2;
491         req->arg3   = (void *)arg3;
492         ret = wine_server_call( req );
493     }
494     SERVER_END_REQ;
495     return ret;
496 }
497
498
499 /***********************************************************************
500  *              NtSetContextThread  (NTDLL.@)
501  *              ZwSetContextThread  (NTDLL.@)
502  */
503 NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
504 {
505     NTSTATUS ret;
506     DWORD dummy, i;
507     BOOL self = FALSE;
508
509 #ifdef __i386__
510     /* on i386 debug registers always require a server call */
511     self = (handle == GetCurrentThread());
512     if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)))
513     {
514         struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
515         self = (regs->dr0 == context->Dr0 && regs->dr1 == context->Dr1 &&
516                 regs->dr2 == context->Dr2 && regs->dr3 == context->Dr3 &&
517                 regs->dr6 == context->Dr6 && regs->dr7 == context->Dr7);
518     }
519 #endif
520
521     if (!self)
522     {
523         SERVER_START_REQ( set_thread_context )
524         {
525             req->handle  = handle;
526             req->flags   = context->ContextFlags;
527             req->suspend = 0;
528             wine_server_add_data( req, context, sizeof(*context) );
529             ret = wine_server_call( req );
530             self = reply->self;
531         }
532         SERVER_END_REQ;
533
534         if (ret == STATUS_PENDING)
535         {
536             if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
537             {
538                 for (i = 0; i < 100; i++)
539                 {
540                     SERVER_START_REQ( set_thread_context )
541                     {
542                         req->handle  = handle;
543                         req->flags   = context->ContextFlags;
544                         req->suspend = 0;
545                         wine_server_add_data( req, context, sizeof(*context) );
546                         ret = wine_server_call( req );
547                     }
548                     SERVER_END_REQ;
549                     if (ret != STATUS_PENDING) break;
550                     NtYieldExecution();
551                 }
552                 NtResumeThread( handle, &dummy );
553             }
554             if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
555         }
556
557         if (ret) return ret;
558     }
559
560     if (self) set_cpu_context( context );
561     return STATUS_SUCCESS;
562 }
563
564
565 /* copy a context structure according to the flags */
566 static inline void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
567 {
568 #ifdef __i386__
569     flags &= ~CONTEXT_i386;  /* get rid of CPU id */
570     if (flags & CONTEXT_INTEGER)
571     {
572         to->Eax = from->Eax;
573         to->Ebx = from->Ebx;
574         to->Ecx = from->Ecx;
575         to->Edx = from->Edx;
576         to->Esi = from->Esi;
577         to->Edi = from->Edi;
578     }
579     if (flags & CONTEXT_CONTROL)
580     {
581         to->Ebp    = from->Ebp;
582         to->Esp    = from->Esp;
583         to->Eip    = from->Eip;
584         to->SegCs  = from->SegCs;
585         to->SegSs  = from->SegSs;
586         to->EFlags = from->EFlags;
587     }
588     if (flags & CONTEXT_SEGMENTS)
589     {
590         to->SegDs = from->SegDs;
591         to->SegEs = from->SegEs;
592         to->SegFs = from->SegFs;
593         to->SegGs = from->SegGs;
594     }
595     if (flags & CONTEXT_DEBUG_REGISTERS)
596     {
597         to->Dr0 = from->Dr0;
598         to->Dr1 = from->Dr1;
599         to->Dr2 = from->Dr2;
600         to->Dr3 = from->Dr3;
601         to->Dr6 = from->Dr6;
602         to->Dr7 = from->Dr7;
603     }
604     if (flags & CONTEXT_FLOATING_POINT)
605     {
606         to->FloatSave = from->FloatSave;
607     }
608 #elif defined(__x86_64__)
609     flags &= ~CONTEXT_AMD64;  /* get rid of CPU id */
610     if (flags & CONTEXT_CONTROL)
611     {
612         to->Rbp    = from->Rbp;
613         to->Rip    = from->Rip;
614         to->Rsp    = from->Rsp;
615         to->SegCs  = from->SegCs;
616         to->SegSs  = from->SegSs;
617         to->EFlags = from->EFlags;
618         to->MxCsr  = from->MxCsr;
619     }
620     if (flags & CONTEXT_INTEGER)
621     {
622         to->Rax = from->Rax;
623         to->Rcx = from->Rcx;
624         to->Rdx = from->Rdx;
625         to->Rbx = from->Rbx;
626         to->Rsi = from->Rsi;
627         to->Rdi = from->Rdi;
628         to->R8  = from->R8;
629         to->R9  = from->R9;
630         to->R10 = from->R10;
631         to->R11 = from->R11;
632         to->R12 = from->R12;
633         to->R13 = from->R13;
634         to->R14 = from->R14;
635         to->R15 = from->R15;
636     }
637     if (flags & CONTEXT_SEGMENTS)
638     {
639         to->SegDs = from->SegDs;
640         to->SegEs = from->SegEs;
641         to->SegFs = from->SegFs;
642         to->SegGs = from->SegGs;
643     }
644     if (flags & CONTEXT_FLOATING_POINT)
645     {
646         to->u.FltSave = from->u.FltSave;
647     }
648     if (flags & CONTEXT_DEBUG_REGISTERS)
649     {
650         to->Dr0 = from->Dr0;
651         to->Dr1 = from->Dr1;
652         to->Dr2 = from->Dr2;
653         to->Dr3 = from->Dr3;
654         to->Dr6 = from->Dr6;
655         to->Dr7 = from->Dr7;
656     }
657 #elif defined(__sparc__)
658     flags &= ~CONTEXT_SPARC;  /* get rid of CPU id */
659     if (flags & CONTEXT_CONTROL)
660     {
661         to->psr = from->psr;
662         to->pc  = from->pc;
663         to->npc = from->npc;
664         to->y   = from->y;
665         to->wim = from->wim;
666         to->tbr = from->tbr;
667     }
668     if (flags & CONTEXT_INTEGER)
669     {
670         to->g0 = from->g0;
671         to->g1 = from->g1;
672         to->g2 = from->g2;
673         to->g3 = from->g3;
674         to->g4 = from->g4;
675         to->g5 = from->g5;
676         to->g6 = from->g6;
677         to->g7 = from->g7;
678         to->o0 = from->o0;
679         to->o1 = from->o1;
680         to->o2 = from->o2;
681         to->o3 = from->o3;
682         to->o4 = from->o4;
683         to->o5 = from->o5;
684         to->o6 = from->o6;
685         to->o7 = from->o7;
686         to->l0 = from->l0;
687         to->l1 = from->l1;
688         to->l2 = from->l2;
689         to->l3 = from->l3;
690         to->l4 = from->l4;
691         to->l5 = from->l5;
692         to->l6 = from->l6;
693         to->l7 = from->l7;
694         to->i0 = from->i0;
695         to->i1 = from->i1;
696         to->i2 = from->i2;
697         to->i3 = from->i3;
698         to->i4 = from->i4;
699         to->i5 = from->i5;
700         to->i6 = from->i6;
701         to->i7 = from->i7;
702     }
703     if (flags & CONTEXT_FLOATING_POINT)
704     {
705         /* FIXME */
706     }
707 #elif defined(__powerpc__)
708     /* Has no CPU id */
709     if (flags & CONTEXT_CONTROL)
710     {
711         to->Msr = from->Msr;
712         to->Ctr = from->Ctr;
713         to->Iar = from->Iar;
714     }
715     if (flags & CONTEXT_INTEGER)
716     {
717         to->Gpr0  = from->Gpr0;
718         to->Gpr1  = from->Gpr1;
719         to->Gpr2  = from->Gpr2;
720         to->Gpr3  = from->Gpr3;
721         to->Gpr4  = from->Gpr4;
722         to->Gpr5  = from->Gpr5;
723         to->Gpr6  = from->Gpr6;
724         to->Gpr7  = from->Gpr7;
725         to->Gpr8  = from->Gpr8;
726         to->Gpr9  = from->Gpr9;
727         to->Gpr10 = from->Gpr10;
728         to->Gpr11 = from->Gpr11;
729         to->Gpr12 = from->Gpr12;
730         to->Gpr13 = from->Gpr13;
731         to->Gpr14 = from->Gpr14;
732         to->Gpr15 = from->Gpr15;
733         to->Gpr16 = from->Gpr16;
734         to->Gpr17 = from->Gpr17;
735         to->Gpr18 = from->Gpr18;
736         to->Gpr19 = from->Gpr19;
737         to->Gpr20 = from->Gpr20;
738         to->Gpr21 = from->Gpr21;
739         to->Gpr22 = from->Gpr22;
740         to->Gpr23 = from->Gpr23;
741         to->Gpr24 = from->Gpr24;
742         to->Gpr25 = from->Gpr25;
743         to->Gpr26 = from->Gpr26;
744         to->Gpr27 = from->Gpr27;
745         to->Gpr28 = from->Gpr28;
746         to->Gpr29 = from->Gpr29;
747         to->Gpr30 = from->Gpr30;
748         to->Gpr31 = from->Gpr31;
749         to->Xer   = from->Xer;
750         to->Cr    = from->Cr;
751     }
752     if (flags & CONTEXT_FLOATING_POINT)
753     {
754         to->Fpr0  = from->Fpr0;
755         to->Fpr1  = from->Fpr1;
756         to->Fpr2  = from->Fpr2;
757         to->Fpr3  = from->Fpr3;
758         to->Fpr4  = from->Fpr4;
759         to->Fpr5  = from->Fpr5;
760         to->Fpr6  = from->Fpr6;
761         to->Fpr7  = from->Fpr7;
762         to->Fpr8  = from->Fpr8;
763         to->Fpr9  = from->Fpr9;
764         to->Fpr10 = from->Fpr10;
765         to->Fpr11 = from->Fpr11;
766         to->Fpr12 = from->Fpr12;
767         to->Fpr13 = from->Fpr13;
768         to->Fpr14 = from->Fpr14;
769         to->Fpr15 = from->Fpr15;
770         to->Fpr16 = from->Fpr16;
771         to->Fpr17 = from->Fpr17;
772         to->Fpr18 = from->Fpr18;
773         to->Fpr19 = from->Fpr19;
774         to->Fpr20 = from->Fpr20;
775         to->Fpr21 = from->Fpr21;
776         to->Fpr22 = from->Fpr22;
777         to->Fpr23 = from->Fpr23;
778         to->Fpr24 = from->Fpr24;
779         to->Fpr25 = from->Fpr25;
780         to->Fpr26 = from->Fpr26;
781         to->Fpr27 = from->Fpr27;
782         to->Fpr28 = from->Fpr28;
783         to->Fpr29 = from->Fpr29;
784         to->Fpr30 = from->Fpr30;
785         to->Fpr31 = from->Fpr31;
786         to->Fpscr = from->Fpscr;
787     }
788 #else
789 #error You must implement context copying for your CPU
790 #endif
791 }
792
793
794 /***********************************************************************
795  *              NtGetContextThread  (NTDLL.@)
796  *              ZwGetContextThread  (NTDLL.@)
797  */
798 NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
799 {
800     NTSTATUS ret;
801     CONTEXT ctx;
802     DWORD dummy, i;
803     BOOL self = FALSE;
804
805     SERVER_START_REQ( get_thread_context )
806     {
807         req->handle  = handle;
808         req->flags   = context->ContextFlags;
809         req->suspend = 0;
810         wine_server_set_reply( req, &ctx, sizeof(ctx) );
811         ret = wine_server_call( req );
812         self = reply->self;
813     }
814     SERVER_END_REQ;
815
816     if (ret == STATUS_PENDING)
817     {
818         if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
819         {
820             for (i = 0; i < 100; i++)
821             {
822                 SERVER_START_REQ( get_thread_context )
823                 {
824                     req->handle  = handle;
825                     req->flags   = context->ContextFlags;
826                     req->suspend = 0;
827                     wine_server_set_reply( req, &ctx, sizeof(ctx) );
828                     ret = wine_server_call( req );
829                 }
830                 SERVER_END_REQ;
831                 if (ret != STATUS_PENDING) break;
832                 NtYieldExecution();
833             }
834             NtResumeThread( handle, &dummy );
835         }
836     }
837
838     if (ret == STATUS_SUCCESS)
839     {
840         copy_context( context, &ctx, context->ContextFlags );
841 #ifdef __i386__
842         /* update the cached version of the debug registers */
843         if (self && (context->ContextFlags & (CONTEXT_DEBUG_REGISTERS & ~CONTEXT_i386)))
844         {
845             struct ntdll_thread_regs * const regs = ntdll_get_thread_regs();
846             regs->dr0 = context->Dr0;
847             regs->dr1 = context->Dr1;
848             regs->dr2 = context->Dr2;
849             regs->dr3 = context->Dr3;
850             regs->dr6 = context->Dr6;
851             regs->dr7 = context->Dr7;
852         }
853 #endif
854     }
855     else if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
856     return ret;
857 }
858
859
860 /******************************************************************************
861  *              NtQueryInformationThread  (NTDLL.@)
862  *              ZwQueryInformationThread  (NTDLL.@)
863  */
864 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
865                                           void *data, ULONG length, ULONG *ret_len )
866 {
867     NTSTATUS status;
868
869     switch(class)
870     {
871     case ThreadBasicInformation:
872         {
873             THREAD_BASIC_INFORMATION info;
874
875             SERVER_START_REQ( get_thread_info )
876             {
877                 req->handle = handle;
878                 req->tid_in = 0;
879                 if (!(status = wine_server_call( req )))
880                 {
881                     info.ExitStatus             = reply->exit_code;
882                     info.TebBaseAddress         = reply->teb;
883                     info.ClientId.UniqueProcess = (HANDLE)reply->pid;
884                     info.ClientId.UniqueThread  = (HANDLE)reply->tid;
885                     info.AffinityMask           = reply->affinity;
886                     info.Priority               = reply->priority;
887                     info.BasePriority           = reply->priority;  /* FIXME */
888                 }
889             }
890             SERVER_END_REQ;
891             if (status == STATUS_SUCCESS)
892             {
893                 if (data) memcpy( data, &info, min( length, sizeof(info) ));
894                 if (ret_len) *ret_len = min( length, sizeof(info) );
895             }
896         }
897         return status;
898     case ThreadTimes:
899         {
900             KERNEL_USER_TIMES   kusrt;
901             /* We need to do a server call to get the creation time or exit time */
902             /* This works on any thread */
903             SERVER_START_REQ( get_thread_info )
904             {
905                 req->handle = handle;
906                 req->tid_in = 0;
907                 status = wine_server_call( req );
908                 if (status == STATUS_SUCCESS)
909                 {
910                     RtlSecondsSince1970ToTime( reply->creation_time, &kusrt.CreateTime );
911                     RtlSecondsSince1970ToTime( reply->exit_time, &kusrt.ExitTime );
912                 }
913             }
914             SERVER_END_REQ;
915             if (status == STATUS_SUCCESS)
916             {
917                 /* We call times(2) for kernel time or user time */
918                 /* We can only (portably) do this for the current thread */
919                 if (handle == GetCurrentThread())
920                 {
921                     struct tms time_buf;
922                     long clocks_per_sec = sysconf(_SC_CLK_TCK);
923
924                     times(&time_buf);
925                     kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
926                     kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
927                 }
928                 else
929                 {
930                     kusrt.KernelTime.QuadPart = 0;
931                     kusrt.UserTime.QuadPart = 0;
932                     FIXME("Cannot get kerneltime or usertime of other threads\n");
933                 }
934                 if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
935                 if (ret_len) *ret_len = min( length, sizeof(kusrt) );
936             }
937         }
938         return status;
939     case ThreadPriority:
940     case ThreadBasePriority:
941     case ThreadAffinityMask:
942     case ThreadImpersonationToken:
943     case ThreadDescriptorTableEntry:
944     case ThreadEnableAlignmentFaultFixup:
945     case ThreadEventPair_Reusable:
946     case ThreadQuerySetWin32StartAddress:
947     case ThreadZeroTlsCell:
948     case ThreadPerformanceCount:
949     case ThreadAmILastThread:
950     case ThreadIdealProcessor:
951     case ThreadPriorityBoost:
952     case ThreadSetTlsArrayAddress:
953     case ThreadIsIoPending:
954     default:
955         FIXME( "info class %d not supported yet\n", class );
956         return STATUS_NOT_IMPLEMENTED;
957     }
958 }
959
960
961 /******************************************************************************
962  *              NtSetInformationThread  (NTDLL.@)
963  *              ZwSetInformationThread  (NTDLL.@)
964  */
965 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
966                                         LPCVOID data, ULONG length )
967 {
968     NTSTATUS status;
969     switch(class)
970     {
971     case ThreadZeroTlsCell:
972         if (handle == GetCurrentThread())
973         {
974             LIST_ENTRY *entry;
975             DWORD index;
976
977             if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
978             index = *(const DWORD *)data;
979             if (index < TLS_MINIMUM_AVAILABLE)
980             {
981                 RtlAcquirePebLock();
982                 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
983                 {
984                     TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
985                     teb->TlsSlots[index] = 0;
986                 }
987                 RtlReleasePebLock();
988             }
989             else
990             {
991                 index -= TLS_MINIMUM_AVAILABLE;
992                 if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
993                     return STATUS_INVALID_PARAMETER;
994                 RtlAcquirePebLock();
995                 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
996                 {
997                     TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
998                     if (teb->TlsExpansionSlots) teb->TlsExpansionSlots[index] = 0;
999                 }
1000                 RtlReleasePebLock();
1001             }
1002             return STATUS_SUCCESS;
1003         }
1004         FIXME( "ZeroTlsCell not supported on other threads\n" );
1005         return STATUS_NOT_IMPLEMENTED;
1006
1007     case ThreadImpersonationToken:
1008         {
1009             const HANDLE *phToken = data;
1010             if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
1011             TRACE("Setting ThreadImpersonationToken handle to %p\n", *phToken );
1012             SERVER_START_REQ( set_thread_info )
1013             {
1014                 req->handle   = handle;
1015                 req->token    = *phToken;
1016                 req->mask     = SET_THREAD_INFO_TOKEN;
1017                 status = wine_server_call( req );
1018             }
1019             SERVER_END_REQ;
1020         }
1021         return status;
1022     case ThreadBasePriority:
1023         {
1024             const DWORD *pprio = data;
1025             if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
1026             SERVER_START_REQ( set_thread_info )
1027             {
1028                 req->handle   = handle;
1029                 req->priority = *pprio;
1030                 req->mask     = SET_THREAD_INFO_PRIORITY;
1031                 status = wine_server_call( req );
1032             }
1033             SERVER_END_REQ;
1034         }
1035         return status;
1036     case ThreadAffinityMask:
1037         {
1038             const DWORD *paff = data;
1039             if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
1040             SERVER_START_REQ( set_thread_info )
1041             {
1042                 req->handle   = handle;
1043                 req->affinity = *paff;
1044                 req->mask     = SET_THREAD_INFO_AFFINITY;
1045                 status = wine_server_call( req );
1046             }
1047             SERVER_END_REQ;
1048         }
1049         return status;
1050     case ThreadBasicInformation:
1051     case ThreadTimes:
1052     case ThreadPriority:
1053     case ThreadDescriptorTableEntry:
1054     case ThreadEnableAlignmentFaultFixup:
1055     case ThreadEventPair_Reusable:
1056     case ThreadQuerySetWin32StartAddress:
1057     case ThreadPerformanceCount:
1058     case ThreadAmILastThread:
1059     case ThreadIdealProcessor:
1060     case ThreadPriorityBoost:
1061     case ThreadSetTlsArrayAddress:
1062     case ThreadIsIoPending:
1063     default:
1064         FIXME( "info class %d not supported yet\n", class );
1065         return STATUS_NOT_IMPLEMENTED;
1066     }
1067 }
1068
1069
1070 /**********************************************************************
1071  *           NtCurrentTeb   (NTDLL.@)
1072  */
1073 #if defined(__i386__) && defined(__GNUC__)
1074
1075 __ASM_GLOBAL_FUNC( NtCurrentTeb, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" );
1076
1077 #elif defined(__i386__) && defined(_MSC_VER)
1078
1079 /* Nothing needs to be done. MS C "magically" exports the inline version from winnt.h */
1080
1081 #else
1082
1083 /**********************************************************************/
1084
1085 TEB * WINAPI NtCurrentTeb(void)
1086 {
1087     return pthread_functions.get_current_teb();
1088 }
1089
1090 #endif  /* __i386__ */