ntdll: Always allocate extra stack space for the kernel stack.
[wine.git] / dlls / ntdll / unix / thread.c
blob9859301c8acd2b711723d0c2a6834950640ee274
1 /*
2 * NT threads support
4 * Copyright 1996, 2003 Alexandre Julliard
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #if 0
22 #pragma makedep unix
23 #endif
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <errno.h>
30 #include <limits.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <pthread.h>
35 #include <signal.h>
36 #include <sys/types.h>
37 #ifdef HAVE_SYS_MMAN_H
38 #include <sys/mman.h>
39 #endif
40 #ifdef HAVE_SYS_TIMES_H
41 #include <sys/times.h>
42 #endif
43 #ifdef HAVE_SYS_SYSCALL_H
44 #include <sys/syscall.h>
45 #endif
46 #ifdef HAVE_SYS_SYSCTL_H
47 #include <sys/sysctl.h>
48 #endif
49 #ifdef HAVE_SYS_PARAM_H
50 #include <sys/param.h>
51 #endif
52 #ifdef HAVE_SYS_QUEUE_H
53 #include <sys/queue.h>
54 #endif
55 #ifdef HAVE_SYS_USER_H
56 #include <sys/user.h>
57 #endif
58 #ifdef HAVE_LIBPROCSTAT_H
59 #include <libprocstat.h>
60 #endif
62 #define NONAMELESSUNION
63 #define NONAMELESSSTRUCT
64 #include "ntstatus.h"
65 #define WIN32_NO_STATUS
66 #include "winternl.h"
67 #include "ddk/wdm.h"
68 #include "wine/server.h"
69 #include "wine/debug.h"
70 #include "wine/exception.h"
71 #include "unix_private.h"
73 WINE_DEFAULT_DEBUG_CHANNEL(thread);
74 WINE_DECLARE_DEBUG_CHANNEL(seh);
76 #ifndef PTHREAD_STACK_MIN
77 #define PTHREAD_STACK_MIN 16384
78 #endif
80 static int nb_threads = 1;
82 static inline int get_unix_exit_code( NTSTATUS status )
84 /* prevent a nonzero exit code to end up truncated to zero in unix */
85 if (status && !(status & 0xff)) return 1;
86 return status;
90 /***********************************************************************
91 * get_server_context_flags
93 static unsigned int get_server_context_flags( const void *context, USHORT machine )
95 unsigned int flags, ret = 0;
97 switch (machine)
99 case IMAGE_FILE_MACHINE_I386:
100 flags = ((const I386_CONTEXT *)context)->ContextFlags & ~CONTEXT_i386;
101 if (flags & CONTEXT_I386_CONTROL) ret |= SERVER_CTX_CONTROL;
102 if (flags & CONTEXT_I386_INTEGER) ret |= SERVER_CTX_INTEGER;
103 if (flags & CONTEXT_I386_SEGMENTS) ret |= SERVER_CTX_SEGMENTS;
104 if (flags & CONTEXT_I386_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
105 if (flags & CONTEXT_I386_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
106 if (flags & CONTEXT_I386_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS;
107 if (flags & CONTEXT_I386_XSTATE) ret |= SERVER_CTX_YMM_REGISTERS;
108 break;
109 case IMAGE_FILE_MACHINE_AMD64:
110 flags = ((const AMD64_CONTEXT *)context)->ContextFlags & ~CONTEXT_AMD64;
111 if (flags & CONTEXT_AMD64_CONTROL) ret |= SERVER_CTX_CONTROL;
112 if (flags & CONTEXT_AMD64_INTEGER) ret |= SERVER_CTX_INTEGER;
113 if (flags & CONTEXT_AMD64_SEGMENTS) ret |= SERVER_CTX_SEGMENTS;
114 if (flags & CONTEXT_AMD64_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
115 if (flags & CONTEXT_AMD64_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
116 if (flags & CONTEXT_AMD64_XSTATE) ret |= SERVER_CTX_YMM_REGISTERS;
117 break;
118 case IMAGE_FILE_MACHINE_ARMNT:
119 flags = ((const ARM_CONTEXT *)context)->ContextFlags & ~CONTEXT_ARM;
120 if (flags & CONTEXT_ARM_CONTROL) ret |= SERVER_CTX_CONTROL;
121 if (flags & CONTEXT_ARM_INTEGER) ret |= SERVER_CTX_INTEGER;
122 if (flags & CONTEXT_ARM_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
123 if (flags & CONTEXT_ARM_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
124 break;
125 case IMAGE_FILE_MACHINE_ARM64:
126 flags = ((const ARM64_NT_CONTEXT *)context)->ContextFlags & ~CONTEXT_ARM64;
127 if (flags & CONTEXT_ARM64_CONTROL) ret |= SERVER_CTX_CONTROL;
128 if (flags & CONTEXT_ARM64_INTEGER) ret |= SERVER_CTX_INTEGER;
129 if (flags & CONTEXT_ARM64_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
130 if (flags & CONTEXT_ARM64_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
131 break;
133 return ret;
137 /***********************************************************************
138 * context_to_server
140 * Convert a register context to the server format.
142 static NTSTATUS context_to_server( context_t *to, const void *src, USHORT machine )
144 DWORD i, flags;
146 memset( to, 0, sizeof(*to) );
147 to->machine = machine;
149 switch (machine)
151 case IMAGE_FILE_MACHINE_I386:
153 const I386_CONTEXT *from = src;
155 flags = from->ContextFlags & ~CONTEXT_i386;
156 if (flags & CONTEXT_I386_CONTROL)
158 to->flags |= SERVER_CTX_CONTROL;
159 to->ctl.i386_regs.ebp = from->Ebp;
160 to->ctl.i386_regs.esp = from->Esp;
161 to->ctl.i386_regs.eip = from->Eip;
162 to->ctl.i386_regs.cs = from->SegCs;
163 to->ctl.i386_regs.ss = from->SegSs;
164 to->ctl.i386_regs.eflags = from->EFlags;
166 if (flags & CONTEXT_I386_INTEGER)
168 to->flags |= SERVER_CTX_INTEGER;
169 to->integer.i386_regs.eax = from->Eax;
170 to->integer.i386_regs.ebx = from->Ebx;
171 to->integer.i386_regs.ecx = from->Ecx;
172 to->integer.i386_regs.edx = from->Edx;
173 to->integer.i386_regs.esi = from->Esi;
174 to->integer.i386_regs.edi = from->Edi;
176 if (flags & CONTEXT_I386_SEGMENTS)
178 to->flags |= SERVER_CTX_SEGMENTS;
179 to->seg.i386_regs.ds = from->SegDs;
180 to->seg.i386_regs.es = from->SegEs;
181 to->seg.i386_regs.fs = from->SegFs;
182 to->seg.i386_regs.gs = from->SegGs;
184 if (flags & CONTEXT_I386_FLOATING_POINT)
186 to->flags |= SERVER_CTX_FLOATING_POINT;
187 to->fp.i386_regs.ctrl = from->FloatSave.ControlWord;
188 to->fp.i386_regs.status = from->FloatSave.StatusWord;
189 to->fp.i386_regs.tag = from->FloatSave.TagWord;
190 to->fp.i386_regs.err_off = from->FloatSave.ErrorOffset;
191 to->fp.i386_regs.err_sel = from->FloatSave.ErrorSelector;
192 to->fp.i386_regs.data_off = from->FloatSave.DataOffset;
193 to->fp.i386_regs.data_sel = from->FloatSave.DataSelector;
194 to->fp.i386_regs.cr0npx = from->FloatSave.Cr0NpxState;
195 memcpy( to->fp.i386_regs.regs, from->FloatSave.RegisterArea, sizeof(to->fp.i386_regs.regs) );
197 if (flags & CONTEXT_I386_DEBUG_REGISTERS)
199 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
200 to->debug.i386_regs.dr0 = from->Dr0;
201 to->debug.i386_regs.dr1 = from->Dr1;
202 to->debug.i386_regs.dr2 = from->Dr2;
203 to->debug.i386_regs.dr3 = from->Dr3;
204 to->debug.i386_regs.dr6 = from->Dr6;
205 to->debug.i386_regs.dr7 = from->Dr7;
207 if (flags & CONTEXT_I386_EXTENDED_REGISTERS)
209 to->flags |= SERVER_CTX_EXTENDED_REGISTERS;
210 memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) );
212 if (flags & CONTEXT_I386_XSTATE)
214 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
215 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
217 to->flags |= SERVER_CTX_YMM_REGISTERS;
218 if (xs->Mask & 4)
219 memcpy( &to->ymm.ymm_high_regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
221 return STATUS_SUCCESS;
224 case IMAGE_FILE_MACHINE_AMD64:
226 const AMD64_CONTEXT *from = src;
228 flags = from->ContextFlags & ~CONTEXT_AMD64;
229 if (flags & CONTEXT_AMD64_CONTROL)
231 to->flags |= SERVER_CTX_CONTROL;
232 to->ctl.x86_64_regs.rbp = from->Rbp;
233 to->ctl.x86_64_regs.rip = from->Rip;
234 to->ctl.x86_64_regs.rsp = from->Rsp;
235 to->ctl.x86_64_regs.cs = from->SegCs;
236 to->ctl.x86_64_regs.ss = from->SegSs;
237 to->ctl.x86_64_regs.flags = from->EFlags;
239 if (flags & CONTEXT_AMD64_INTEGER)
241 to->flags |= SERVER_CTX_INTEGER;
242 to->integer.x86_64_regs.rax = from->Rax;
243 to->integer.x86_64_regs.rcx = from->Rcx;
244 to->integer.x86_64_regs.rdx = from->Rdx;
245 to->integer.x86_64_regs.rbx = from->Rbx;
246 to->integer.x86_64_regs.rsi = from->Rsi;
247 to->integer.x86_64_regs.rdi = from->Rdi;
248 to->integer.x86_64_regs.r8 = from->R8;
249 to->integer.x86_64_regs.r9 = from->R9;
250 to->integer.x86_64_regs.r10 = from->R10;
251 to->integer.x86_64_regs.r11 = from->R11;
252 to->integer.x86_64_regs.r12 = from->R12;
253 to->integer.x86_64_regs.r13 = from->R13;
254 to->integer.x86_64_regs.r14 = from->R14;
255 to->integer.x86_64_regs.r15 = from->R15;
257 if (flags & CONTEXT_AMD64_SEGMENTS)
259 to->flags |= SERVER_CTX_SEGMENTS;
260 to->seg.x86_64_regs.ds = from->SegDs;
261 to->seg.x86_64_regs.es = from->SegEs;
262 to->seg.x86_64_regs.fs = from->SegFs;
263 to->seg.x86_64_regs.gs = from->SegGs;
265 if (flags & CONTEXT_AMD64_FLOATING_POINT)
267 to->flags |= SERVER_CTX_FLOATING_POINT;
268 memcpy( to->fp.x86_64_regs.fpregs, &from->u.FltSave, sizeof(to->fp.x86_64_regs.fpregs) );
270 if (flags & CONTEXT_AMD64_DEBUG_REGISTERS)
272 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
273 to->debug.x86_64_regs.dr0 = from->Dr0;
274 to->debug.x86_64_regs.dr1 = from->Dr1;
275 to->debug.x86_64_regs.dr2 = from->Dr2;
276 to->debug.x86_64_regs.dr3 = from->Dr3;
277 to->debug.x86_64_regs.dr6 = from->Dr6;
278 to->debug.x86_64_regs.dr7 = from->Dr7;
280 if (flags & CONTEXT_AMD64_XSTATE)
282 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
283 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
285 to->flags |= SERVER_CTX_YMM_REGISTERS;
286 if (xs->Mask & 4)
287 memcpy( &to->ymm.ymm_high_regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
289 return STATUS_SUCCESS;
292 case IMAGE_FILE_MACHINE_ARMNT:
294 const ARM_CONTEXT *from = src;
296 flags = from->ContextFlags & ~CONTEXT_ARM;
297 if (flags & CONTEXT_ARM_CONTROL)
299 to->flags |= SERVER_CTX_CONTROL;
300 to->ctl.arm_regs.sp = from->Sp;
301 to->ctl.arm_regs.lr = from->Lr;
302 to->ctl.arm_regs.pc = from->Pc;
303 to->ctl.arm_regs.cpsr = from->Cpsr;
305 if (flags & CONTEXT_ARM_INTEGER)
307 to->flags |= SERVER_CTX_INTEGER;
308 to->integer.arm_regs.r[0] = from->R0;
309 to->integer.arm_regs.r[1] = from->R1;
310 to->integer.arm_regs.r[2] = from->R2;
311 to->integer.arm_regs.r[3] = from->R3;
312 to->integer.arm_regs.r[4] = from->R4;
313 to->integer.arm_regs.r[5] = from->R5;
314 to->integer.arm_regs.r[6] = from->R6;
315 to->integer.arm_regs.r[7] = from->R7;
316 to->integer.arm_regs.r[8] = from->R8;
317 to->integer.arm_regs.r[9] = from->R9;
318 to->integer.arm_regs.r[10] = from->R10;
319 to->integer.arm_regs.r[11] = from->R11;
320 to->integer.arm_regs.r[12] = from->R12;
322 if (flags & CONTEXT_ARM_FLOATING_POINT)
324 to->flags |= SERVER_CTX_FLOATING_POINT;
325 for (i = 0; i < 32; i++) to->fp.arm_regs.d[i] = from->u.D[i];
326 to->fp.arm_regs.fpscr = from->Fpscr;
328 if (flags & CONTEXT_ARM_DEBUG_REGISTERS)
330 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
331 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bvr[i] = from->Bvr[i];
332 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bcr[i] = from->Bcr[i];
333 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wvr[i] = from->Wvr[i];
334 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wcr[i] = from->Wcr[i];
336 return STATUS_SUCCESS;
339 case IMAGE_FILE_MACHINE_ARM64:
341 const ARM64_NT_CONTEXT *from = src;
343 flags = from->ContextFlags & ~CONTEXT_ARM64;
344 if (flags & CONTEXT_ARM64_CONTROL)
346 to->flags |= SERVER_CTX_CONTROL;
347 to->integer.arm64_regs.x[29] = from->u.s.Fp;
348 to->integer.arm64_regs.x[30] = from->u.s.Lr;
349 to->ctl.arm64_regs.sp = from->Sp;
350 to->ctl.arm64_regs.pc = from->Pc;
351 to->ctl.arm64_regs.pstate = from->Cpsr;
353 if (flags & CONTEXT_ARM64_INTEGER)
355 to->flags |= SERVER_CTX_INTEGER;
356 for (i = 0; i <= 28; i++) to->integer.arm64_regs.x[i] = from->u.X[i];
358 if (flags & CONTEXT_ARM64_FLOATING_POINT)
360 to->flags |= SERVER_CTX_FLOATING_POINT;
361 for (i = 0; i < 32; i++)
363 to->fp.arm64_regs.q[i].low = from->V[i].s.Low;
364 to->fp.arm64_regs.q[i].high = from->V[i].s.High;
366 to->fp.arm64_regs.fpcr = from->Fpcr;
367 to->fp.arm64_regs.fpsr = from->Fpsr;
369 if (flags & CONTEXT_ARM64_DEBUG_REGISTERS)
371 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
372 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bcr[i] = from->Bcr[i];
373 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bvr[i] = from->Bvr[i];
374 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wcr[i] = from->Wcr[i];
375 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wvr[i] = from->Wvr[i];
377 return STATUS_SUCCESS;
380 default:
381 return STATUS_INVALID_PARAMETER;
386 /***********************************************************************
387 * context_from_server
389 * Convert a register context from the server format.
391 static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT machine )
393 DWORD i;
395 /* special case for WoW64 (FIXME) */
396 if (machine == IMAGE_FILE_MACHINE_AMD64 && from->machine == IMAGE_FILE_MACHINE_I386)
398 AMD64_CONTEXT *to = dst;
400 to->ContextFlags = CONTEXT_AMD64;
401 if (from->flags & SERVER_CTX_CONTROL)
403 to->ContextFlags |= CONTEXT_AMD64_CONTROL;
404 to->Rbp = from->ctl.i386_regs.ebp;
405 to->Rip = from->ctl.i386_regs.eip;
406 to->Rsp = from->ctl.i386_regs.esp;
407 to->SegCs = from->ctl.i386_regs.cs;
408 to->SegSs = from->ctl.i386_regs.ss;
409 to->EFlags = from->ctl.i386_regs.eflags;
412 if (from->flags & SERVER_CTX_INTEGER)
414 to->ContextFlags |= CONTEXT_AMD64_INTEGER;
415 to->Rax = from->integer.i386_regs.eax;
416 to->Rcx = from->integer.i386_regs.ecx;
417 to->Rdx = from->integer.i386_regs.edx;
418 to->Rbx = from->integer.i386_regs.ebx;
419 to->Rsi = from->integer.i386_regs.esi;
420 to->Rdi = from->integer.i386_regs.edi;
421 to->R8 = 0;
422 to->R9 = 0;
423 to->R10 = 0;
424 to->R11 = 0;
425 to->R12 = 0;
426 to->R13 = 0;
427 to->R14 = 0;
428 to->R15 = 0;
430 if (from->flags & SERVER_CTX_SEGMENTS)
432 to->ContextFlags |= CONTEXT_AMD64_SEGMENTS;
433 to->SegDs = from->seg.i386_regs.ds;
434 to->SegEs = from->seg.i386_regs.es;
435 to->SegFs = from->seg.i386_regs.fs;
436 to->SegGs = from->seg.i386_regs.gs;
438 if (from->flags & SERVER_CTX_FLOATING_POINT)
440 to->ContextFlags |= CONTEXT_AMD64_FLOATING_POINT;
441 memset(&to->u.FltSave, 0, sizeof(to->u.FltSave));
443 if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
445 to->ContextFlags |= CONTEXT_AMD64_DEBUG_REGISTERS;
446 to->Dr0 = from->debug.i386_regs.dr0;
447 to->Dr1 = from->debug.i386_regs.dr1;
448 to->Dr2 = from->debug.i386_regs.dr2;
449 to->Dr3 = from->debug.i386_regs.dr3;
450 to->Dr6 = from->debug.i386_regs.dr6;
451 to->Dr7 = from->debug.i386_regs.dr7;
453 return STATUS_SUCCESS;
456 if (from->machine != machine) return STATUS_INVALID_PARAMETER;
458 switch (machine)
460 case IMAGE_FILE_MACHINE_I386:
462 I386_CONTEXT *to = dst;
464 to->ContextFlags = CONTEXT_i386 | (to->ContextFlags & CONTEXT_I386_XSTATE);
465 if (from->flags & SERVER_CTX_CONTROL)
467 to->ContextFlags |= CONTEXT_I386_CONTROL;
468 to->Ebp = from->ctl.i386_regs.ebp;
469 to->Esp = from->ctl.i386_regs.esp;
470 to->Eip = from->ctl.i386_regs.eip;
471 to->SegCs = from->ctl.i386_regs.cs;
472 to->SegSs = from->ctl.i386_regs.ss;
473 to->EFlags = from->ctl.i386_regs.eflags;
475 if (from->flags & SERVER_CTX_INTEGER)
477 to->ContextFlags |= CONTEXT_I386_INTEGER;
478 to->Eax = from->integer.i386_regs.eax;
479 to->Ebx = from->integer.i386_regs.ebx;
480 to->Ecx = from->integer.i386_regs.ecx;
481 to->Edx = from->integer.i386_regs.edx;
482 to->Esi = from->integer.i386_regs.esi;
483 to->Edi = from->integer.i386_regs.edi;
485 if (from->flags & SERVER_CTX_SEGMENTS)
487 to->ContextFlags |= CONTEXT_I386_SEGMENTS;
488 to->SegDs = from->seg.i386_regs.ds;
489 to->SegEs = from->seg.i386_regs.es;
490 to->SegFs = from->seg.i386_regs.fs;
491 to->SegGs = from->seg.i386_regs.gs;
493 if (from->flags & SERVER_CTX_FLOATING_POINT)
495 to->ContextFlags |= CONTEXT_I386_FLOATING_POINT;
496 to->FloatSave.ControlWord = from->fp.i386_regs.ctrl;
497 to->FloatSave.StatusWord = from->fp.i386_regs.status;
498 to->FloatSave.TagWord = from->fp.i386_regs.tag;
499 to->FloatSave.ErrorOffset = from->fp.i386_regs.err_off;
500 to->FloatSave.ErrorSelector = from->fp.i386_regs.err_sel;
501 to->FloatSave.DataOffset = from->fp.i386_regs.data_off;
502 to->FloatSave.DataSelector = from->fp.i386_regs.data_sel;
503 to->FloatSave.Cr0NpxState = from->fp.i386_regs.cr0npx;
504 memcpy( to->FloatSave.RegisterArea, from->fp.i386_regs.regs, sizeof(to->FloatSave.RegisterArea) );
506 if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
508 to->ContextFlags |= CONTEXT_I386_DEBUG_REGISTERS;
509 to->Dr0 = from->debug.i386_regs.dr0;
510 to->Dr1 = from->debug.i386_regs.dr1;
511 to->Dr2 = from->debug.i386_regs.dr2;
512 to->Dr3 = from->debug.i386_regs.dr3;
513 to->Dr6 = from->debug.i386_regs.dr6;
514 to->Dr7 = from->debug.i386_regs.dr7;
516 if (from->flags & SERVER_CTX_EXTENDED_REGISTERS)
518 to->ContextFlags |= CONTEXT_I386_EXTENDED_REGISTERS;
519 memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) );
521 if (from->flags & SERVER_CTX_YMM_REGISTERS &&
522 (to->ContextFlags & CONTEXT_I386_XSTATE) == CONTEXT_I386_XSTATE)
524 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
525 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
527 xs->Mask &= ~4;
528 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
529 for (i = 0; i < ARRAY_SIZE( from->ymm.ymm_high_regs.ymm_high); i++)
531 if (!from->ymm.ymm_high_regs.ymm_high[i].low && !from->ymm.ymm_high_regs.ymm_high[i].high)
532 continue;
533 memcpy( &xs->YmmContext, &from->ymm.ymm_high_regs, sizeof(xs->YmmContext) );
534 xs->Mask |= 4;
535 break;
538 return STATUS_SUCCESS;
541 case IMAGE_FILE_MACHINE_AMD64:
543 AMD64_CONTEXT *to = dst;
545 to->ContextFlags = CONTEXT_AMD64 | (to->ContextFlags & CONTEXT_AMD64_XSTATE);
546 if (from->flags & SERVER_CTX_CONTROL)
548 to->ContextFlags |= CONTEXT_AMD64_CONTROL;
549 to->Rbp = from->ctl.x86_64_regs.rbp;
550 to->Rip = from->ctl.x86_64_regs.rip;
551 to->Rsp = from->ctl.x86_64_regs.rsp;
552 to->SegCs = from->ctl.x86_64_regs.cs;
553 to->SegSs = from->ctl.x86_64_regs.ss;
554 to->EFlags = from->ctl.x86_64_regs.flags;
557 if (from->flags & SERVER_CTX_INTEGER)
559 to->ContextFlags |= CONTEXT_AMD64_INTEGER;
560 to->Rax = from->integer.x86_64_regs.rax;
561 to->Rcx = from->integer.x86_64_regs.rcx;
562 to->Rdx = from->integer.x86_64_regs.rdx;
563 to->Rbx = from->integer.x86_64_regs.rbx;
564 to->Rsi = from->integer.x86_64_regs.rsi;
565 to->Rdi = from->integer.x86_64_regs.rdi;
566 to->R8 = from->integer.x86_64_regs.r8;
567 to->R9 = from->integer.x86_64_regs.r9;
568 to->R10 = from->integer.x86_64_regs.r10;
569 to->R11 = from->integer.x86_64_regs.r11;
570 to->R12 = from->integer.x86_64_regs.r12;
571 to->R13 = from->integer.x86_64_regs.r13;
572 to->R14 = from->integer.x86_64_regs.r14;
573 to->R15 = from->integer.x86_64_regs.r15;
575 if (from->flags & SERVER_CTX_SEGMENTS)
577 to->ContextFlags |= CONTEXT_AMD64_SEGMENTS;
578 to->SegDs = from->seg.x86_64_regs.ds;
579 to->SegEs = from->seg.x86_64_regs.es;
580 to->SegFs = from->seg.x86_64_regs.fs;
581 to->SegGs = from->seg.x86_64_regs.gs;
583 if (from->flags & SERVER_CTX_FLOATING_POINT)
585 to->ContextFlags |= CONTEXT_AMD64_FLOATING_POINT;
586 memcpy( &to->u.FltSave, from->fp.x86_64_regs.fpregs, sizeof(from->fp.x86_64_regs.fpregs) );
587 to->MxCsr = to->u.FltSave.MxCsr;
589 if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
591 to->ContextFlags |= CONTEXT_AMD64_DEBUG_REGISTERS;
592 to->Dr0 = from->debug.x86_64_regs.dr0;
593 to->Dr1 = from->debug.x86_64_regs.dr1;
594 to->Dr2 = from->debug.x86_64_regs.dr2;
595 to->Dr3 = from->debug.x86_64_regs.dr3;
596 to->Dr6 = from->debug.x86_64_regs.dr6;
597 to->Dr7 = from->debug.x86_64_regs.dr7;
599 if (from->flags & SERVER_CTX_YMM_REGISTERS &&
600 (to->ContextFlags & CONTEXT_AMD64_XSTATE) == CONTEXT_AMD64_XSTATE)
602 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
603 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
605 xs->Mask &= ~4;
606 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
607 for (i = 0; i < ARRAY_SIZE( from->ymm.ymm_high_regs.ymm_high); i++)
609 if (!from->ymm.ymm_high_regs.ymm_high[i].low && !from->ymm.ymm_high_regs.ymm_high[i].high)
610 continue;
611 memcpy( &xs->YmmContext, &from->ymm.ymm_high_regs, sizeof(xs->YmmContext) );
612 xs->Mask |= 4;
613 break;
616 return STATUS_SUCCESS;
619 case IMAGE_FILE_MACHINE_ARMNT:
621 ARM_CONTEXT *to = dst;
623 to->ContextFlags = CONTEXT_ARM;
624 if (from->flags & SERVER_CTX_CONTROL)
626 to->ContextFlags |= CONTEXT_ARM_CONTROL;
627 to->Sp = from->ctl.arm_regs.sp;
628 to->Lr = from->ctl.arm_regs.lr;
629 to->Pc = from->ctl.arm_regs.pc;
630 to->Cpsr = from->ctl.arm_regs.cpsr;
632 if (from->flags & SERVER_CTX_INTEGER)
634 to->ContextFlags |= CONTEXT_ARM_INTEGER;
635 to->R0 = from->integer.arm_regs.r[0];
636 to->R1 = from->integer.arm_regs.r[1];
637 to->R2 = from->integer.arm_regs.r[2];
638 to->R3 = from->integer.arm_regs.r[3];
639 to->R4 = from->integer.arm_regs.r[4];
640 to->R5 = from->integer.arm_regs.r[5];
641 to->R6 = from->integer.arm_regs.r[6];
642 to->R7 = from->integer.arm_regs.r[7];
643 to->R8 = from->integer.arm_regs.r[8];
644 to->R9 = from->integer.arm_regs.r[9];
645 to->R10 = from->integer.arm_regs.r[10];
646 to->R11 = from->integer.arm_regs.r[11];
647 to->R12 = from->integer.arm_regs.r[12];
649 if (from->flags & SERVER_CTX_FLOATING_POINT)
651 to->ContextFlags |= CONTEXT_ARM_FLOATING_POINT;
652 for (i = 0; i < 32; i++) to->u.D[i] = from->fp.arm_regs.d[i];
653 to->Fpscr = from->fp.arm_regs.fpscr;
655 if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
657 to->ContextFlags |= CONTEXT_ARM_DEBUG_REGISTERS;
658 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm_regs.bvr[i];
659 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm_regs.bcr[i];
660 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm_regs.wvr[i];
661 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm_regs.wcr[i];
663 return STATUS_SUCCESS;
666 case IMAGE_FILE_MACHINE_ARM64:
668 ARM64_NT_CONTEXT *to = dst;
670 to->ContextFlags = CONTEXT_ARM64;
671 if (from->flags & SERVER_CTX_CONTROL)
673 to->ContextFlags |= CONTEXT_ARM64_CONTROL;
674 to->u.s.Fp = from->integer.arm64_regs.x[29];
675 to->u.s.Lr = from->integer.arm64_regs.x[30];
676 to->Sp = from->ctl.arm64_regs.sp;
677 to->Pc = from->ctl.arm64_regs.pc;
678 to->Cpsr = from->ctl.arm64_regs.pstate;
680 if (from->flags & SERVER_CTX_INTEGER)
682 to->ContextFlags |= CONTEXT_ARM64_INTEGER;
683 for (i = 0; i <= 28; i++) to->u.X[i] = from->integer.arm64_regs.x[i];
685 if (from->flags & SERVER_CTX_FLOATING_POINT)
687 to->ContextFlags |= CONTEXT_ARM64_FLOATING_POINT;
688 for (i = 0; i < 32; i++)
690 to->V[i].s.Low = from->fp.arm64_regs.q[i].low;
691 to->V[i].s.High = from->fp.arm64_regs.q[i].high;
693 to->Fpcr = from->fp.arm64_regs.fpcr;
694 to->Fpsr = from->fp.arm64_regs.fpsr;
696 if (from->flags & SERVER_CTX_DEBUG_REGISTERS)
698 to->ContextFlags |= CONTEXT_ARM64_DEBUG_REGISTERS;
699 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm64_regs.bcr[i];
700 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm64_regs.bvr[i];
701 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm64_regs.wcr[i];
702 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm64_regs.wvr[i];
704 return STATUS_SUCCESS;
707 default:
708 return STATUS_INVALID_PARAMETER;
713 /***********************************************************************
714 * pthread_exit_wrapper
716 static void pthread_exit_wrapper( int status )
718 close( ntdll_get_thread_data()->wait_fd[0] );
719 close( ntdll_get_thread_data()->wait_fd[1] );
720 close( ntdll_get_thread_data()->reply_fd );
721 close( ntdll_get_thread_data()->request_fd );
722 pthread_exit( UIntToPtr(status) );
726 /***********************************************************************
727 * start_thread
729 * Startup routine for a newly created thread.
731 static void start_thread( TEB *teb )
733 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
734 struct debug_info debug_info;
735 BOOL suspend;
737 debug_info.str_pos = debug_info.out_pos = 0;
738 thread_data->debug_info = &debug_info;
739 thread_data->pthread_id = pthread_self();
740 signal_init_thread( teb );
741 server_init_thread( thread_data->start, &suspend );
742 signal_start_thread( thread_data->start, thread_data->param, suspend, pLdrInitializeThunk, teb );
746 /***********************************************************************
747 * get_machine_context_size
749 static SIZE_T get_machine_context_size( USHORT machine )
751 switch (machine)
753 case IMAGE_FILE_MACHINE_I386: return sizeof(I386_CONTEXT);
754 case IMAGE_FILE_MACHINE_ARMNT: return sizeof(ARM_CONTEXT);
755 case IMAGE_FILE_MACHINE_AMD64: return sizeof(AMD64_CONTEXT);
756 case IMAGE_FILE_MACHINE_ARM64: return sizeof(ARM64_NT_CONTEXT);
757 default: return 0;
762 /***********************************************************************
763 * set_thread_id
765 void set_thread_id( TEB *teb, DWORD pid, DWORD tid )
767 teb->ClientId.UniqueProcess = ULongToHandle( pid );
768 teb->ClientId.UniqueThread = ULongToHandle( tid );
769 if (teb->WowTebOffset)
771 #ifdef _WIN64
772 TEB32 *teb32 = (TEB32 *)((char *)teb + teb->WowTebOffset);
773 teb32->ClientId.UniqueProcess = pid;
774 teb32->ClientId.UniqueThread = tid;
775 #else
776 TEB64 *teb64 = (TEB64 *)((char *)teb + teb->WowTebOffset);
777 teb64->ClientId.UniqueProcess = pid;
778 teb64->ClientId.UniqueThread = tid;
779 #endif
784 /***********************************************************************
785 * init_thread_stack
787 NTSTATUS init_thread_stack( TEB *teb, ULONG_PTR zero_bits, SIZE_T reserve_size, SIZE_T commit_size )
789 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
790 INITIAL_TEB stack;
791 NTSTATUS status;
793 if (teb->WowTebOffset)
795 WOW64_CPURESERVED *cpu;
796 SIZE_T cpusize = sizeof(WOW64_CPURESERVED) +
797 ((get_machine_context_size( main_image_info.Machine ) + 7) & ~7) + sizeof(ULONG64);
799 #ifdef _WIN64
800 TEB32 *teb32 = (TEB32 *)((char *)teb + teb->WowTebOffset);
802 /* 32-bit stack */
803 if ((status = virtual_alloc_thread_stack( &stack, zero_bits, reserve_size, commit_size, 0 )))
804 return status;
805 teb32->Tib.StackBase = PtrToUlong( stack.StackBase );
806 teb32->Tib.StackLimit = PtrToUlong( stack.StackLimit );
807 teb32->DeallocationStack = PtrToUlong( stack.DeallocationStack );
809 /* 64-bit stack */
810 if ((status = virtual_alloc_thread_stack( &stack, 0, 0x40000, 0x40000, kernel_stack_size )))
811 return status;
812 cpu = (WOW64_CPURESERVED *)(((ULONG_PTR)stack.StackBase - cpusize) & ~15);
813 cpu->Machine = main_image_info.Machine;
814 teb->Tib.StackBase = teb->TlsSlots[WOW64_TLS_CPURESERVED] = cpu;
815 teb->Tib.StackLimit = stack.StackLimit;
816 teb->DeallocationStack = stack.DeallocationStack;
817 thread_data->kernel_stack = stack.StackBase;
818 return STATUS_SUCCESS;
819 #else
820 TEB64 *teb64 = (TEB64 *)((char *)teb + teb->WowTebOffset);
822 /* 64-bit stack */
823 if ((status = virtual_alloc_thread_stack( &stack, 0, 0x40000, 0x40000, 0 ))) return status;
825 cpu = (WOW64_CPURESERVED *)(((ULONG_PTR)stack.StackBase - cpusize) & ~15);
826 cpu->Machine = main_image_info.Machine;
827 teb64->Tib.StackBase = teb64->TlsSlots[WOW64_TLS_CPURESERVED] = PtrToUlong( cpu );
828 teb64->Tib.StackLimit = PtrToUlong( stack.StackLimit );
829 teb64->DeallocationStack = PtrToUlong( stack.DeallocationStack );
830 #endif
833 /* native stack */
834 if ((status = virtual_alloc_thread_stack( &stack, zero_bits, reserve_size,
835 commit_size, kernel_stack_size )))
836 return status;
837 teb->Tib.StackBase = stack.StackBase;
838 teb->Tib.StackLimit = stack.StackLimit;
839 teb->DeallocationStack = stack.DeallocationStack;
840 thread_data->kernel_stack = stack.StackBase;
841 return STATUS_SUCCESS;
845 /***********************************************************************
846 * update_attr_list
848 * Update the output attributes.
850 static void update_attr_list( PS_ATTRIBUTE_LIST *attr, const CLIENT_ID *id, TEB *teb )
852 SIZE_T i, count = (attr->TotalLength - sizeof(attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
854 for (i = 0; i < count; i++)
856 if (attr->Attributes[i].Attribute == PS_ATTRIBUTE_CLIENT_ID)
858 SIZE_T size = min( attr->Attributes[i].Size, sizeof(*id) );
859 memcpy( attr->Attributes[i].ValuePtr, id, size );
860 if (attr->Attributes[i].ReturnLength) *attr->Attributes[i].ReturnLength = size;
862 else if (attr->Attributes[i].Attribute == PS_ATTRIBUTE_TEB_ADDRESS)
864 SIZE_T size = min( attr->Attributes[i].Size, sizeof(teb) );
865 memcpy( attr->Attributes[i].ValuePtr, &teb, size );
866 if (attr->Attributes[i].ReturnLength) *attr->Attributes[i].ReturnLength = size;
871 /***********************************************************************
872 * NtCreateThread (NTDLL.@)
874 NTSTATUS WINAPI NtCreateThread( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
875 HANDLE process, CLIENT_ID *id, CONTEXT *ctx, INITIAL_TEB *teb,
876 BOOLEAN suspended )
878 FIXME( "%p %d %p %p %p %p %p %d, stub!\n", handle, access, attr, process, id, ctx, teb, suspended );
879 return STATUS_NOT_IMPLEMENTED;
882 /***********************************************************************
883 * NtCreateThreadEx (NTDLL.@)
885 NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
886 HANDLE process, PRTL_THREAD_START_ROUTINE start, void *param,
887 ULONG flags, ULONG_PTR zero_bits, SIZE_T stack_commit,
888 SIZE_T stack_reserve, PS_ATTRIBUTE_LIST *attr_list )
890 sigset_t sigset;
891 pthread_t pthread_id;
892 pthread_attr_t pthread_attr;
893 data_size_t len;
894 struct object_attributes *objattr;
895 struct ntdll_thread_data *thread_data;
896 DWORD tid = 0;
897 int request_pipe[2];
898 TEB *teb;
899 NTSTATUS status;
901 if (zero_bits > 21 && zero_bits < 32) return STATUS_INVALID_PARAMETER_3;
902 #ifndef _WIN64
903 if (!is_wow64 && zero_bits >= 32) return STATUS_INVALID_PARAMETER_3;
904 #endif
906 if (process != NtCurrentProcess())
908 apc_call_t call;
909 apc_result_t result;
911 memset( &call, 0, sizeof(call) );
913 call.create_thread.type = APC_CREATE_THREAD;
914 call.create_thread.flags = flags;
915 call.create_thread.func = wine_server_client_ptr( start );
916 call.create_thread.arg = wine_server_client_ptr( param );
917 call.create_thread.zero_bits = zero_bits;
918 call.create_thread.reserve = stack_reserve;
919 call.create_thread.commit = stack_commit;
920 status = server_queue_process_apc( process, &call, &result );
921 if (status != STATUS_SUCCESS) return status;
923 if (result.create_thread.status == STATUS_SUCCESS)
925 CLIENT_ID client_id;
926 TEB *teb = wine_server_get_ptr( result.create_thread.teb );
927 *handle = wine_server_ptr_handle( result.create_thread.handle );
928 client_id.UniqueProcess = ULongToHandle( result.create_thread.pid );
929 client_id.UniqueThread = ULongToHandle( result.create_thread.tid );
930 if (attr_list) update_attr_list( attr_list, &client_id, teb );
932 return result.create_thread.status;
935 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
937 if (server_pipe( request_pipe ) == -1)
939 free( objattr );
940 return STATUS_TOO_MANY_OPENED_FILES;
942 wine_server_send_fd( request_pipe[0] );
944 if (!access) access = THREAD_ALL_ACCESS;
946 SERVER_START_REQ( new_thread )
948 req->process = wine_server_obj_handle( process );
949 req->access = access;
950 req->suspend = flags & THREAD_CREATE_FLAGS_CREATE_SUSPENDED;
951 req->request_fd = request_pipe[0];
952 wine_server_add_data( req, objattr, len );
953 if (!(status = wine_server_call( req )))
955 *handle = wine_server_ptr_handle( reply->handle );
956 tid = reply->tid;
958 close( request_pipe[0] );
960 SERVER_END_REQ;
962 free( objattr );
963 if (status)
965 close( request_pipe[1] );
966 return status;
969 pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
971 if ((status = virtual_alloc_teb( &teb ))) goto done;
973 if ((status = init_thread_stack( teb, zero_bits, stack_reserve, stack_commit )))
975 virtual_free_teb( teb );
976 goto done;
979 set_thread_id( teb, GetCurrentProcessId(), tid );
981 thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
982 thread_data->request_fd = request_pipe[1];
983 thread_data->start = start;
984 thread_data->param = param;
986 pthread_attr_init( &pthread_attr );
987 pthread_attr_setstack( &pthread_attr, teb->DeallocationStack,
988 (char *)thread_data->kernel_stack + kernel_stack_size - (char *)teb->DeallocationStack );
989 pthread_attr_setguardsize( &pthread_attr, 0 );
990 pthread_attr_setscope( &pthread_attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a kernel thread */
991 InterlockedIncrement( &nb_threads );
992 if (pthread_create( &pthread_id, &pthread_attr, (void * (*)(void *))start_thread, teb ))
994 InterlockedDecrement( &nb_threads );
995 virtual_free_teb( teb );
996 status = STATUS_NO_MEMORY;
998 pthread_attr_destroy( &pthread_attr );
1000 done:
1001 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
1002 if (status)
1004 NtClose( *handle );
1005 close( request_pipe[1] );
1006 return status;
1008 if (attr_list) update_attr_list( attr_list, &teb->ClientId, teb );
1009 return STATUS_SUCCESS;
1013 /***********************************************************************
1014 * abort_thread
1016 void abort_thread( int status )
1018 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
1019 if (InterlockedDecrement( &nb_threads ) <= 0) abort_process( status );
1020 signal_exit_thread( status, pthread_exit_wrapper );
1024 /***********************************************************************
1025 * abort_process
1027 void abort_process( int status )
1029 _exit( get_unix_exit_code( status ));
1033 /***********************************************************************
1034 * exit_thread
1036 static DECLSPEC_NORETURN void exit_thread( int status )
1038 static void *prev_teb;
1039 TEB *teb;
1041 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
1043 if ((teb = InterlockedExchangePointer( &prev_teb, NtCurrentTeb() )))
1045 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1047 if (thread_data->pthread_id)
1049 pthread_join( thread_data->pthread_id, NULL );
1050 virtual_free_teb( teb );
1053 signal_exit_thread( status, pthread_exit_wrapper );
1057 /***********************************************************************
1058 * exit_process
1060 void exit_process( int status )
1062 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
1063 signal_exit_thread( get_unix_exit_code( status ), process_exit_wrapper );
1067 /**********************************************************************
1068 * wait_suspend
1070 * Wait until the thread is no longer suspended.
1072 void wait_suspend( CONTEXT *context )
1074 int saved_errno = errno;
1075 context_t server_context;
1077 context_to_server( &server_context, context, current_machine );
1078 /* wait with 0 timeout, will only return once the thread is no longer suspended */
1079 server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, &server_context, NULL, NULL );
1080 context_from_server( context, &server_context, current_machine );
1081 errno = saved_errno;
1085 /**********************************************************************
1086 * send_debug_event
1088 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
1090 NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1092 NTSTATUS ret;
1093 DWORD i;
1094 obj_handle_t handle = 0;
1095 client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
1096 select_op_t select_op;
1097 sigset_t old_set;
1099 if (!NtCurrentTeb()->Peb->BeingDebugged) return 0; /* no debugger present */
1101 pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set );
1103 for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++)
1104 params[i] = rec->ExceptionInformation[i];
1106 SERVER_START_REQ( queue_exception_event )
1108 req->first = first_chance;
1109 req->code = rec->ExceptionCode;
1110 req->flags = rec->ExceptionFlags;
1111 req->record = wine_server_client_ptr( rec->ExceptionRecord );
1112 req->address = wine_server_client_ptr( rec->ExceptionAddress );
1113 req->len = i * sizeof(params[0]);
1114 wine_server_add_data( req, params, req->len );
1115 if (!(ret = wine_server_call( req ))) handle = reply->handle;
1117 SERVER_END_REQ;
1119 if (handle)
1121 context_t server_context;
1123 select_op.wait.op = SELECT_WAIT;
1124 select_op.wait.handles[0] = handle;
1126 context_to_server( &server_context, context, current_machine );
1128 server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE,
1129 TIMEOUT_INFINITE, &server_context, NULL, NULL );
1131 SERVER_START_REQ( get_exception_status )
1133 req->handle = handle;
1134 ret = wine_server_call( req );
1136 SERVER_END_REQ;
1137 if (ret >= 0) context_from_server( context, &server_context, current_machine );
1140 pthread_sigmask( SIG_SETMASK, &old_set, NULL );
1141 return ret;
1145 /*******************************************************************
1146 * NtRaiseException (NTDLL.@)
1148 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1150 NTSTATUS status = send_debug_event( rec, context, first_chance );
1152 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
1153 return NtContinue( context, FALSE );
1155 if (first_chance) return call_user_exception_dispatcher( rec, context, pKiUserExceptionDispatcher );
1157 if (rec->ExceptionFlags & EH_STACK_INVALID)
1158 ERR_(seh)("Exception frame is not in stack limits => unable to dispatch exception.\n");
1159 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
1160 ERR_(seh)("Process attempted to continue execution after noncontinuable exception.\n");
1161 else
1162 ERR_(seh)("Unhandled exception code %x flags %x addr %p\n",
1163 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
1165 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
1166 return STATUS_SUCCESS;
1170 /***********************************************************************
1171 * NtOpenThread (NTDLL.@)
1173 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
1174 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
1176 NTSTATUS ret;
1178 SERVER_START_REQ( open_thread )
1180 req->tid = HandleToULong(id->UniqueThread);
1181 req->access = access;
1182 req->attributes = attr ? attr->Attributes : 0;
1183 ret = wine_server_call( req );
1184 *handle = wine_server_ptr_handle( reply->handle );
1186 SERVER_END_REQ;
1187 return ret;
1191 /******************************************************************************
1192 * NtSuspendThread (NTDLL.@)
1194 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count )
1196 NTSTATUS ret;
1198 SERVER_START_REQ( suspend_thread )
1200 req->handle = wine_server_obj_handle( handle );
1201 if (!(ret = wine_server_call( req )))
1203 if (count) *count = reply->count;
1206 SERVER_END_REQ;
1207 return ret;
1211 /******************************************************************************
1212 * NtResumeThread (NTDLL.@)
1214 NTSTATUS WINAPI NtResumeThread( HANDLE handle, ULONG *count )
1216 NTSTATUS ret;
1218 SERVER_START_REQ( resume_thread )
1220 req->handle = wine_server_obj_handle( handle );
1221 if (!(ret = wine_server_call( req )))
1223 if (count) *count = reply->count;
1226 SERVER_END_REQ;
1227 return ret;
1231 /******************************************************************************
1232 * NtAlertResumeThread (NTDLL.@)
1234 NTSTATUS WINAPI NtAlertResumeThread( HANDLE handle, ULONG *count )
1236 FIXME( "stub: should alert thread %p\n", handle );
1237 return NtResumeThread( handle, count );
1241 /******************************************************************************
1242 * NtAlertThread (NTDLL.@)
1244 NTSTATUS WINAPI NtAlertThread( HANDLE handle )
1246 FIXME( "stub: %p\n", handle );
1247 return STATUS_NOT_IMPLEMENTED;
1251 /******************************************************************************
1252 * NtTerminateThread (NTDLL.@)
1254 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
1256 NTSTATUS ret;
1257 BOOL self = (handle == GetCurrentThread());
1259 if (!self || exit_code)
1261 SERVER_START_REQ( terminate_thread )
1263 req->handle = wine_server_obj_handle( handle );
1264 req->exit_code = exit_code;
1265 ret = wine_server_call( req );
1266 self = !ret && reply->self;
1268 SERVER_END_REQ;
1270 if (self) exit_thread( exit_code );
1271 return ret;
1275 /******************************************************************************
1276 * NtQueueApcThread (NTDLL.@)
1278 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
1279 ULONG_PTR arg2, ULONG_PTR arg3 )
1281 NTSTATUS ret;
1283 SERVER_START_REQ( queue_apc )
1285 req->handle = wine_server_obj_handle( handle );
1286 if (func)
1288 req->call.type = APC_USER;
1289 req->call.user.func = wine_server_client_ptr( func );
1290 req->call.user.args[0] = arg1;
1291 req->call.user.args[1] = arg2;
1292 req->call.user.args[2] = arg3;
1294 else req->call.type = APC_NONE; /* wake up only */
1295 ret = wine_server_call( req );
1297 SERVER_END_REQ;
1298 return ret;
1302 /***********************************************************************
1303 * set_thread_context
1305 NTSTATUS set_thread_context( HANDLE handle, const void *context, BOOL *self, USHORT machine )
1307 context_t server_context;
1308 NTSTATUS ret;
1310 context_to_server( &server_context, context, machine );
1311 SERVER_START_REQ( set_thread_context )
1313 req->handle = wine_server_obj_handle( handle );
1314 wine_server_add_data( req, &server_context, sizeof(server_context) );
1315 ret = wine_server_call( req );
1316 *self = reply->self;
1318 SERVER_END_REQ;
1320 return ret;
1324 /***********************************************************************
1325 * get_thread_context
1327 NTSTATUS get_thread_context( HANDLE handle, void *context, BOOL *self, USHORT machine )
1329 NTSTATUS ret;
1330 context_t server_context;
1331 unsigned int flags = get_server_context_flags( context, machine );
1333 SERVER_START_REQ( get_thread_context )
1335 req->handle = wine_server_obj_handle( handle );
1336 req->flags = flags;
1337 wine_server_set_reply( req, &server_context, sizeof(server_context) );
1338 ret = wine_server_call( req );
1339 *self = reply->self;
1340 handle = wine_server_ptr_handle( reply->handle );
1342 SERVER_END_REQ;
1344 if (ret == STATUS_PENDING)
1346 NtWaitForSingleObject( handle, FALSE, NULL );
1348 SERVER_START_REQ( get_thread_context )
1350 req->handle = wine_server_obj_handle( handle );
1351 req->flags = flags;
1352 wine_server_set_reply( req, &server_context, sizeof(server_context) );
1353 ret = wine_server_call( req );
1355 SERVER_END_REQ;
1357 if (!ret) ret = context_from_server( context, &server_context, machine );
1358 return ret;
1362 BOOL get_thread_times(int unix_pid, int unix_tid, LARGE_INTEGER *kernel_time, LARGE_INTEGER *user_time)
1364 #ifdef linux
1365 unsigned long clocks_per_sec = sysconf( _SC_CLK_TCK );
1366 unsigned long usr, sys;
1367 const char *pos;
1368 char buf[512];
1369 FILE *f;
1370 int i;
1372 if (unix_tid == -1)
1373 sprintf( buf, "/proc/%u/stat", unix_pid );
1374 else
1375 sprintf( buf, "/proc/%u/task/%u/stat", unix_pid, unix_tid );
1376 if (!(f = fopen( buf, "r" )))
1378 WARN("Failed to open %s: %s\n", buf, strerror(errno));
1379 return FALSE;
1382 pos = fgets( buf, sizeof(buf), f );
1383 fclose( f );
1385 /* the process name is printed unescaped, so we have to skip to the last ')'
1386 * to avoid misinterpreting the string */
1387 if (pos) pos = strrchr( pos, ')' );
1388 if (pos) pos = strchr( pos + 1, ' ' );
1389 if (pos) pos++;
1391 /* skip over the following fields: state, ppid, pgid, sid, tty_nr, tty_pgrp,
1392 * task->flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
1393 for (i = 0; i < 11 && pos; i++)
1395 pos = strchr( pos + 1, ' ' );
1396 if (pos) pos++;
1399 /* the next two values are user and system time */
1400 if (pos && (sscanf( pos, "%lu %lu", &usr, &sys ) == 2))
1402 kernel_time->QuadPart = (ULONGLONG)sys * 10000000 / clocks_per_sec;
1403 user_time->QuadPart = (ULONGLONG)usr * 10000000 / clocks_per_sec;
1404 return TRUE;
1407 ERR("Failed to parse %s\n", debugstr_a(buf));
1408 return FALSE;
1409 #elif defined(HAVE_LIBPROCSTAT)
1410 struct procstat *pstat;
1411 struct kinfo_proc *kip;
1412 unsigned int proc_count;
1413 BOOL ret = FALSE;
1415 pstat = procstat_open_sysctl();
1416 if (!pstat)
1417 return FALSE;
1418 if (unix_tid == -1)
1419 kip = procstat_getprocs(pstat, KERN_PROC_PID, unix_pid, &proc_count);
1420 else
1421 kip = procstat_getprocs(pstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, unix_pid, &proc_count);
1422 if (kip)
1424 unsigned int i;
1425 for (i = 0; i < proc_count; i++)
1427 if (unix_tid == -1 || kip[i].ki_tid == unix_tid)
1429 kernel_time->QuadPart = 10000000 * (ULONGLONG)kip[i].ki_rusage.ru_stime.tv_sec +
1430 10 * (ULONGLONG)kip[i].ki_rusage.ru_stime.tv_usec;
1431 user_time->QuadPart = 10000000 * (ULONGLONG)kip[i].ki_rusage.ru_utime.tv_sec +
1432 10 * (ULONGLONG)kip[i].ki_rusage.ru_utime.tv_usec;
1433 ret = TRUE;
1434 break;
1437 procstat_freeprocs(pstat, kip);
1439 procstat_close(pstat);
1440 return ret;
1441 #else
1442 static int once;
1443 if (!once++) FIXME("not implemented on this platform\n");
1444 return FALSE;
1445 #endif
1448 #ifndef _WIN64
1449 static BOOL is_process_wow64( const CLIENT_ID *id )
1451 HANDLE handle;
1452 ULONG_PTR info;
1453 BOOL ret = FALSE;
1455 if (id->UniqueProcess == ULongToHandle(GetCurrentProcessId())) return is_wow64;
1456 if (!NtOpenProcess( &handle, PROCESS_QUERY_LIMITED_INFORMATION, NULL, id ))
1458 if (!NtQueryInformationProcess( handle, ProcessWow64Information, &info, sizeof(info), NULL ))
1459 ret = !!info;
1460 NtClose( handle );
1462 return ret;
1464 #endif
1466 /******************************************************************************
1467 * NtQueryInformationThread (NTDLL.@)
1469 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
1470 void *data, ULONG length, ULONG *ret_len )
1472 NTSTATUS status;
1474 TRACE("(%p,%d,%p,%x,%p)\n", handle, class, data, length, ret_len);
1476 switch (class)
1478 case ThreadBasicInformation:
1480 THREAD_BASIC_INFORMATION info;
1481 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1483 SERVER_START_REQ( get_thread_info )
1485 req->handle = wine_server_obj_handle( handle );
1486 if (!(status = wine_server_call( req )))
1488 info.ExitStatus = reply->exit_code;
1489 info.TebBaseAddress = wine_server_get_ptr( reply->teb );
1490 info.ClientId.UniqueProcess = ULongToHandle(reply->pid);
1491 info.ClientId.UniqueThread = ULongToHandle(reply->tid);
1492 info.AffinityMask = reply->affinity & affinity_mask;
1493 info.Priority = reply->priority;
1494 info.BasePriority = reply->priority; /* FIXME */
1497 SERVER_END_REQ;
1498 if (status == STATUS_SUCCESS)
1500 #ifndef _WIN64
1501 if (is_wow64)
1503 if (is_process_wow64( &info.ClientId ))
1504 info.TebBaseAddress = (char *)info.TebBaseAddress + teb_offset;
1505 else
1506 info.TebBaseAddress = NULL;
1508 #endif
1509 if (data) memcpy( data, &info, min( length, sizeof(info) ));
1510 if (ret_len) *ret_len = min( length, sizeof(info) );
1512 return status;
1515 case ThreadAffinityMask:
1517 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1518 ULONG_PTR affinity = 0;
1520 SERVER_START_REQ( get_thread_info )
1522 req->handle = wine_server_obj_handle( handle );
1523 req->access = THREAD_QUERY_INFORMATION;
1524 if (!(status = wine_server_call( req ))) affinity = reply->affinity & affinity_mask;
1526 SERVER_END_REQ;
1527 if (status == STATUS_SUCCESS)
1529 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
1530 if (ret_len) *ret_len = min( length, sizeof(affinity) );
1532 return status;
1535 case ThreadTimes:
1537 KERNEL_USER_TIMES kusrt;
1538 int unix_pid, unix_tid;
1540 SERVER_START_REQ( get_thread_times )
1542 req->handle = wine_server_obj_handle( handle );
1543 status = wine_server_call( req );
1544 if (status == STATUS_SUCCESS)
1546 kusrt.CreateTime.QuadPart = reply->creation_time;
1547 kusrt.ExitTime.QuadPart = reply->exit_time;
1548 unix_pid = reply->unix_pid;
1549 unix_tid = reply->unix_tid;
1552 SERVER_END_REQ;
1553 if (status == STATUS_SUCCESS)
1555 BOOL ret = FALSE;
1557 kusrt.KernelTime.QuadPart = kusrt.UserTime.QuadPart = 0;
1558 if (unix_pid != -1 && unix_tid != -1)
1559 ret = get_thread_times( unix_pid, unix_tid, &kusrt.KernelTime, &kusrt.UserTime );
1560 if (!ret && handle == GetCurrentThread())
1562 /* fall back to process times */
1563 struct tms time_buf;
1564 long clocks_per_sec = sysconf(_SC_CLK_TCK);
1566 times(&time_buf);
1567 kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
1568 kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
1570 if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
1571 if (ret_len) *ret_len = min( length, sizeof(kusrt) );
1573 return status;
1576 case ThreadDescriptorTableEntry:
1577 return get_thread_ldt_entry( handle, data, length, ret_len );
1579 case ThreadAmILastThread:
1581 if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
1582 SERVER_START_REQ( get_thread_info )
1584 req->handle = wine_server_obj_handle( handle );
1585 status = wine_server_call( req );
1586 if (status == STATUS_SUCCESS)
1588 ULONG last = reply->last;
1589 if (data) memcpy( data, &last, sizeof(last) );
1590 if (ret_len) *ret_len = sizeof(last);
1593 SERVER_END_REQ;
1594 return status;
1597 case ThreadQuerySetWin32StartAddress:
1599 SERVER_START_REQ( get_thread_info )
1601 req->handle = wine_server_obj_handle( handle );
1602 req->access = THREAD_QUERY_INFORMATION;
1603 status = wine_server_call( req );
1604 if (status == STATUS_SUCCESS)
1606 PRTL_THREAD_START_ROUTINE entry = wine_server_get_ptr( reply->entry_point );
1607 if (data) memcpy( data, &entry, min( length, sizeof(entry) ) );
1608 if (ret_len) *ret_len = min( length, sizeof(entry) );
1611 SERVER_END_REQ;
1612 return status;
1615 case ThreadGroupInformation:
1617 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1618 GROUP_AFFINITY affinity;
1620 memset( &affinity, 0, sizeof(affinity) );
1621 affinity.Group = 0; /* Wine only supports max 64 processors */
1623 SERVER_START_REQ( get_thread_info )
1625 req->handle = wine_server_obj_handle( handle );
1626 if (!(status = wine_server_call( req ))) affinity.Mask = reply->affinity & affinity_mask;
1628 SERVER_END_REQ;
1629 if (status == STATUS_SUCCESS)
1631 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
1632 if (ret_len) *ret_len = min( length, sizeof(affinity) );
1634 return status;
1637 case ThreadIsIoPending:
1638 FIXME( "ThreadIsIoPending info class not supported yet\n" );
1639 if (length != sizeof(BOOL)) return STATUS_INFO_LENGTH_MISMATCH;
1640 if (!data) return STATUS_ACCESS_DENIED;
1641 *(BOOL*)data = FALSE;
1642 if (ret_len) *ret_len = sizeof(BOOL);
1643 return STATUS_SUCCESS;
1645 case ThreadSuspendCount:
1646 if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
1647 if (!data) return STATUS_ACCESS_VIOLATION;
1649 SERVER_START_REQ( get_thread_info )
1651 req->handle = wine_server_obj_handle( handle );
1652 if (!(status = wine_server_call( req ))) *(ULONG *)data = reply->suspend_count;
1654 SERVER_END_REQ;
1655 return status;
1657 case ThreadDescription:
1659 THREAD_DESCRIPTION_INFORMATION *info = data;
1660 data_size_t len, desc_len = 0;
1661 WCHAR *ptr;
1663 len = length >= sizeof(*info) ? length - sizeof(*info) : 0;
1664 ptr = info ? (WCHAR *)(info + 1) : NULL;
1666 SERVER_START_REQ( get_thread_info )
1668 req->handle = wine_server_obj_handle( handle );
1669 if (ptr) wine_server_set_reply( req, ptr, len );
1670 status = wine_server_call( req );
1671 desc_len = reply->desc_len;
1673 SERVER_END_REQ;
1675 if (!info) status = STATUS_BUFFER_TOO_SMALL;
1676 else if (status == STATUS_SUCCESS)
1678 info->Description.Length = info->Description.MaximumLength = desc_len;
1679 info->Description.Buffer = ptr;
1682 if (ret_len && (status == STATUS_SUCCESS || status == STATUS_BUFFER_TOO_SMALL))
1683 *ret_len = sizeof(*info) + desc_len;
1684 return status;
1687 case ThreadWow64Context:
1688 return get_thread_wow64_context( handle, data, length );
1690 case ThreadHideFromDebugger:
1691 if (length != sizeof(BOOLEAN)) return STATUS_INFO_LENGTH_MISMATCH;
1692 if (!data) return STATUS_ACCESS_VIOLATION;
1693 SERVER_START_REQ( get_thread_info )
1695 req->handle = wine_server_obj_handle( handle );
1696 req->access = THREAD_QUERY_INFORMATION;
1697 if ((status = wine_server_call( req ))) return status;
1698 *(BOOLEAN*)data = reply->dbg_hidden;
1700 SERVER_END_REQ;
1701 if (ret_len) *ret_len = sizeof(BOOLEAN);
1702 return STATUS_SUCCESS;
1704 case ThreadEnableAlignmentFaultFixup:
1705 return STATUS_INVALID_INFO_CLASS;
1707 case ThreadPriority:
1708 case ThreadBasePriority:
1709 case ThreadImpersonationToken:
1710 case ThreadEventPair_Reusable:
1711 case ThreadZeroTlsCell:
1712 case ThreadPerformanceCount:
1713 case ThreadIdealProcessor:
1714 case ThreadPriorityBoost:
1715 case ThreadSetTlsArrayAddress:
1716 default:
1717 FIXME( "info class %d not supported yet\n", class );
1718 return STATUS_NOT_IMPLEMENTED;
1723 /******************************************************************************
1724 * NtSetInformationThread (NTDLL.@)
1726 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
1727 const void *data, ULONG length )
1729 NTSTATUS status;
1731 TRACE("(%p,%d,%p,%x)\n", handle, class, data, length);
1733 switch (class)
1735 case ThreadZeroTlsCell:
1736 if (handle == GetCurrentThread())
1738 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
1739 return virtual_clear_tls_index( *(const ULONG *)data );
1741 FIXME( "ZeroTlsCell not supported on other threads\n" );
1742 return STATUS_NOT_IMPLEMENTED;
1744 case ThreadImpersonationToken:
1746 const HANDLE *token = data;
1748 if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
1749 TRACE("Setting ThreadImpersonationToken handle to %p\n", *token );
1750 SERVER_START_REQ( set_thread_info )
1752 req->handle = wine_server_obj_handle( handle );
1753 req->token = wine_server_obj_handle( *token );
1754 req->mask = SET_THREAD_INFO_TOKEN;
1755 status = wine_server_call( req );
1757 SERVER_END_REQ;
1758 return status;
1761 case ThreadBasePriority:
1763 const DWORD *pprio = data;
1764 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
1765 SERVER_START_REQ( set_thread_info )
1767 req->handle = wine_server_obj_handle( handle );
1768 req->priority = *pprio;
1769 req->mask = SET_THREAD_INFO_PRIORITY;
1770 status = wine_server_call( req );
1772 SERVER_END_REQ;
1773 return status;
1776 case ThreadAffinityMask:
1778 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1779 ULONG_PTR req_aff;
1781 if (length != sizeof(ULONG_PTR)) return STATUS_INVALID_PARAMETER;
1782 req_aff = *(const ULONG_PTR *)data & affinity_mask;
1783 if (!req_aff) return STATUS_INVALID_PARAMETER;
1785 SERVER_START_REQ( set_thread_info )
1787 req->handle = wine_server_obj_handle( handle );
1788 req->affinity = req_aff;
1789 req->mask = SET_THREAD_INFO_AFFINITY;
1790 status = wine_server_call( req );
1792 SERVER_END_REQ;
1793 return status;
1796 case ThreadHideFromDebugger:
1797 if (length) return STATUS_INFO_LENGTH_MISMATCH;
1798 SERVER_START_REQ( set_thread_info )
1800 req->handle = wine_server_obj_handle( handle );
1801 req->mask = SET_THREAD_INFO_DBG_HIDDEN;
1802 status = wine_server_call( req );
1804 SERVER_END_REQ;
1805 return status;
1807 case ThreadQuerySetWin32StartAddress:
1809 const PRTL_THREAD_START_ROUTINE *entry = data;
1810 if (length != sizeof(PRTL_THREAD_START_ROUTINE)) return STATUS_INVALID_PARAMETER;
1811 SERVER_START_REQ( set_thread_info )
1813 req->handle = wine_server_obj_handle( handle );
1814 req->mask = SET_THREAD_INFO_ENTRYPOINT;
1815 req->entry_point = wine_server_client_ptr( *entry );
1816 status = wine_server_call( req );
1818 SERVER_END_REQ;
1819 return status;
1822 case ThreadGroupInformation:
1824 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1825 const GROUP_AFFINITY *req_aff;
1827 if (length != sizeof(*req_aff)) return STATUS_INVALID_PARAMETER;
1828 if (!data) return STATUS_ACCESS_VIOLATION;
1829 req_aff = data;
1831 /* On Windows the request fails if the reserved fields are set */
1832 if (req_aff->Reserved[0] || req_aff->Reserved[1] || req_aff->Reserved[2])
1833 return STATUS_INVALID_PARAMETER;
1835 /* Wine only supports max 64 processors */
1836 if (req_aff->Group) return STATUS_INVALID_PARAMETER;
1837 if (req_aff->Mask & ~affinity_mask) return STATUS_INVALID_PARAMETER;
1838 if (!req_aff->Mask) return STATUS_INVALID_PARAMETER;
1839 SERVER_START_REQ( set_thread_info )
1841 req->handle = wine_server_obj_handle( handle );
1842 req->affinity = req_aff->Mask;
1843 req->mask = SET_THREAD_INFO_AFFINITY;
1844 status = wine_server_call( req );
1846 SERVER_END_REQ;
1847 return status;
1850 case ThreadDescription:
1852 const THREAD_DESCRIPTION_INFORMATION *info = data;
1854 if (length != sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
1855 if (!info) return STATUS_ACCESS_VIOLATION;
1856 if (info->Description.Length != info->Description.MaximumLength) return STATUS_INVALID_PARAMETER;
1857 if (info->Description.Length && !info->Description.Buffer) return STATUS_ACCESS_VIOLATION;
1859 SERVER_START_REQ( set_thread_info )
1861 req->handle = wine_server_obj_handle( handle );
1862 req->mask = SET_THREAD_INFO_DESCRIPTION;
1863 wine_server_add_data( req, info->Description.Buffer, info->Description.Length );
1864 status = wine_server_call( req );
1866 SERVER_END_REQ;
1867 return status;
1870 case ThreadWow64Context:
1871 return set_thread_wow64_context( handle, data, length );
1873 case ThreadEnableAlignmentFaultFixup:
1874 if (length != sizeof(BOOLEAN)) return STATUS_INFO_LENGTH_MISMATCH;
1875 if (!data) return STATUS_ACCESS_VIOLATION;
1876 FIXME( "ThreadEnableAlignmentFaultFixup stub!\n" );
1877 return STATUS_SUCCESS;
1879 case ThreadBasicInformation:
1880 case ThreadTimes:
1881 case ThreadPriority:
1882 case ThreadDescriptorTableEntry:
1883 case ThreadEventPair_Reusable:
1884 case ThreadPerformanceCount:
1885 case ThreadAmILastThread:
1886 case ThreadIdealProcessor:
1887 case ThreadPriorityBoost:
1888 case ThreadSetTlsArrayAddress:
1889 case ThreadIsIoPending:
1890 default:
1891 FIXME( "info class %d not supported yet\n", class );
1892 return STATUS_NOT_IMPLEMENTED;
1897 /******************************************************************************
1898 * NtGetCurrentProcessorNumber (NTDLL.@)
1900 ULONG WINAPI NtGetCurrentProcessorNumber(void)
1902 ULONG processor;
1904 #if defined(__linux__) && defined(__NR_getcpu)
1905 int res = syscall(__NR_getcpu, &processor, NULL, NULL);
1906 if (res != -1) return processor;
1907 #endif
1909 if (NtCurrentTeb()->Peb->NumberOfProcessors > 1)
1911 ULONG_PTR thread_mask, processor_mask;
1913 if (!NtQueryInformationThread( GetCurrentThread(), ThreadAffinityMask,
1914 &thread_mask, sizeof(thread_mask), NULL ))
1916 for (processor = 0; processor < NtCurrentTeb()->Peb->NumberOfProcessors; processor++)
1918 processor_mask = (1 << processor);
1919 if (thread_mask & processor_mask)
1921 if (thread_mask != processor_mask)
1922 FIXME( "need multicore support (%d processors)\n",
1923 NtCurrentTeb()->Peb->NumberOfProcessors );
1924 return processor;
1929 /* fallback to the first processor */
1930 return 0;
1934 /******************************************************************************
1935 * NtGetNextThread (NTDLL.@)
1937 NTSTATUS WINAPI NtGetNextThread( HANDLE process, HANDLE thread, ACCESS_MASK access, ULONG attributes,
1938 ULONG flags, HANDLE *handle )
1940 HANDLE ret_handle = 0;
1941 NTSTATUS ret;
1943 TRACE( "process %p, thread %p, access %#x, attributes %#x, flags %#x, handle %p.\n",
1944 process, thread, access, attributes, flags, handle );
1946 SERVER_START_REQ( get_next_thread )
1948 req->process = wine_server_obj_handle( process );
1949 req->last = wine_server_obj_handle( thread );
1950 req->access = access;
1951 req->attributes = attributes;
1952 req->flags = flags;
1953 if (!(ret = wine_server_call( req ))) ret_handle = wine_server_ptr_handle( reply->handle );
1955 SERVER_END_REQ;
1957 *handle = ret_handle;
1958 return ret;