ntdll: Use nameless unions/structs for CPU-related data.
[wine.git] / dlls / ntdll / unix / thread.c
blob3e2be2feaffd1e4c1eae500b2ace73e02e605f53
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"
27 #include <assert.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <limits.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <pthread.h>
36 #include <signal.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39 #include <sys/mman.h>
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 #ifdef __APPLE__
63 #include <mach/mach.h>
64 #endif
66 #include "ntstatus.h"
67 #define WIN32_NO_STATUS
68 #include "winternl.h"
69 #include "ddk/wdm.h"
70 #include "wine/server.h"
71 #include "wine/debug.h"
72 #include "unix_private.h"
74 WINE_DEFAULT_DEBUG_CHANNEL(thread);
75 WINE_DECLARE_DEBUG_CHANNEL(seh);
76 WINE_DECLARE_DEBUG_CHANNEL(threadname);
78 pthread_key_t teb_key = 0;
80 static LONG 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 * fpux_to_fpu
93 * Build a standard i386 FPU context from an extended one.
95 void fpux_to_fpu( I386_FLOATING_SAVE_AREA *fpu, const XMM_SAVE_AREA32 *fpux )
97 unsigned int i, tag, stack_top;
99 fpu->ControlWord = fpux->ControlWord;
100 fpu->StatusWord = fpux->StatusWord;
101 fpu->ErrorOffset = fpux->ErrorOffset;
102 fpu->ErrorSelector = fpux->ErrorSelector | (fpux->ErrorOpcode << 16);
103 fpu->DataOffset = fpux->DataOffset;
104 fpu->DataSelector = fpux->DataSelector;
105 fpu->Cr0NpxState = fpux->StatusWord | 0xffff0000;
107 stack_top = (fpux->StatusWord >> 11) & 7;
108 fpu->TagWord = 0xffff0000;
109 for (i = 0; i < 8; i++)
111 memcpy( &fpu->RegisterArea[10 * i], &fpux->FloatRegisters[i], 10 );
112 if (!(fpux->TagWord & (1 << i))) tag = 3; /* empty */
113 else
115 const M128A *reg = &fpux->FloatRegisters[(i - stack_top) & 7];
116 if ((reg->High & 0x7fff) == 0x7fff) /* exponent all ones */
118 tag = 2; /* special */
120 else if (!(reg->High & 0x7fff)) /* exponent all zeroes */
122 if (reg->Low) tag = 2; /* special */
123 else tag = 1; /* zero */
125 else
127 if (reg->Low >> 63) tag = 0; /* valid */
128 else tag = 2; /* special */
131 fpu->TagWord |= tag << (2 * i);
136 /***********************************************************************
137 * fpu_to_fpux
139 * Fill extended i386 FPU context from standard one.
141 void fpu_to_fpux( XMM_SAVE_AREA32 *fpux, const I386_FLOATING_SAVE_AREA *fpu )
143 unsigned int i;
145 fpux->ControlWord = fpu->ControlWord;
146 fpux->StatusWord = fpu->StatusWord;
147 fpux->ErrorOffset = fpu->ErrorOffset;
148 fpux->ErrorSelector = fpu->ErrorSelector;
149 fpux->ErrorOpcode = fpu->ErrorSelector >> 16;
150 fpux->DataOffset = fpu->DataOffset;
151 fpux->DataSelector = fpu->DataSelector;
152 fpux->TagWord = 0;
153 for (i = 0; i < 8; i++)
155 if (((fpu->TagWord >> (i * 2)) & 3) != 3) fpux->TagWord |= 1 << i;
156 memcpy( &fpux->FloatRegisters[i], &fpu->RegisterArea[10 * i], 10 );
161 /***********************************************************************
162 * get_server_context_flags
164 static unsigned int get_server_context_flags( const void *context, USHORT machine )
166 unsigned int flags, ret = 0;
168 switch (machine)
170 case IMAGE_FILE_MACHINE_I386:
171 flags = ((const I386_CONTEXT *)context)->ContextFlags & ~CONTEXT_i386;
172 if (flags & CONTEXT_I386_CONTROL) ret |= SERVER_CTX_CONTROL;
173 if (flags & CONTEXT_I386_INTEGER) ret |= SERVER_CTX_INTEGER;
174 if (flags & CONTEXT_I386_SEGMENTS) ret |= SERVER_CTX_SEGMENTS;
175 if (flags & CONTEXT_I386_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
176 if (flags & CONTEXT_I386_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
177 if (flags & CONTEXT_I386_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS | SERVER_CTX_FLOATING_POINT;
178 if (flags & CONTEXT_I386_XSTATE) ret |= SERVER_CTX_YMM_REGISTERS;
179 break;
180 case IMAGE_FILE_MACHINE_AMD64:
181 flags = ((const AMD64_CONTEXT *)context)->ContextFlags & ~CONTEXT_AMD64;
182 if (flags & CONTEXT_AMD64_CONTROL) ret |= SERVER_CTX_CONTROL;
183 if (flags & CONTEXT_AMD64_INTEGER) ret |= SERVER_CTX_INTEGER;
184 if (flags & CONTEXT_AMD64_SEGMENTS) ret |= SERVER_CTX_SEGMENTS;
185 if (flags & CONTEXT_AMD64_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
186 if (flags & CONTEXT_AMD64_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
187 if (flags & CONTEXT_AMD64_XSTATE) ret |= SERVER_CTX_YMM_REGISTERS;
188 break;
189 case IMAGE_FILE_MACHINE_ARMNT:
190 flags = ((const ARM_CONTEXT *)context)->ContextFlags & ~CONTEXT_ARM;
191 if (flags & CONTEXT_ARM_CONTROL) ret |= SERVER_CTX_CONTROL;
192 if (flags & CONTEXT_ARM_INTEGER) ret |= SERVER_CTX_INTEGER;
193 if (flags & CONTEXT_ARM_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
194 if (flags & CONTEXT_ARM_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
195 break;
196 case IMAGE_FILE_MACHINE_ARM64:
197 flags = ((const ARM64_NT_CONTEXT *)context)->ContextFlags & ~CONTEXT_ARM64;
198 if (flags & CONTEXT_ARM64_CONTROL) ret |= SERVER_CTX_CONTROL;
199 if (flags & CONTEXT_ARM64_INTEGER) ret |= SERVER_CTX_INTEGER;
200 if (flags & CONTEXT_ARM64_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
201 if (flags & CONTEXT_ARM64_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
202 break;
204 return ret;
208 /***********************************************************************
209 * get_native_context_flags
211 * Get flags for registers that are set from the native context in WoW mode.
213 static unsigned int get_native_context_flags( USHORT native_machine, USHORT wow_machine )
215 switch (MAKELONG( native_machine, wow_machine ))
217 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386 ):
218 return SERVER_CTX_DEBUG_REGISTERS | SERVER_CTX_FLOATING_POINT | SERVER_CTX_YMM_REGISTERS;
219 case MAKELONG( IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_ARMNT ):
220 return SERVER_CTX_DEBUG_REGISTERS | SERVER_CTX_FLOATING_POINT;
221 default:
222 return 0;
227 /***********************************************************************
228 * context_to_server
230 * Convert a register context to the server format.
232 static NTSTATUS context_to_server( context_t *to, USHORT to_machine, const void *src, USHORT from_machine )
234 DWORD i, flags;
236 memset( to, 0, sizeof(*to) );
237 to->machine = to_machine;
239 switch (MAKELONG( from_machine, to_machine ))
241 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_I386 ):
243 const I386_CONTEXT *from = src;
245 flags = from->ContextFlags & ~CONTEXT_i386;
246 if (flags & CONTEXT_I386_CONTROL)
248 to->flags |= SERVER_CTX_CONTROL;
249 to->ctl.i386_regs.ebp = from->Ebp;
250 to->ctl.i386_regs.esp = from->Esp;
251 to->ctl.i386_regs.eip = from->Eip;
252 to->ctl.i386_regs.cs = from->SegCs;
253 to->ctl.i386_regs.ss = from->SegSs;
254 to->ctl.i386_regs.eflags = from->EFlags;
256 if (flags & CONTEXT_I386_INTEGER)
258 to->flags |= SERVER_CTX_INTEGER;
259 to->integer.i386_regs.eax = from->Eax;
260 to->integer.i386_regs.ebx = from->Ebx;
261 to->integer.i386_regs.ecx = from->Ecx;
262 to->integer.i386_regs.edx = from->Edx;
263 to->integer.i386_regs.esi = from->Esi;
264 to->integer.i386_regs.edi = from->Edi;
266 if (flags & CONTEXT_I386_SEGMENTS)
268 to->flags |= SERVER_CTX_SEGMENTS;
269 to->seg.i386_regs.ds = from->SegDs;
270 to->seg.i386_regs.es = from->SegEs;
271 to->seg.i386_regs.fs = from->SegFs;
272 to->seg.i386_regs.gs = from->SegGs;
274 if (flags & CONTEXT_I386_FLOATING_POINT)
276 to->flags |= SERVER_CTX_FLOATING_POINT;
277 to->fp.i386_regs.ctrl = from->FloatSave.ControlWord;
278 to->fp.i386_regs.status = from->FloatSave.StatusWord;
279 to->fp.i386_regs.tag = from->FloatSave.TagWord;
280 to->fp.i386_regs.err_off = from->FloatSave.ErrorOffset;
281 to->fp.i386_regs.err_sel = from->FloatSave.ErrorSelector;
282 to->fp.i386_regs.data_off = from->FloatSave.DataOffset;
283 to->fp.i386_regs.data_sel = from->FloatSave.DataSelector;
284 to->fp.i386_regs.cr0npx = from->FloatSave.Cr0NpxState;
285 memcpy( to->fp.i386_regs.regs, from->FloatSave.RegisterArea, sizeof(to->fp.i386_regs.regs) );
287 if (flags & CONTEXT_I386_DEBUG_REGISTERS)
289 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
290 to->debug.i386_regs.dr0 = from->Dr0;
291 to->debug.i386_regs.dr1 = from->Dr1;
292 to->debug.i386_regs.dr2 = from->Dr2;
293 to->debug.i386_regs.dr3 = from->Dr3;
294 to->debug.i386_regs.dr6 = from->Dr6;
295 to->debug.i386_regs.dr7 = from->Dr7;
297 if (flags & CONTEXT_I386_EXTENDED_REGISTERS)
299 to->flags |= SERVER_CTX_EXTENDED_REGISTERS;
300 memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) );
302 if (flags & CONTEXT_I386_XSTATE)
304 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
305 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
307 to->flags |= SERVER_CTX_YMM_REGISTERS;
308 if (xs->Mask & 4) memcpy( &to->ymm.regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
310 return STATUS_SUCCESS;
313 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_AMD64 ):
315 const I386_CONTEXT *from = src;
317 flags = from->ContextFlags & ~CONTEXT_i386;
318 if (flags & CONTEXT_I386_CONTROL)
320 to->flags |= SERVER_CTX_CONTROL;
321 to->ctl.x86_64_regs.rbp = from->Ebp;
322 to->ctl.x86_64_regs.rsp = from->Esp;
323 to->ctl.x86_64_regs.rip = from->Eip;
324 to->ctl.x86_64_regs.cs = from->SegCs;
325 to->ctl.x86_64_regs.ss = from->SegSs;
326 to->ctl.x86_64_regs.flags = from->EFlags;
328 if (flags & CONTEXT_I386_INTEGER)
330 to->flags |= SERVER_CTX_INTEGER;
331 to->integer.x86_64_regs.rax = from->Eax;
332 to->integer.x86_64_regs.rbx = from->Ebx;
333 to->integer.x86_64_regs.rcx = from->Ecx;
334 to->integer.x86_64_regs.rdx = from->Edx;
335 to->integer.x86_64_regs.rsi = from->Esi;
336 to->integer.x86_64_regs.rdi = from->Edi;
338 if (flags & CONTEXT_I386_SEGMENTS)
340 to->flags |= SERVER_CTX_SEGMENTS;
341 to->seg.x86_64_regs.ds = from->SegDs;
342 to->seg.x86_64_regs.es = from->SegEs;
343 to->seg.x86_64_regs.fs = from->SegFs;
344 to->seg.x86_64_regs.gs = from->SegGs;
346 if (flags & CONTEXT_I386_DEBUG_REGISTERS)
348 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
349 to->debug.x86_64_regs.dr0 = from->Dr0;
350 to->debug.x86_64_regs.dr1 = from->Dr1;
351 to->debug.x86_64_regs.dr2 = from->Dr2;
352 to->debug.x86_64_regs.dr3 = from->Dr3;
353 to->debug.x86_64_regs.dr6 = from->Dr6;
354 to->debug.x86_64_regs.dr7 = from->Dr7;
356 if (flags & CONTEXT_I386_EXTENDED_REGISTERS)
358 to->flags |= SERVER_CTX_FLOATING_POINT;
359 memcpy( to->fp.x86_64_regs.fpregs, from->ExtendedRegisters, sizeof(to->fp.x86_64_regs.fpregs) );
361 else if (flags & CONTEXT_I386_FLOATING_POINT)
363 to->flags |= SERVER_CTX_FLOATING_POINT;
364 fpu_to_fpux( (XMM_SAVE_AREA32 *)to->fp.x86_64_regs.fpregs, &from->FloatSave );
366 if (flags & CONTEXT_I386_XSTATE)
368 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
369 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
371 to->flags |= SERVER_CTX_YMM_REGISTERS;
372 if (xs->Mask & 4) memcpy( &to->ymm.regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
374 return STATUS_SUCCESS;
377 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_AMD64 ):
379 const AMD64_CONTEXT *from = src;
381 flags = from->ContextFlags & ~CONTEXT_AMD64;
382 if (flags & CONTEXT_AMD64_CONTROL)
384 to->flags |= SERVER_CTX_CONTROL;
385 to->ctl.x86_64_regs.rbp = from->Rbp;
386 to->ctl.x86_64_regs.rip = from->Rip;
387 to->ctl.x86_64_regs.rsp = from->Rsp;
388 to->ctl.x86_64_regs.cs = from->SegCs;
389 to->ctl.x86_64_regs.ss = from->SegSs;
390 to->ctl.x86_64_regs.flags = from->EFlags;
392 if (flags & CONTEXT_AMD64_INTEGER)
394 to->flags |= SERVER_CTX_INTEGER;
395 to->integer.x86_64_regs.rax = from->Rax;
396 to->integer.x86_64_regs.rcx = from->Rcx;
397 to->integer.x86_64_regs.rdx = from->Rdx;
398 to->integer.x86_64_regs.rbx = from->Rbx;
399 to->integer.x86_64_regs.rsi = from->Rsi;
400 to->integer.x86_64_regs.rdi = from->Rdi;
401 to->integer.x86_64_regs.r8 = from->R8;
402 to->integer.x86_64_regs.r9 = from->R9;
403 to->integer.x86_64_regs.r10 = from->R10;
404 to->integer.x86_64_regs.r11 = from->R11;
405 to->integer.x86_64_regs.r12 = from->R12;
406 to->integer.x86_64_regs.r13 = from->R13;
407 to->integer.x86_64_regs.r14 = from->R14;
408 to->integer.x86_64_regs.r15 = from->R15;
410 if (flags & CONTEXT_AMD64_SEGMENTS)
412 to->flags |= SERVER_CTX_SEGMENTS;
413 to->seg.x86_64_regs.ds = from->SegDs;
414 to->seg.x86_64_regs.es = from->SegEs;
415 to->seg.x86_64_regs.fs = from->SegFs;
416 to->seg.x86_64_regs.gs = from->SegGs;
418 if (flags & CONTEXT_AMD64_FLOATING_POINT)
420 to->flags |= SERVER_CTX_FLOATING_POINT;
421 memcpy( to->fp.x86_64_regs.fpregs, &from->FltSave, sizeof(to->fp.x86_64_regs.fpregs) );
423 if (flags & CONTEXT_AMD64_DEBUG_REGISTERS)
425 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
426 to->debug.x86_64_regs.dr0 = from->Dr0;
427 to->debug.x86_64_regs.dr1 = from->Dr1;
428 to->debug.x86_64_regs.dr2 = from->Dr2;
429 to->debug.x86_64_regs.dr3 = from->Dr3;
430 to->debug.x86_64_regs.dr6 = from->Dr6;
431 to->debug.x86_64_regs.dr7 = from->Dr7;
433 if (flags & CONTEXT_AMD64_XSTATE)
435 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
436 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
438 to->flags |= SERVER_CTX_YMM_REGISTERS;
439 if (xs->Mask & 4) memcpy( &to->ymm.regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
441 return STATUS_SUCCESS;
444 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386 ):
446 const AMD64_CONTEXT *from = src;
448 flags = from->ContextFlags & ~CONTEXT_AMD64;
449 if (flags & CONTEXT_AMD64_CONTROL)
451 to->flags |= SERVER_CTX_CONTROL;
452 to->ctl.i386_regs.ebp = from->Rbp;
453 to->ctl.i386_regs.eip = from->Rip;
454 to->ctl.i386_regs.esp = from->Rsp;
455 to->ctl.i386_regs.cs = from->SegCs;
456 to->ctl.i386_regs.ss = from->SegSs;
457 to->ctl.i386_regs.eflags = from->EFlags;
459 if (flags & CONTEXT_AMD64_INTEGER)
461 to->flags |= SERVER_CTX_INTEGER;
462 to->integer.i386_regs.eax = from->Rax;
463 to->integer.i386_regs.ecx = from->Rcx;
464 to->integer.i386_regs.edx = from->Rdx;
465 to->integer.i386_regs.ebx = from->Rbx;
466 to->integer.i386_regs.esi = from->Rsi;
467 to->integer.i386_regs.edi = from->Rdi;
469 if (flags & CONTEXT_AMD64_SEGMENTS)
471 to->flags |= SERVER_CTX_SEGMENTS;
472 to->seg.i386_regs.ds = from->SegDs;
473 to->seg.i386_regs.es = from->SegEs;
474 to->seg.i386_regs.fs = from->SegFs;
475 to->seg.i386_regs.gs = from->SegGs;
477 if (flags & CONTEXT_AMD64_FLOATING_POINT)
479 I386_FLOATING_SAVE_AREA fpu;
481 to->flags |= SERVER_CTX_EXTENDED_REGISTERS | SERVER_CTX_FLOATING_POINT;
482 memcpy( to->ext.i386_regs, &from->FltSave, sizeof(to->ext.i386_regs) );
483 fpux_to_fpu( &fpu, &from->FltSave );
484 to->fp.i386_regs.ctrl = fpu.ControlWord;
485 to->fp.i386_regs.status = fpu.StatusWord;
486 to->fp.i386_regs.tag = fpu.TagWord;
487 to->fp.i386_regs.err_off = fpu.ErrorOffset;
488 to->fp.i386_regs.err_sel = fpu.ErrorSelector;
489 to->fp.i386_regs.data_off = fpu.DataOffset;
490 to->fp.i386_regs.data_sel = fpu.DataSelector;
491 to->fp.i386_regs.cr0npx = fpu.Cr0NpxState;
492 memcpy( to->fp.i386_regs.regs, fpu.RegisterArea, sizeof(to->fp.i386_regs.regs) );
494 if (flags & CONTEXT_AMD64_DEBUG_REGISTERS)
496 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
497 to->debug.i386_regs.dr0 = from->Dr0;
498 to->debug.i386_regs.dr1 = from->Dr1;
499 to->debug.i386_regs.dr2 = from->Dr2;
500 to->debug.i386_regs.dr3 = from->Dr3;
501 to->debug.i386_regs.dr6 = from->Dr6;
502 to->debug.i386_regs.dr7 = from->Dr7;
504 if (flags & CONTEXT_AMD64_XSTATE)
506 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
507 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
509 to->flags |= SERVER_CTX_YMM_REGISTERS;
510 if (xs->Mask & 4) memcpy( &to->ymm.regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
512 return STATUS_SUCCESS;
515 case MAKELONG( IMAGE_FILE_MACHINE_ARMNT, IMAGE_FILE_MACHINE_ARMNT ):
517 const ARM_CONTEXT *from = src;
519 flags = from->ContextFlags & ~CONTEXT_ARM;
520 if (flags & CONTEXT_ARM_CONTROL)
522 to->flags |= SERVER_CTX_CONTROL;
523 to->ctl.arm_regs.sp = from->Sp;
524 to->ctl.arm_regs.lr = from->Lr;
525 to->ctl.arm_regs.pc = from->Pc;
526 to->ctl.arm_regs.cpsr = from->Cpsr;
528 if (flags & CONTEXT_ARM_INTEGER)
530 to->flags |= SERVER_CTX_INTEGER;
531 to->integer.arm_regs.r[0] = from->R0;
532 to->integer.arm_regs.r[1] = from->R1;
533 to->integer.arm_regs.r[2] = from->R2;
534 to->integer.arm_regs.r[3] = from->R3;
535 to->integer.arm_regs.r[4] = from->R4;
536 to->integer.arm_regs.r[5] = from->R5;
537 to->integer.arm_regs.r[6] = from->R6;
538 to->integer.arm_regs.r[7] = from->R7;
539 to->integer.arm_regs.r[8] = from->R8;
540 to->integer.arm_regs.r[9] = from->R9;
541 to->integer.arm_regs.r[10] = from->R10;
542 to->integer.arm_regs.r[11] = from->R11;
543 to->integer.arm_regs.r[12] = from->R12;
545 if (flags & CONTEXT_ARM_FLOATING_POINT)
547 to->flags |= SERVER_CTX_FLOATING_POINT;
548 for (i = 0; i < 32; i++) to->fp.arm_regs.d[i] = from->D[i];
549 to->fp.arm_regs.fpscr = from->Fpscr;
551 if (flags & CONTEXT_ARM_DEBUG_REGISTERS)
553 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
554 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bvr[i] = from->Bvr[i];
555 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bcr[i] = from->Bcr[i];
556 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wvr[i] = from->Wvr[i];
557 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wcr[i] = from->Wcr[i];
559 return STATUS_SUCCESS;
562 case MAKELONG( IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_ARM64 ):
564 const ARM64_NT_CONTEXT *from = src;
566 flags = from->ContextFlags & ~CONTEXT_ARM64;
567 if (flags & CONTEXT_ARM64_CONTROL)
569 to->flags |= SERVER_CTX_CONTROL;
570 to->integer.arm64_regs.x[29] = from->Fp;
571 to->integer.arm64_regs.x[30] = from->Lr;
572 to->ctl.arm64_regs.sp = from->Sp;
573 to->ctl.arm64_regs.pc = from->Pc;
574 to->ctl.arm64_regs.pstate = from->Cpsr;
576 if (flags & CONTEXT_ARM64_INTEGER)
578 to->flags |= SERVER_CTX_INTEGER;
579 for (i = 0; i <= 28; i++) to->integer.arm64_regs.x[i] = from->X[i];
581 if (flags & CONTEXT_ARM64_FLOATING_POINT)
583 to->flags |= SERVER_CTX_FLOATING_POINT;
584 for (i = 0; i < 32; i++)
586 to->fp.arm64_regs.q[i].low = from->V[i].Low;
587 to->fp.arm64_regs.q[i].high = from->V[i].High;
589 to->fp.arm64_regs.fpcr = from->Fpcr;
590 to->fp.arm64_regs.fpsr = from->Fpsr;
592 if (flags & CONTEXT_ARM64_DEBUG_REGISTERS)
594 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
595 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bcr[i] = from->Bcr[i];
596 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bvr[i] = from->Bvr[i];
597 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wcr[i] = from->Wcr[i];
598 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wvr[i] = from->Wvr[i];
600 return STATUS_SUCCESS;
603 case MAKELONG( IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_I386 ):
604 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_ARM64 ):
605 return STATUS_SUCCESS;
607 default:
608 return STATUS_INVALID_PARAMETER;
613 /***********************************************************************
614 * context_from_server
616 * Convert a register context from the server format.
618 static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT machine )
620 DWORD i, to_flags;
622 switch (MAKELONG( from->machine, machine ))
624 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_I386 ):
626 I386_CONTEXT *to = dst;
628 to_flags = to->ContextFlags & ~CONTEXT_i386;
629 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_I386_CONTROL))
631 to->ContextFlags |= CONTEXT_I386_CONTROL;
632 to->Ebp = from->ctl.i386_regs.ebp;
633 to->Esp = from->ctl.i386_regs.esp;
634 to->Eip = from->ctl.i386_regs.eip;
635 to->SegCs = from->ctl.i386_regs.cs;
636 to->SegSs = from->ctl.i386_regs.ss;
637 to->EFlags = from->ctl.i386_regs.eflags;
639 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_I386_INTEGER))
641 to->ContextFlags |= CONTEXT_I386_INTEGER;
642 to->Eax = from->integer.i386_regs.eax;
643 to->Ebx = from->integer.i386_regs.ebx;
644 to->Ecx = from->integer.i386_regs.ecx;
645 to->Edx = from->integer.i386_regs.edx;
646 to->Esi = from->integer.i386_regs.esi;
647 to->Edi = from->integer.i386_regs.edi;
649 if ((from->flags & SERVER_CTX_SEGMENTS) && (to_flags & CONTEXT_I386_SEGMENTS))
651 to->ContextFlags |= CONTEXT_I386_SEGMENTS;
652 to->SegDs = from->seg.i386_regs.ds;
653 to->SegEs = from->seg.i386_regs.es;
654 to->SegFs = from->seg.i386_regs.fs;
655 to->SegGs = from->seg.i386_regs.gs;
657 if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_I386_FLOATING_POINT))
659 to->ContextFlags |= CONTEXT_I386_FLOATING_POINT;
660 to->FloatSave.ControlWord = from->fp.i386_regs.ctrl;
661 to->FloatSave.StatusWord = from->fp.i386_regs.status;
662 to->FloatSave.TagWord = from->fp.i386_regs.tag;
663 to->FloatSave.ErrorOffset = from->fp.i386_regs.err_off;
664 to->FloatSave.ErrorSelector = from->fp.i386_regs.err_sel;
665 to->FloatSave.DataOffset = from->fp.i386_regs.data_off;
666 to->FloatSave.DataSelector = from->fp.i386_regs.data_sel;
667 to->FloatSave.Cr0NpxState = from->fp.i386_regs.cr0npx;
668 memcpy( to->FloatSave.RegisterArea, from->fp.i386_regs.regs, sizeof(to->FloatSave.RegisterArea) );
670 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_I386_DEBUG_REGISTERS))
672 to->ContextFlags |= CONTEXT_I386_DEBUG_REGISTERS;
673 to->Dr0 = from->debug.i386_regs.dr0;
674 to->Dr1 = from->debug.i386_regs.dr1;
675 to->Dr2 = from->debug.i386_regs.dr2;
676 to->Dr3 = from->debug.i386_regs.dr3;
677 to->Dr6 = from->debug.i386_regs.dr6;
678 to->Dr7 = from->debug.i386_regs.dr7;
680 if ((from->flags & SERVER_CTX_EXTENDED_REGISTERS) && (to_flags & CONTEXT_I386_EXTENDED_REGISTERS))
682 to->ContextFlags |= CONTEXT_I386_EXTENDED_REGISTERS;
683 memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) );
685 if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_I386_XSTATE))
687 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
688 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
690 xs->Mask &= ~4;
691 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
692 for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++)
694 if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue;
695 memcpy( &xs->YmmContext, &from->ymm.regs, sizeof(xs->YmmContext) );
696 xs->Mask |= 4;
697 break;
700 return STATUS_SUCCESS;
703 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386 ):
705 I386_CONTEXT *to = dst;
707 to_flags = to->ContextFlags & ~CONTEXT_i386;
708 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_I386_CONTROL))
710 to->ContextFlags |= CONTEXT_I386_CONTROL;
711 to->Ebp = from->ctl.x86_64_regs.rbp;
712 to->Esp = from->ctl.x86_64_regs.rsp;
713 to->Eip = from->ctl.x86_64_regs.rip;
714 to->SegCs = from->ctl.x86_64_regs.cs;
715 to->SegSs = from->ctl.x86_64_regs.ss;
716 to->EFlags = from->ctl.x86_64_regs.flags;
718 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_I386_INTEGER))
720 to->ContextFlags |= CONTEXT_I386_INTEGER;
721 to->Eax = from->integer.x86_64_regs.rax;
722 to->Ebx = from->integer.x86_64_regs.rbx;
723 to->Ecx = from->integer.x86_64_regs.rcx;
724 to->Edx = from->integer.x86_64_regs.rdx;
725 to->Esi = from->integer.x86_64_regs.rsi;
726 to->Edi = from->integer.x86_64_regs.rdi;
728 if ((from->flags & SERVER_CTX_SEGMENTS) && (to_flags & CONTEXT_I386_SEGMENTS))
730 to->ContextFlags |= CONTEXT_I386_SEGMENTS;
731 to->SegDs = from->seg.x86_64_regs.ds;
732 to->SegEs = from->seg.x86_64_regs.es;
733 to->SegFs = from->seg.x86_64_regs.fs;
734 to->SegGs = from->seg.x86_64_regs.gs;
736 if (from->flags & SERVER_CTX_FLOATING_POINT)
738 if (to_flags & CONTEXT_I386_EXTENDED_REGISTERS)
740 to->ContextFlags |= CONTEXT_I386_EXTENDED_REGISTERS;
741 memcpy( to->ExtendedRegisters, from->fp.x86_64_regs.fpregs, sizeof(to->ExtendedRegisters) );
743 if (to_flags & CONTEXT_I386_FLOATING_POINT)
745 to->ContextFlags |= CONTEXT_I386_FLOATING_POINT;
746 fpux_to_fpu( &to->FloatSave, (XMM_SAVE_AREA32 *)from->fp.x86_64_regs.fpregs );
749 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_I386_DEBUG_REGISTERS))
751 to->ContextFlags |= CONTEXT_I386_DEBUG_REGISTERS;
752 to->Dr0 = from->debug.x86_64_regs.dr0;
753 to->Dr1 = from->debug.x86_64_regs.dr1;
754 to->Dr2 = from->debug.x86_64_regs.dr2;
755 to->Dr3 = from->debug.x86_64_regs.dr3;
756 to->Dr6 = from->debug.x86_64_regs.dr6;
757 to->Dr7 = from->debug.x86_64_regs.dr7;
759 if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_I386_XSTATE))
761 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
762 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
764 xs->Mask &= ~4;
765 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
766 for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++)
768 if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue;
769 memcpy( &xs->YmmContext, &from->ymm.regs, sizeof(xs->YmmContext) );
770 xs->Mask |= 4;
771 break;
774 return STATUS_SUCCESS;
777 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_AMD64 ):
779 AMD64_CONTEXT *to = dst;
781 to_flags = to->ContextFlags & ~CONTEXT_AMD64;
782 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_AMD64_CONTROL))
784 to->ContextFlags |= CONTEXT_AMD64_CONTROL;
785 to->Rbp = from->ctl.x86_64_regs.rbp;
786 to->Rip = from->ctl.x86_64_regs.rip;
787 to->Rsp = from->ctl.x86_64_regs.rsp;
788 to->SegCs = from->ctl.x86_64_regs.cs;
789 to->SegSs = from->ctl.x86_64_regs.ss;
790 to->EFlags = from->ctl.x86_64_regs.flags;
792 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_AMD64_INTEGER))
794 to->ContextFlags |= CONTEXT_AMD64_INTEGER;
795 to->Rax = from->integer.x86_64_regs.rax;
796 to->Rcx = from->integer.x86_64_regs.rcx;
797 to->Rdx = from->integer.x86_64_regs.rdx;
798 to->Rbx = from->integer.x86_64_regs.rbx;
799 to->Rsi = from->integer.x86_64_regs.rsi;
800 to->Rdi = from->integer.x86_64_regs.rdi;
801 to->R8 = from->integer.x86_64_regs.r8;
802 to->R9 = from->integer.x86_64_regs.r9;
803 to->R10 = from->integer.x86_64_regs.r10;
804 to->R11 = from->integer.x86_64_regs.r11;
805 to->R12 = from->integer.x86_64_regs.r12;
806 to->R13 = from->integer.x86_64_regs.r13;
807 to->R14 = from->integer.x86_64_regs.r14;
808 to->R15 = from->integer.x86_64_regs.r15;
810 if ((from->flags & SERVER_CTX_SEGMENTS) && (to_flags & CONTEXT_AMD64_SEGMENTS))
812 to->ContextFlags |= CONTEXT_AMD64_SEGMENTS;
813 to->SegDs = from->seg.x86_64_regs.ds;
814 to->SegEs = from->seg.x86_64_regs.es;
815 to->SegFs = from->seg.x86_64_regs.fs;
816 to->SegGs = from->seg.x86_64_regs.gs;
818 if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_AMD64_FLOATING_POINT))
820 to->ContextFlags |= CONTEXT_AMD64_FLOATING_POINT;
821 memcpy( &to->FltSave, from->fp.x86_64_regs.fpregs, sizeof(from->fp.x86_64_regs.fpregs) );
822 to->MxCsr = to->FltSave.MxCsr;
824 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_AMD64_DEBUG_REGISTERS))
826 to->ContextFlags |= CONTEXT_AMD64_DEBUG_REGISTERS;
827 to->Dr0 = from->debug.x86_64_regs.dr0;
828 to->Dr1 = from->debug.x86_64_regs.dr1;
829 to->Dr2 = from->debug.x86_64_regs.dr2;
830 to->Dr3 = from->debug.x86_64_regs.dr3;
831 to->Dr6 = from->debug.x86_64_regs.dr6;
832 to->Dr7 = from->debug.x86_64_regs.dr7;
834 if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_AMD64_XSTATE))
836 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
837 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
839 xs->Mask &= ~4;
840 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
841 for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++)
843 if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue;
844 memcpy( &xs->YmmContext, &from->ymm.regs, sizeof(xs->YmmContext) );
845 xs->Mask |= 4;
846 break;
849 return STATUS_SUCCESS;
852 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_AMD64 ):
854 AMD64_CONTEXT *to = dst;
856 to_flags = to->ContextFlags & ~CONTEXT_AMD64;
857 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_AMD64_CONTROL))
859 to->ContextFlags |= CONTEXT_AMD64_CONTROL;
860 to->Rbp = from->ctl.i386_regs.ebp;
861 to->Rip = from->ctl.i386_regs.eip;
862 to->Rsp = from->ctl.i386_regs.esp;
863 to->SegCs = from->ctl.i386_regs.cs;
864 to->SegSs = from->ctl.i386_regs.ss;
865 to->EFlags = from->ctl.i386_regs.eflags;
867 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_AMD64_INTEGER))
869 to->ContextFlags |= CONTEXT_AMD64_INTEGER;
870 to->Rax = from->integer.i386_regs.eax;
871 to->Rcx = from->integer.i386_regs.ecx;
872 to->Rdx = from->integer.i386_regs.edx;
873 to->Rbx = from->integer.i386_regs.ebx;
874 to->Rsi = from->integer.i386_regs.esi;
875 to->Rdi = from->integer.i386_regs.edi;
877 if ((from->flags & SERVER_CTX_SEGMENTS) && (to_flags & CONTEXT_AMD64_SEGMENTS))
879 to->ContextFlags |= CONTEXT_AMD64_SEGMENTS;
880 to->SegDs = from->seg.i386_regs.ds;
881 to->SegEs = from->seg.i386_regs.es;
882 to->SegFs = from->seg.i386_regs.fs;
883 to->SegGs = from->seg.i386_regs.gs;
885 if ((from->flags & SERVER_CTX_EXTENDED_REGISTERS) && (to_flags & CONTEXT_AMD64_FLOATING_POINT))
887 to->ContextFlags |= CONTEXT_AMD64_FLOATING_POINT;
888 memcpy( &to->FltSave, from->ext.i386_regs, sizeof(to->FltSave) );
890 else if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_AMD64_FLOATING_POINT))
892 I386_FLOATING_SAVE_AREA fpu;
894 to->ContextFlags |= CONTEXT_AMD64_FLOATING_POINT;
895 fpu.ControlWord = from->fp.i386_regs.ctrl;
896 fpu.StatusWord = from->fp.i386_regs.status;
897 fpu.TagWord = from->fp.i386_regs.tag;
898 fpu.ErrorOffset = from->fp.i386_regs.err_off;
899 fpu.ErrorSelector = from->fp.i386_regs.err_sel;
900 fpu.DataOffset = from->fp.i386_regs.data_off;
901 fpu.DataSelector = from->fp.i386_regs.data_sel;
902 fpu.Cr0NpxState = from->fp.i386_regs.cr0npx;
903 memcpy( fpu.RegisterArea, from->fp.i386_regs.regs, sizeof(fpu.RegisterArea) );
904 fpu_to_fpux( &to->FltSave, &fpu );
906 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_AMD64_DEBUG_REGISTERS))
908 to->ContextFlags |= CONTEXT_AMD64_DEBUG_REGISTERS;
909 to->Dr0 = from->debug.i386_regs.dr0;
910 to->Dr1 = from->debug.i386_regs.dr1;
911 to->Dr2 = from->debug.i386_regs.dr2;
912 to->Dr3 = from->debug.i386_regs.dr3;
913 to->Dr6 = from->debug.i386_regs.dr6;
914 to->Dr7 = from->debug.i386_regs.dr7;
916 if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_AMD64_XSTATE))
918 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
919 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
921 xs->Mask &= ~4;
922 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
923 for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++)
925 if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue;
926 memcpy( &xs->YmmContext, &from->ymm.regs, sizeof(xs->YmmContext) );
927 xs->Mask |= 4;
928 break;
931 return STATUS_SUCCESS;
934 case MAKELONG( IMAGE_FILE_MACHINE_ARMNT, IMAGE_FILE_MACHINE_ARMNT ):
936 ARM_CONTEXT *to = dst;
938 to_flags = to->ContextFlags & ~CONTEXT_ARM;
939 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_ARM_CONTROL))
941 to->ContextFlags |= CONTEXT_ARM_CONTROL;
942 to->Sp = from->ctl.arm_regs.sp;
943 to->Lr = from->ctl.arm_regs.lr;
944 to->Pc = from->ctl.arm_regs.pc;
945 to->Cpsr = from->ctl.arm_regs.cpsr;
947 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_ARM_INTEGER))
949 to->ContextFlags |= CONTEXT_ARM_INTEGER;
950 to->R0 = from->integer.arm_regs.r[0];
951 to->R1 = from->integer.arm_regs.r[1];
952 to->R2 = from->integer.arm_regs.r[2];
953 to->R3 = from->integer.arm_regs.r[3];
954 to->R4 = from->integer.arm_regs.r[4];
955 to->R5 = from->integer.arm_regs.r[5];
956 to->R6 = from->integer.arm_regs.r[6];
957 to->R7 = from->integer.arm_regs.r[7];
958 to->R8 = from->integer.arm_regs.r[8];
959 to->R9 = from->integer.arm_regs.r[9];
960 to->R10 = from->integer.arm_regs.r[10];
961 to->R11 = from->integer.arm_regs.r[11];
962 to->R12 = from->integer.arm_regs.r[12];
964 if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_ARM_FLOATING_POINT))
966 to->ContextFlags |= CONTEXT_ARM_FLOATING_POINT;
967 for (i = 0; i < 32; i++) to->D[i] = from->fp.arm_regs.d[i];
968 to->Fpscr = from->fp.arm_regs.fpscr;
970 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_ARM_DEBUG_REGISTERS))
972 to->ContextFlags |= CONTEXT_ARM_DEBUG_REGISTERS;
973 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm_regs.bvr[i];
974 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm_regs.bcr[i];
975 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm_regs.wvr[i];
976 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm_regs.wcr[i];
978 return STATUS_SUCCESS;
981 case MAKELONG( IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_ARM64 ):
983 ARM64_NT_CONTEXT *to = dst;
985 to_flags = to->ContextFlags & ~CONTEXT_ARM64;
986 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_ARM64_CONTROL))
988 to->ContextFlags |= CONTEXT_ARM64_CONTROL;
989 to->Fp = from->integer.arm64_regs.x[29];
990 to->Lr = from->integer.arm64_regs.x[30];
991 to->Sp = from->ctl.arm64_regs.sp;
992 to->Pc = from->ctl.arm64_regs.pc;
993 to->Cpsr = from->ctl.arm64_regs.pstate;
995 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_ARM64_INTEGER))
997 to->ContextFlags |= CONTEXT_ARM64_INTEGER;
998 for (i = 0; i <= 28; i++) to->X[i] = from->integer.arm64_regs.x[i];
1000 if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_ARM64_FLOATING_POINT))
1002 to->ContextFlags |= CONTEXT_ARM64_FLOATING_POINT;
1003 for (i = 0; i < 32; i++)
1005 to->V[i].Low = from->fp.arm64_regs.q[i].low;
1006 to->V[i].High = from->fp.arm64_regs.q[i].high;
1008 to->Fpcr = from->fp.arm64_regs.fpcr;
1009 to->Fpsr = from->fp.arm64_regs.fpsr;
1011 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_ARM64_DEBUG_REGISTERS))
1013 to->ContextFlags |= CONTEXT_ARM64_DEBUG_REGISTERS;
1014 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm64_regs.bcr[i];
1015 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm64_regs.bvr[i];
1016 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm64_regs.wcr[i];
1017 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm64_regs.wvr[i];
1019 return STATUS_SUCCESS;
1022 case MAKELONG( IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_I386 ):
1023 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_ARM64 ):
1024 return STATUS_SUCCESS;
1026 default:
1027 return STATUS_INVALID_PARAMETER;
1032 /***********************************************************************
1033 * contexts_to_server
1035 static void contexts_to_server( context_t server_contexts[2], CONTEXT *context )
1037 unsigned int count = 0;
1038 void *native_context = get_native_context( context );
1039 void *wow_context = get_wow_context( context );
1041 if (native_context)
1043 context_to_server( &server_contexts[count++], native_machine, native_context, native_machine );
1044 if (wow_context) context_to_server( &server_contexts[count++], main_image_info.Machine,
1045 wow_context, main_image_info.Machine );
1046 else if (native_machine != main_image_info.Machine)
1047 context_to_server( &server_contexts[count++], main_image_info.Machine,
1048 native_context, native_machine );
1050 else
1051 context_to_server( &server_contexts[count++], native_machine,
1052 wow_context, main_image_info.Machine );
1054 if (count < 2) memset( &server_contexts[1], 0, sizeof(server_contexts[1]) );
1058 /***********************************************************************
1059 * contexts_from_server
1061 static void contexts_from_server( CONTEXT *context, context_t server_contexts[2] )
1063 void *native_context = get_native_context( context );
1064 void *wow_context = get_wow_context( context );
1066 if (native_context)
1068 context_from_server( native_context, &server_contexts[0], native_machine );
1069 if (wow_context)
1070 context_from_server( wow_context, &server_contexts[1], main_image_info.Machine );
1071 else
1072 context_from_server( native_context, &server_contexts[1], native_machine );
1074 else context_from_server( wow_context, &server_contexts[0], main_image_info.Machine );
1078 /***********************************************************************
1079 * pthread_exit_wrapper
1081 static void pthread_exit_wrapper( int status )
1083 close( ntdll_get_thread_data()->wait_fd[0] );
1084 close( ntdll_get_thread_data()->wait_fd[1] );
1085 close( ntdll_get_thread_data()->reply_fd );
1086 close( ntdll_get_thread_data()->request_fd );
1087 pthread_exit( UIntToPtr(status) );
1091 /***********************************************************************
1092 * start_thread
1094 * Startup routine for a newly created thread.
1096 static void start_thread( TEB *teb )
1098 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1099 BOOL suspend;
1101 thread_data->pthread_id = pthread_self();
1102 pthread_setspecific( teb_key, teb );
1103 server_init_thread( thread_data->start, &suspend );
1104 signal_start_thread( thread_data->start, thread_data->param, suspend, teb );
1108 /***********************************************************************
1109 * get_machine_context_size
1111 static SIZE_T get_machine_context_size( USHORT machine )
1113 switch (machine)
1115 case IMAGE_FILE_MACHINE_I386: return sizeof(I386_CONTEXT);
1116 case IMAGE_FILE_MACHINE_ARMNT: return sizeof(ARM_CONTEXT);
1117 case IMAGE_FILE_MACHINE_AMD64: return sizeof(AMD64_CONTEXT);
1118 case IMAGE_FILE_MACHINE_ARM64: return sizeof(ARM64_NT_CONTEXT);
1119 default: return 0;
1124 /***********************************************************************
1125 * get_cpu_area
1127 * cf. RtlWow64GetCurrentCpuArea
1129 void *get_cpu_area( USHORT machine )
1131 WOW64_CPURESERVED *cpu;
1132 ULONG align;
1134 if (!is_wow64()) return NULL;
1135 #ifdef _WIN64
1136 cpu = NtCurrentTeb()->TlsSlots[WOW64_TLS_CPURESERVED];
1137 #else
1138 cpu = ULongToPtr( NtCurrentTeb64()->TlsSlots[WOW64_TLS_CPURESERVED] );
1139 #endif
1140 if (cpu->Machine != machine) return NULL;
1141 switch (cpu->Machine)
1143 case IMAGE_FILE_MACHINE_I386: align = TYPE_ALIGNMENT(I386_CONTEXT); break;
1144 case IMAGE_FILE_MACHINE_AMD64: align = TYPE_ALIGNMENT(AMD64_CONTEXT); break;
1145 case IMAGE_FILE_MACHINE_ARMNT: align = TYPE_ALIGNMENT(ARM_CONTEXT); break;
1146 case IMAGE_FILE_MACHINE_ARM64: align = TYPE_ALIGNMENT(ARM64_NT_CONTEXT); break;
1147 default: return NULL;
1149 return (void *)(((ULONG_PTR)(cpu + 1) + align - 1) & ~((ULONG_PTR)align - 1));
1153 /***********************************************************************
1154 * set_thread_id
1156 void set_thread_id( TEB *teb, DWORD pid, DWORD tid )
1158 WOW_TEB *wow_teb = get_wow_teb( teb );
1160 teb->ClientId.UniqueProcess = ULongToHandle( pid );
1161 teb->ClientId.UniqueThread = ULongToHandle( tid );
1162 teb->RealClientId = teb->ClientId;
1163 if (wow_teb)
1165 wow_teb->ClientId.UniqueProcess = pid;
1166 wow_teb->ClientId.UniqueThread = tid;
1167 wow_teb->RealClientId = wow_teb->ClientId;
1172 /***********************************************************************
1173 * init_thread_stack
1175 NTSTATUS init_thread_stack( TEB *teb, ULONG_PTR limit, SIZE_T reserve_size, SIZE_T commit_size )
1177 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1178 WOW_TEB *wow_teb = get_wow_teb( teb );
1179 INITIAL_TEB stack;
1180 NTSTATUS status;
1182 /* kernel stack */
1183 if ((status = virtual_alloc_thread_stack( &stack, 0, kernel_stack_size, kernel_stack_size, FALSE )))
1184 return status;
1185 thread_data->kernel_stack = stack.DeallocationStack;
1187 if (wow_teb)
1189 WOW64_CPURESERVED *cpu;
1190 SIZE_T cpusize = sizeof(WOW64_CPURESERVED) +
1191 ((get_machine_context_size( main_image_info.Machine ) + 7) & ~7) + sizeof(ULONG64);
1193 /* 64-bit stack */
1194 if ((status = virtual_alloc_thread_stack( &stack, 0, 0x40000, 0x40000, TRUE ))) return status;
1195 cpu = (WOW64_CPURESERVED *)(((ULONG_PTR)stack.StackBase - cpusize) & ~15);
1196 cpu->Machine = main_image_info.Machine;
1198 #ifdef _WIN64
1199 teb->Tib.StackBase = teb->TlsSlots[WOW64_TLS_CPURESERVED] = cpu;
1200 teb->Tib.StackLimit = stack.StackLimit;
1201 teb->DeallocationStack = stack.DeallocationStack;
1203 /* 32-bit stack */
1204 if ((status = virtual_alloc_thread_stack( &stack, limit ? limit : 0x7fffffff,
1205 reserve_size, commit_size, TRUE )))
1206 return status;
1207 wow_teb->Tib.StackBase = PtrToUlong( stack.StackBase );
1208 wow_teb->Tib.StackLimit = PtrToUlong( stack.StackLimit );
1209 wow_teb->DeallocationStack = PtrToUlong( stack.DeallocationStack );
1210 return STATUS_SUCCESS;
1211 #else
1212 wow_teb->Tib.StackBase = wow_teb->TlsSlots[WOW64_TLS_CPURESERVED] = PtrToUlong( cpu );
1213 wow_teb->Tib.StackLimit = PtrToUlong( stack.StackLimit );
1214 wow_teb->DeallocationStack = PtrToUlong( stack.DeallocationStack );
1215 #endif
1218 /* native stack */
1219 if ((status = virtual_alloc_thread_stack( &stack, limit, reserve_size, commit_size, TRUE )))
1220 return status;
1221 teb->Tib.StackBase = stack.StackBase;
1222 teb->Tib.StackLimit = stack.StackLimit;
1223 teb->DeallocationStack = stack.DeallocationStack;
1224 return STATUS_SUCCESS;
1228 /***********************************************************************
1229 * update_attr_list
1231 * Update the output attributes.
1233 static void update_attr_list( PS_ATTRIBUTE_LIST *attr, const CLIENT_ID *id, TEB *teb )
1235 SIZE_T i, count = (attr->TotalLength - sizeof(attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
1237 for (i = 0; i < count; i++)
1239 if (attr->Attributes[i].Attribute == PS_ATTRIBUTE_CLIENT_ID)
1241 SIZE_T size = min( attr->Attributes[i].Size, sizeof(*id) );
1242 memcpy( attr->Attributes[i].ValuePtr, id, size );
1243 if (attr->Attributes[i].ReturnLength) *attr->Attributes[i].ReturnLength = size;
1245 else if (attr->Attributes[i].Attribute == PS_ATTRIBUTE_TEB_ADDRESS)
1247 SIZE_T size = min( attr->Attributes[i].Size, sizeof(teb) );
1248 memcpy( attr->Attributes[i].ValuePtr, &teb, size );
1249 if (attr->Attributes[i].ReturnLength) *attr->Attributes[i].ReturnLength = size;
1254 /***********************************************************************
1255 * NtCreateThread (NTDLL.@)
1257 NTSTATUS WINAPI NtCreateThread( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
1258 HANDLE process, CLIENT_ID *id, CONTEXT *ctx, INITIAL_TEB *teb,
1259 BOOLEAN suspended )
1261 FIXME( "%p %d %p %p %p %p %p %d, stub!\n",
1262 handle, (int)access, attr, process, id, ctx, teb, suspended );
1263 return STATUS_NOT_IMPLEMENTED;
1266 /***********************************************************************
1267 * NtCreateThreadEx (NTDLL.@)
1269 NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
1270 HANDLE process, PRTL_THREAD_START_ROUTINE start, void *param,
1271 ULONG flags, ULONG_PTR zero_bits, SIZE_T stack_commit,
1272 SIZE_T stack_reserve, PS_ATTRIBUTE_LIST *attr_list )
1274 static const ULONG supported_flags = THREAD_CREATE_FLAGS_CREATE_SUSPENDED | THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER;
1275 sigset_t sigset;
1276 pthread_t pthread_id;
1277 pthread_attr_t pthread_attr;
1278 data_size_t len;
1279 struct object_attributes *objattr;
1280 struct ntdll_thread_data *thread_data;
1281 DWORD tid = 0;
1282 int request_pipe[2];
1283 TEB *teb;
1284 unsigned int status;
1286 if (flags & ~supported_flags)
1287 FIXME( "Unsupported flags %#x.\n", (int)flags );
1289 if (zero_bits > 21 && zero_bits < 32) return STATUS_INVALID_PARAMETER_3;
1290 #ifndef _WIN64
1291 if (!is_old_wow64() && zero_bits >= 32) return STATUS_INVALID_PARAMETER_3;
1292 #endif
1294 if (process != NtCurrentProcess())
1296 apc_call_t call;
1297 apc_result_t result;
1299 memset( &call, 0, sizeof(call) );
1301 call.create_thread.type = APC_CREATE_THREAD;
1302 call.create_thread.flags = flags;
1303 call.create_thread.func = wine_server_client_ptr( start );
1304 call.create_thread.arg = wine_server_client_ptr( param );
1305 call.create_thread.zero_bits = zero_bits;
1306 call.create_thread.reserve = stack_reserve;
1307 call.create_thread.commit = stack_commit;
1308 status = server_queue_process_apc( process, &call, &result );
1309 if (status != STATUS_SUCCESS) return status;
1311 if (result.create_thread.status == STATUS_SUCCESS)
1313 CLIENT_ID client_id;
1314 TEB *teb = wine_server_get_ptr( result.create_thread.teb );
1315 *handle = wine_server_ptr_handle( result.create_thread.handle );
1316 client_id.UniqueProcess = ULongToHandle( result.create_thread.pid );
1317 client_id.UniqueThread = ULongToHandle( result.create_thread.tid );
1318 if (attr_list) update_attr_list( attr_list, &client_id, teb );
1320 return result.create_thread.status;
1323 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
1325 if (server_pipe( request_pipe ) == -1)
1327 free( objattr );
1328 return STATUS_TOO_MANY_OPENED_FILES;
1330 wine_server_send_fd( request_pipe[0] );
1332 if (!access) access = THREAD_ALL_ACCESS;
1334 SERVER_START_REQ( new_thread )
1336 req->process = wine_server_obj_handle( process );
1337 req->access = access;
1338 req->flags = flags;
1339 req->request_fd = request_pipe[0];
1340 wine_server_add_data( req, objattr, len );
1341 if (!(status = wine_server_call( req )))
1343 *handle = wine_server_ptr_handle( reply->handle );
1344 tid = reply->tid;
1346 close( request_pipe[0] );
1348 SERVER_END_REQ;
1350 free( objattr );
1351 if (status)
1353 close( request_pipe[1] );
1354 return status;
1357 pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
1359 if ((status = virtual_alloc_teb( &teb ))) goto done;
1361 if ((status = init_thread_stack( teb, get_zero_bits_limit( zero_bits ), stack_reserve, stack_commit )))
1363 virtual_free_teb( teb );
1364 goto done;
1367 set_thread_id( teb, GetCurrentProcessId(), tid );
1369 thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1370 thread_data->request_fd = request_pipe[1];
1371 thread_data->start = start;
1372 thread_data->param = param;
1374 pthread_attr_init( &pthread_attr );
1375 pthread_attr_setstack( &pthread_attr, thread_data->kernel_stack, kernel_stack_size );
1376 pthread_attr_setguardsize( &pthread_attr, 0 );
1377 pthread_attr_setscope( &pthread_attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a kernel thread */
1378 InterlockedIncrement( &nb_threads );
1379 if (pthread_create( &pthread_id, &pthread_attr, (void * (*)(void *))start_thread, teb ))
1381 InterlockedDecrement( &nb_threads );
1382 virtual_free_teb( teb );
1383 status = STATUS_NO_MEMORY;
1385 pthread_attr_destroy( &pthread_attr );
1387 done:
1388 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
1389 if (status)
1391 NtClose( *handle );
1392 close( request_pipe[1] );
1393 return status;
1395 if (attr_list) update_attr_list( attr_list, &teb->ClientId, teb );
1396 return STATUS_SUCCESS;
1400 /***********************************************************************
1401 * abort_thread
1403 void abort_thread( int status )
1405 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
1406 if (InterlockedDecrement( &nb_threads ) <= 0) abort_process( status );
1407 signal_exit_thread( status, pthread_exit_wrapper, NtCurrentTeb() );
1411 /***********************************************************************
1412 * abort_process
1414 void abort_process( int status )
1416 _exit( get_unix_exit_code( status ));
1420 /***********************************************************************
1421 * exit_thread
1423 static DECLSPEC_NORETURN void exit_thread( int status )
1425 static void *prev_teb;
1426 TEB *teb;
1428 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
1430 if (InterlockedDecrement( &nb_threads ) <= 0) exit_process( status );
1432 if ((teb = InterlockedExchangePointer( &prev_teb, NtCurrentTeb() )))
1434 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1436 if (thread_data->pthread_id)
1438 pthread_join( thread_data->pthread_id, NULL );
1439 virtual_free_teb( teb );
1442 signal_exit_thread( status, pthread_exit_wrapper, NtCurrentTeb() );
1446 /***********************************************************************
1447 * exit_process
1449 void exit_process( int status )
1451 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
1452 signal_exit_thread( get_unix_exit_code( status ), process_exit_wrapper, NtCurrentTeb() );
1456 /**********************************************************************
1457 * wait_suspend
1459 * Wait until the thread is no longer suspended.
1461 void wait_suspend( CONTEXT *context )
1463 int saved_errno = errno;
1464 context_t server_contexts[2];
1466 contexts_to_server( server_contexts, context );
1467 /* wait with 0 timeout, will only return once the thread is no longer suspended */
1468 server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, server_contexts, NULL );
1469 contexts_from_server( context, server_contexts );
1470 errno = saved_errno;
1474 /**********************************************************************
1475 * send_debug_event
1477 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
1479 NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1481 unsigned int ret;
1482 DWORD i;
1483 obj_handle_t handle = 0;
1484 client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
1485 select_op_t select_op;
1486 sigset_t old_set;
1488 if (!peb->BeingDebugged) return 0; /* no debugger present */
1490 pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set );
1492 for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++)
1493 params[i] = rec->ExceptionInformation[i];
1495 SERVER_START_REQ( queue_exception_event )
1497 req->first = first_chance;
1498 req->code = rec->ExceptionCode;
1499 req->flags = rec->ExceptionFlags;
1500 req->record = wine_server_client_ptr( rec->ExceptionRecord );
1501 req->address = wine_server_client_ptr( rec->ExceptionAddress );
1502 req->len = i * sizeof(params[0]);
1503 wine_server_add_data( req, params, req->len );
1504 if (!(ret = wine_server_call( req ))) handle = reply->handle;
1506 SERVER_END_REQ;
1508 if (handle)
1510 context_t server_contexts[2];
1512 select_op.wait.op = SELECT_WAIT;
1513 select_op.wait.handles[0] = handle;
1515 contexts_to_server( server_contexts, context );
1516 server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE,
1517 TIMEOUT_INFINITE, server_contexts, NULL );
1519 SERVER_START_REQ( get_exception_status )
1521 req->handle = handle;
1522 ret = wine_server_call( req );
1524 SERVER_END_REQ;
1525 if (NT_SUCCESS(ret)) contexts_from_server( context, server_contexts );
1528 pthread_sigmask( SIG_SETMASK, &old_set, NULL );
1529 return ret;
1533 /*******************************************************************
1534 * NtRaiseException (NTDLL.@)
1536 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1538 NTSTATUS status = send_debug_event( rec, context, first_chance );
1540 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
1541 return NtContinue( context, FALSE );
1543 if (first_chance) return call_user_exception_dispatcher( rec, context );
1545 if (rec->ExceptionFlags & EH_STACK_INVALID)
1546 ERR_(seh)("Exception frame is not in stack limits => unable to dispatch exception.\n");
1547 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
1548 ERR_(seh)("Process attempted to continue execution after noncontinuable exception.\n");
1549 else
1550 ERR_(seh)("Unhandled exception code %x flags %x addr %p\n",
1551 (int)rec->ExceptionCode, (int)rec->ExceptionFlags, rec->ExceptionAddress );
1553 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
1554 return STATUS_SUCCESS;
1558 /**********************************************************************
1559 * NtCurrentTeb (NTDLL.@)
1561 TEB * WINAPI NtCurrentTeb(void)
1563 return pthread_getspecific( teb_key );
1567 /***********************************************************************
1568 * NtOpenThread (NTDLL.@)
1570 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
1571 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
1573 unsigned int ret;
1575 *handle = 0;
1577 SERVER_START_REQ( open_thread )
1579 req->tid = HandleToULong(id->UniqueThread);
1580 req->access = access;
1581 req->attributes = attr ? attr->Attributes : 0;
1582 ret = wine_server_call( req );
1583 *handle = wine_server_ptr_handle( reply->handle );
1585 SERVER_END_REQ;
1586 return ret;
1590 /******************************************************************************
1591 * NtSuspendThread (NTDLL.@)
1593 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count )
1595 unsigned int ret;
1597 SERVER_START_REQ( suspend_thread )
1599 req->handle = wine_server_obj_handle( handle );
1600 if (!(ret = wine_server_call( req )))
1602 if (count) *count = reply->count;
1605 SERVER_END_REQ;
1606 return ret;
1610 /******************************************************************************
1611 * NtResumeThread (NTDLL.@)
1613 NTSTATUS WINAPI NtResumeThread( HANDLE handle, ULONG *count )
1615 unsigned int ret;
1617 SERVER_START_REQ( resume_thread )
1619 req->handle = wine_server_obj_handle( handle );
1620 if (!(ret = wine_server_call( req )))
1622 if (count) *count = reply->count;
1625 SERVER_END_REQ;
1626 return ret;
1630 /******************************************************************************
1631 * NtAlertResumeThread (NTDLL.@)
1633 NTSTATUS WINAPI NtAlertResumeThread( HANDLE handle, ULONG *count )
1635 FIXME( "stub: should alert thread %p\n", handle );
1636 return NtResumeThread( handle, count );
1640 /******************************************************************************
1641 * NtAlertThread (NTDLL.@)
1643 NTSTATUS WINAPI NtAlertThread( HANDLE handle )
1645 FIXME( "stub: %p\n", handle );
1646 return STATUS_NOT_IMPLEMENTED;
1650 /******************************************************************************
1651 * NtTerminateThread (NTDLL.@)
1653 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
1655 unsigned int ret;
1656 BOOL self;
1658 SERVER_START_REQ( terminate_thread )
1660 req->handle = wine_server_obj_handle( handle );
1661 req->exit_code = exit_code;
1662 ret = wine_server_call( req );
1663 self = !ret && reply->self;
1665 SERVER_END_REQ;
1667 if (self)
1669 server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, NULL, NULL );
1670 exit_thread( exit_code );
1672 return ret;
1676 /******************************************************************************
1677 * NtQueueApcThread (NTDLL.@)
1679 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
1680 ULONG_PTR arg2, ULONG_PTR arg3 )
1682 unsigned int ret;
1684 SERVER_START_REQ( queue_apc )
1686 req->handle = wine_server_obj_handle( handle );
1687 if (func)
1689 req->call.type = APC_USER;
1690 req->call.user.func = wine_server_client_ptr( func );
1691 req->call.user.args[0] = arg1;
1692 req->call.user.args[1] = arg2;
1693 req->call.user.args[2] = arg3;
1695 else req->call.type = APC_NONE; /* wake up only */
1696 ret = wine_server_call( req );
1698 SERVER_END_REQ;
1699 return ret;
1703 /***********************************************************************
1704 * set_thread_context
1706 NTSTATUS set_thread_context( HANDLE handle, const void *context, BOOL *self, USHORT machine )
1708 context_t server_contexts[2];
1709 unsigned int count = 0;
1710 unsigned int ret;
1712 context_to_server( &server_contexts[count++], native_machine, context, machine );
1713 if (machine != native_machine)
1714 context_to_server( &server_contexts[count++], machine, context, machine );
1716 SERVER_START_REQ( set_thread_context )
1718 req->handle = wine_server_obj_handle( handle );
1719 req->native_flags = server_contexts[0].flags & get_native_context_flags( native_machine, machine );
1720 wine_server_add_data( req, server_contexts, count * sizeof(server_contexts[0]) );
1721 ret = wine_server_call( req );
1722 *self = reply->self;
1724 SERVER_END_REQ;
1726 return ret;
1730 /***********************************************************************
1731 * get_thread_context
1733 NTSTATUS get_thread_context( HANDLE handle, void *context, BOOL *self, USHORT machine )
1735 unsigned int ret;
1736 HANDLE context_handle;
1737 context_t server_contexts[2];
1738 unsigned int count;
1739 unsigned int flags = get_server_context_flags( context, machine );
1741 SERVER_START_REQ( get_thread_context )
1743 req->handle = wine_server_obj_handle( handle );
1744 req->flags = flags;
1745 req->machine = machine;
1746 req->native_flags = flags & get_native_context_flags( native_machine, machine );
1747 wine_server_set_reply( req, server_contexts, sizeof(server_contexts) );
1748 ret = wine_server_call( req );
1749 *self = reply->self;
1750 context_handle = wine_server_ptr_handle( reply->handle );
1751 count = wine_server_reply_size( reply ) / sizeof(server_contexts[0]);
1753 SERVER_END_REQ;
1755 if (ret == STATUS_PENDING)
1757 NtWaitForSingleObject( context_handle, FALSE, NULL );
1759 SERVER_START_REQ( get_thread_context )
1761 req->context = wine_server_obj_handle( context_handle );
1762 req->flags = flags;
1763 req->machine = machine;
1764 req->native_flags = flags & get_native_context_flags( native_machine, machine );
1765 wine_server_set_reply( req, server_contexts, sizeof(server_contexts) );
1766 ret = wine_server_call( req );
1767 count = wine_server_reply_size( reply ) / sizeof(server_contexts[0]);
1769 SERVER_END_REQ;
1771 if (!ret)
1773 ret = context_from_server( context, &server_contexts[0], machine );
1774 if (!ret && count > 1) ret = context_from_server( context, &server_contexts[1], machine );
1776 return ret;
1780 /***********************************************************************
1781 * ntdll_set_exception_jmp_buf
1783 void ntdll_set_exception_jmp_buf( __wine_jmp_buf *jmp )
1785 assert( !jmp || !ntdll_get_thread_data()->jmp_buf );
1786 ntdll_get_thread_data()->jmp_buf = jmp;
1790 BOOL get_thread_times(int unix_pid, int unix_tid, LARGE_INTEGER *kernel_time, LARGE_INTEGER *user_time)
1792 #ifdef linux
1793 unsigned long clocks_per_sec = sysconf( _SC_CLK_TCK );
1794 unsigned long usr, sys;
1795 const char *pos;
1796 char buf[512];
1797 FILE *f;
1798 int i;
1800 if (unix_tid == -1)
1801 sprintf( buf, "/proc/%u/stat", unix_pid );
1802 else
1803 sprintf( buf, "/proc/%u/task/%u/stat", unix_pid, unix_tid );
1804 if (!(f = fopen( buf, "r" )))
1806 WARN("Failed to open %s: %s\n", buf, strerror(errno));
1807 return FALSE;
1810 pos = fgets( buf, sizeof(buf), f );
1811 fclose( f );
1813 /* the process name is printed unescaped, so we have to skip to the last ')'
1814 * to avoid misinterpreting the string */
1815 if (pos) pos = strrchr( pos, ')' );
1816 if (pos) pos = strchr( pos + 1, ' ' );
1817 if (pos) pos++;
1819 /* skip over the following fields: state, ppid, pgid, sid, tty_nr, tty_pgrp,
1820 * task->flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
1821 for (i = 0; i < 11 && pos; i++)
1823 pos = strchr( pos + 1, ' ' );
1824 if (pos) pos++;
1827 /* the next two values are user and system time */
1828 if (pos && (sscanf( pos, "%lu %lu", &usr, &sys ) == 2))
1830 kernel_time->QuadPart = (ULONGLONG)sys * 10000000 / clocks_per_sec;
1831 user_time->QuadPart = (ULONGLONG)usr * 10000000 / clocks_per_sec;
1832 return TRUE;
1835 ERR("Failed to parse %s\n", debugstr_a(buf));
1836 return FALSE;
1837 #elif defined(HAVE_LIBPROCSTAT)
1838 struct procstat *pstat;
1839 struct kinfo_proc *kip;
1840 unsigned int proc_count;
1841 BOOL ret = FALSE;
1843 pstat = procstat_open_sysctl();
1844 if (!pstat)
1845 return FALSE;
1846 if (unix_tid == -1)
1847 kip = procstat_getprocs(pstat, KERN_PROC_PID, unix_pid, &proc_count);
1848 else
1849 kip = procstat_getprocs(pstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, unix_pid, &proc_count);
1850 if (kip)
1852 unsigned int i;
1853 for (i = 0; i < proc_count; i++)
1855 if (unix_tid == -1 || kip[i].ki_tid == unix_tid)
1857 kernel_time->QuadPart = 10000000 * (ULONGLONG)kip[i].ki_rusage.ru_stime.tv_sec +
1858 10 * (ULONGLONG)kip[i].ki_rusage.ru_stime.tv_usec;
1859 user_time->QuadPart = 10000000 * (ULONGLONG)kip[i].ki_rusage.ru_utime.tv_sec +
1860 10 * (ULONGLONG)kip[i].ki_rusage.ru_utime.tv_usec;
1861 ret = TRUE;
1862 break;
1865 procstat_freeprocs(pstat, kip);
1867 procstat_close(pstat);
1868 return ret;
1869 #else
1870 static int once;
1871 if (!once++) FIXME("not implemented on this platform\n");
1872 return FALSE;
1873 #endif
1876 static void set_native_thread_name( HANDLE handle, const UNICODE_STRING *name )
1878 #ifdef linux
1879 unsigned int status;
1880 char path[64], nameA[64];
1881 int unix_pid, unix_tid, len, fd;
1883 SERVER_START_REQ( get_thread_times )
1885 req->handle = wine_server_obj_handle( handle );
1886 status = wine_server_call( req );
1887 if (status == STATUS_SUCCESS)
1889 unix_pid = reply->unix_pid;
1890 unix_tid = reply->unix_tid;
1893 SERVER_END_REQ;
1895 if (status != STATUS_SUCCESS || unix_pid == -1 || unix_tid == -1)
1896 return;
1898 if (unix_pid != getpid())
1900 static int once;
1901 if (!once++) FIXME("cross-process native thread naming not supported\n");
1902 return;
1905 len = ntdll_wcstoumbs( name->Buffer, name->Length / sizeof(WCHAR), nameA, sizeof(nameA), FALSE );
1906 sprintf(path, "/proc/%u/task/%u/comm", unix_pid, unix_tid);
1907 if ((fd = open( path, O_WRONLY )) != -1)
1909 write( fd, nameA, len );
1910 close( fd );
1912 #elif defined(__APPLE__)
1913 /* pthread_setname_np() silently fails if the name is longer than 63 characters + null terminator */
1914 char nameA[64];
1915 NTSTATUS status;
1916 int unix_pid, unix_tid, len, current_tid;
1918 SERVER_START_REQ( get_thread_times )
1920 req->handle = wine_server_obj_handle( handle );
1921 status = wine_server_call( req );
1922 if (status == STATUS_SUCCESS)
1924 unix_pid = reply->unix_pid;
1925 unix_tid = reply->unix_tid;
1928 SERVER_END_REQ;
1930 if (status != STATUS_SUCCESS || unix_pid == -1 || unix_tid == -1)
1931 return;
1933 current_tid = mach_thread_self();
1934 mach_port_deallocate(mach_task_self(), current_tid);
1936 if (unix_tid != current_tid)
1938 static int once;
1939 if (!once++) FIXME("setting other thread name not supported\n");
1940 return;
1943 len = ntdll_wcstoumbs( name->Buffer, name->Length / sizeof(WCHAR), nameA, sizeof(nameA) - 1, FALSE );
1944 nameA[len] = '\0';
1945 pthread_setname_np(nameA);
1946 #else
1947 static int once;
1948 if (!once++) FIXME("not implemented on this platform\n");
1949 #endif
1952 static BOOL is_process_wow64( const CLIENT_ID *id )
1954 HANDLE handle;
1955 ULONG_PTR info;
1956 BOOL ret = FALSE;
1958 if (id->UniqueProcess == ULongToHandle(GetCurrentProcessId())) return is_old_wow64();
1959 if (!NtOpenProcess( &handle, PROCESS_QUERY_LIMITED_INFORMATION, NULL, id ))
1961 if (!NtQueryInformationProcess( handle, ProcessWow64Information, &info, sizeof(info), NULL ))
1962 ret = !!info;
1963 NtClose( handle );
1965 return ret;
1968 /******************************************************************************
1969 * NtQueryInformationThread (NTDLL.@)
1971 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
1972 void *data, ULONG length, ULONG *ret_len )
1974 unsigned int status;
1976 TRACE("(%p,%d,%p,%x,%p)\n", handle, class, data, (int)length, ret_len);
1978 switch (class)
1980 case ThreadBasicInformation:
1982 THREAD_BASIC_INFORMATION info;
1983 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1985 SERVER_START_REQ( get_thread_info )
1987 req->handle = wine_server_obj_handle( handle );
1988 if (!(status = wine_server_call( req )))
1990 info.ExitStatus = reply->exit_code;
1991 info.TebBaseAddress = wine_server_get_ptr( reply->teb );
1992 info.ClientId.UniqueProcess = ULongToHandle(reply->pid);
1993 info.ClientId.UniqueThread = ULongToHandle(reply->tid);
1994 info.AffinityMask = reply->affinity & affinity_mask;
1995 info.Priority = reply->priority;
1996 info.BasePriority = reply->priority; /* FIXME */
1999 SERVER_END_REQ;
2000 if (status == STATUS_SUCCESS)
2002 if (is_old_wow64())
2004 if (is_process_wow64( &info.ClientId ))
2005 info.TebBaseAddress = (char *)info.TebBaseAddress + teb_offset;
2006 else
2007 info.TebBaseAddress = NULL;
2009 if (data) memcpy( data, &info, min( length, sizeof(info) ));
2010 if (ret_len) *ret_len = min( length, sizeof(info) );
2012 return status;
2015 case ThreadAffinityMask:
2017 const ULONG_PTR affinity_mask = get_system_affinity_mask();
2018 ULONG_PTR affinity = 0;
2020 SERVER_START_REQ( get_thread_info )
2022 req->handle = wine_server_obj_handle( handle );
2023 req->access = THREAD_QUERY_INFORMATION;
2024 if (!(status = wine_server_call( req ))) affinity = reply->affinity & affinity_mask;
2026 SERVER_END_REQ;
2027 if (status == STATUS_SUCCESS)
2029 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
2030 if (ret_len) *ret_len = min( length, sizeof(affinity) );
2032 return status;
2035 case ThreadTimes:
2037 KERNEL_USER_TIMES kusrt;
2038 int unix_pid, unix_tid;
2040 SERVER_START_REQ( get_thread_times )
2042 req->handle = wine_server_obj_handle( handle );
2043 status = wine_server_call( req );
2044 if (status == STATUS_SUCCESS)
2046 kusrt.CreateTime.QuadPart = reply->creation_time;
2047 kusrt.ExitTime.QuadPart = reply->exit_time;
2048 unix_pid = reply->unix_pid;
2049 unix_tid = reply->unix_tid;
2052 SERVER_END_REQ;
2053 if (status == STATUS_SUCCESS)
2055 BOOL ret = FALSE;
2057 kusrt.KernelTime.QuadPart = kusrt.UserTime.QuadPart = 0;
2058 if (unix_pid != -1 && unix_tid != -1)
2059 ret = get_thread_times( unix_pid, unix_tid, &kusrt.KernelTime, &kusrt.UserTime );
2060 if (!ret && handle == GetCurrentThread())
2062 /* fall back to process times */
2063 struct tms time_buf;
2064 long clocks_per_sec = sysconf(_SC_CLK_TCK);
2066 times(&time_buf);
2067 kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
2068 kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
2070 if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
2071 if (ret_len) *ret_len = min( length, sizeof(kusrt) );
2073 return status;
2076 case ThreadDescriptorTableEntry:
2077 return get_thread_ldt_entry( handle, data, length, ret_len );
2079 case ThreadAmILastThread:
2081 if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2082 SERVER_START_REQ( get_thread_info )
2084 req->handle = wine_server_obj_handle( handle );
2085 status = wine_server_call( req );
2086 if (status == STATUS_SUCCESS)
2088 ULONG last = reply->last;
2089 if (data) memcpy( data, &last, sizeof(last) );
2090 if (ret_len) *ret_len = sizeof(last);
2093 SERVER_END_REQ;
2094 return status;
2097 case ThreadQuerySetWin32StartAddress:
2099 SERVER_START_REQ( get_thread_info )
2101 req->handle = wine_server_obj_handle( handle );
2102 req->access = THREAD_QUERY_INFORMATION;
2103 status = wine_server_call( req );
2104 if (status == STATUS_SUCCESS)
2106 PRTL_THREAD_START_ROUTINE entry = wine_server_get_ptr( reply->entry_point );
2107 if (data) memcpy( data, &entry, min( length, sizeof(entry) ) );
2108 if (ret_len) *ret_len = min( length, sizeof(entry) );
2111 SERVER_END_REQ;
2112 return status;
2115 case ThreadGroupInformation:
2117 const ULONG_PTR affinity_mask = get_system_affinity_mask();
2118 GROUP_AFFINITY affinity;
2120 memset( &affinity, 0, sizeof(affinity) );
2121 affinity.Group = 0; /* Wine only supports max 64 processors */
2123 SERVER_START_REQ( get_thread_info )
2125 req->handle = wine_server_obj_handle( handle );
2126 if (!(status = wine_server_call( req ))) affinity.Mask = reply->affinity & affinity_mask;
2128 SERVER_END_REQ;
2129 if (status == STATUS_SUCCESS)
2131 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
2132 if (ret_len) *ret_len = min( length, sizeof(affinity) );
2134 return status;
2137 case ThreadIsIoPending:
2138 FIXME( "ThreadIsIoPending info class not supported yet\n" );
2139 if (length != sizeof(BOOL)) return STATUS_INFO_LENGTH_MISMATCH;
2140 if (!data) return STATUS_ACCESS_DENIED;
2141 *(BOOL*)data = FALSE;
2142 if (ret_len) *ret_len = sizeof(BOOL);
2143 return STATUS_SUCCESS;
2145 case ThreadSuspendCount:
2146 if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2147 if (!data) return STATUS_ACCESS_VIOLATION;
2149 SERVER_START_REQ( get_thread_info )
2151 req->handle = wine_server_obj_handle( handle );
2152 if (!(status = wine_server_call( req ))) *(ULONG *)data = reply->suspend_count;
2154 SERVER_END_REQ;
2155 return status;
2157 case ThreadNameInformation:
2159 THREAD_NAME_INFORMATION *info = data;
2160 data_size_t len, desc_len = 0;
2161 WCHAR *ptr;
2163 len = length >= sizeof(*info) ? length - sizeof(*info) : 0;
2164 ptr = info ? (WCHAR *)(info + 1) : NULL;
2166 SERVER_START_REQ( get_thread_info )
2168 req->handle = wine_server_obj_handle( handle );
2169 if (ptr) wine_server_set_reply( req, ptr, len );
2170 status = wine_server_call( req );
2171 desc_len = reply->desc_len;
2173 SERVER_END_REQ;
2175 if (!info) status = STATUS_BUFFER_TOO_SMALL;
2176 else if (status == STATUS_SUCCESS)
2178 info->ThreadName.Length = info->ThreadName.MaximumLength = desc_len;
2179 info->ThreadName.Buffer = ptr;
2182 if (ret_len && (status == STATUS_SUCCESS || status == STATUS_BUFFER_TOO_SMALL))
2183 *ret_len = sizeof(*info) + desc_len;
2184 return status;
2187 case ThreadWow64Context:
2188 return get_thread_wow64_context( handle, data, length );
2190 case ThreadHideFromDebugger:
2191 if (length != sizeof(BOOLEAN)) return STATUS_INFO_LENGTH_MISMATCH;
2192 if (!data) return STATUS_ACCESS_VIOLATION;
2193 SERVER_START_REQ( get_thread_info )
2195 req->handle = wine_server_obj_handle( handle );
2196 req->access = THREAD_QUERY_INFORMATION;
2197 if ((status = wine_server_call( req ))) return status;
2198 *(BOOLEAN*)data = reply->dbg_hidden;
2200 SERVER_END_REQ;
2201 if (ret_len) *ret_len = sizeof(BOOLEAN);
2202 return STATUS_SUCCESS;
2204 case ThreadPriorityBoost:
2206 DWORD *value = data;
2208 if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2209 if (ret_len) *ret_len = sizeof(ULONG);
2210 *value = 0;
2211 return STATUS_SUCCESS;
2214 case ThreadIdealProcessor:
2215 case ThreadEnableAlignmentFaultFixup:
2216 return STATUS_INVALID_INFO_CLASS;
2218 case ThreadPriority:
2219 case ThreadBasePriority:
2220 case ThreadImpersonationToken:
2221 case ThreadEventPair_Reusable:
2222 case ThreadZeroTlsCell:
2223 case ThreadPerformanceCount:
2224 case ThreadSetTlsArrayAddress:
2225 default:
2226 FIXME( "info class %d not supported yet\n", class );
2227 return STATUS_NOT_IMPLEMENTED;
2232 /******************************************************************************
2233 * NtSetInformationThread (NTDLL.@)
2235 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
2236 const void *data, ULONG length )
2238 unsigned int status;
2240 TRACE("(%p,%d,%p,%x)\n", handle, class, data, (int)length);
2242 switch (class)
2244 case ThreadZeroTlsCell:
2245 if (handle == GetCurrentThread())
2247 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
2248 return virtual_clear_tls_index( *(const ULONG *)data );
2250 FIXME( "ZeroTlsCell not supported on other threads\n" );
2251 return STATUS_NOT_IMPLEMENTED;
2253 case ThreadImpersonationToken:
2255 const HANDLE *token = data;
2257 if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
2258 TRACE("Setting ThreadImpersonationToken handle to %p\n", *token );
2259 SERVER_START_REQ( set_thread_info )
2261 req->handle = wine_server_obj_handle( handle );
2262 req->token = wine_server_obj_handle( *token );
2263 req->mask = SET_THREAD_INFO_TOKEN;
2264 status = wine_server_call( req );
2266 SERVER_END_REQ;
2267 return status;
2270 case ThreadBasePriority:
2272 const DWORD *pprio = data;
2273 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
2274 SERVER_START_REQ( set_thread_info )
2276 req->handle = wine_server_obj_handle( handle );
2277 req->priority = *pprio;
2278 req->mask = SET_THREAD_INFO_PRIORITY;
2279 status = wine_server_call( req );
2281 SERVER_END_REQ;
2282 return status;
2285 case ThreadAffinityMask:
2287 const ULONG_PTR affinity_mask = get_system_affinity_mask();
2288 ULONG_PTR req_aff;
2290 if (length != sizeof(ULONG_PTR)) return STATUS_INVALID_PARAMETER;
2291 req_aff = *(const ULONG_PTR *)data & affinity_mask;
2292 if (!req_aff) return STATUS_INVALID_PARAMETER;
2294 SERVER_START_REQ( set_thread_info )
2296 req->handle = wine_server_obj_handle( handle );
2297 req->affinity = req_aff;
2298 req->mask = SET_THREAD_INFO_AFFINITY;
2299 status = wine_server_call( req );
2301 SERVER_END_REQ;
2302 return status;
2305 case ThreadHideFromDebugger:
2306 if (length) return STATUS_INFO_LENGTH_MISMATCH;
2307 SERVER_START_REQ( set_thread_info )
2309 req->handle = wine_server_obj_handle( handle );
2310 req->mask = SET_THREAD_INFO_DBG_HIDDEN;
2311 status = wine_server_call( req );
2313 SERVER_END_REQ;
2314 return status;
2316 case ThreadQuerySetWin32StartAddress:
2318 const PRTL_THREAD_START_ROUTINE *entry = data;
2319 if (length != sizeof(PRTL_THREAD_START_ROUTINE)) return STATUS_INVALID_PARAMETER;
2320 SERVER_START_REQ( set_thread_info )
2322 req->handle = wine_server_obj_handle( handle );
2323 req->mask = SET_THREAD_INFO_ENTRYPOINT;
2324 req->entry_point = wine_server_client_ptr( *entry );
2325 status = wine_server_call( req );
2327 SERVER_END_REQ;
2328 return status;
2331 case ThreadGroupInformation:
2333 const ULONG_PTR affinity_mask = get_system_affinity_mask();
2334 const GROUP_AFFINITY *req_aff;
2336 if (length != sizeof(*req_aff)) return STATUS_INVALID_PARAMETER;
2337 if (!data) return STATUS_ACCESS_VIOLATION;
2338 req_aff = data;
2340 /* On Windows the request fails if the reserved fields are set */
2341 if (req_aff->Reserved[0] || req_aff->Reserved[1] || req_aff->Reserved[2])
2342 return STATUS_INVALID_PARAMETER;
2344 /* Wine only supports max 64 processors */
2345 if (req_aff->Group) return STATUS_INVALID_PARAMETER;
2346 if (req_aff->Mask & ~affinity_mask) return STATUS_INVALID_PARAMETER;
2347 if (!req_aff->Mask) return STATUS_INVALID_PARAMETER;
2348 SERVER_START_REQ( set_thread_info )
2350 req->handle = wine_server_obj_handle( handle );
2351 req->affinity = req_aff->Mask;
2352 req->mask = SET_THREAD_INFO_AFFINITY;
2353 status = wine_server_call( req );
2355 SERVER_END_REQ;
2356 return status;
2359 case ThreadNameInformation:
2361 const THREAD_NAME_INFORMATION *info = data;
2362 THREAD_BASIC_INFORMATION tbi;
2364 if (length != sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
2365 if (!info) return STATUS_ACCESS_VIOLATION;
2366 if (info->ThreadName.Length && !info->ThreadName.Buffer) return STATUS_ACCESS_VIOLATION;
2368 status = NtQueryInformationThread( handle, ThreadBasicInformation, &tbi, sizeof(tbi), NULL );
2369 if (handle == GetCurrentThread() || (!status && (HandleToULong(tbi.ClientId.UniqueThread) == GetCurrentThreadId())))
2370 WARN_(threadname)( "Thread renamed to %s\n", debugstr_us(&info->ThreadName) );
2371 else if (!status)
2372 WARN_(threadname)( "Thread ID %04x renamed to %s\n", (int)HandleToULong( tbi.ClientId.UniqueThread ), debugstr_us(&info->ThreadName) );
2373 else
2374 WARN_(threadname)( "Thread handle %p renamed to %s\n", handle, debugstr_us(&info->ThreadName) );
2376 SERVER_START_REQ( set_thread_info )
2378 req->handle = wine_server_obj_handle( handle );
2379 req->mask = SET_THREAD_INFO_DESCRIPTION;
2380 wine_server_add_data( req, info->ThreadName.Buffer, info->ThreadName.Length );
2381 status = wine_server_call( req );
2383 SERVER_END_REQ;
2385 set_native_thread_name( handle, &info->ThreadName );
2387 return status;
2390 case ThreadWineNativeThreadName:
2392 const THREAD_NAME_INFORMATION *info = data;
2394 if (length != sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
2396 set_native_thread_name( handle, &info->ThreadName );
2397 return STATUS_SUCCESS;
2400 case ThreadWow64Context:
2401 return set_thread_wow64_context( handle, data, length );
2403 case ThreadEnableAlignmentFaultFixup:
2404 if (length != sizeof(BOOLEAN)) return STATUS_INFO_LENGTH_MISMATCH;
2405 if (!data) return STATUS_ACCESS_VIOLATION;
2406 FIXME( "ThreadEnableAlignmentFaultFixup stub!\n" );
2407 return STATUS_SUCCESS;
2409 case ThreadPowerThrottlingState:
2410 if (length != sizeof(THREAD_POWER_THROTTLING_STATE)) return STATUS_INFO_LENGTH_MISMATCH;
2411 if (!data) return STATUS_ACCESS_VIOLATION;
2412 FIXME( "ThreadPowerThrottling stub!\n" );
2413 return STATUS_SUCCESS;
2415 case ThreadIdealProcessor:
2417 const ULONG *number = data;
2419 if (length != sizeof(*number)) return STATUS_INFO_LENGTH_MISMATCH;
2420 if (*number > MAXIMUM_PROCESSORS) return STATUS_INVALID_PARAMETER;
2421 FIXME( "ThreadIdealProcessor stub!\n" );
2422 return STATUS_SUCCESS;
2425 case ThreadPriorityBoost:
2426 WARN("Unimplemented class ThreadPriorityBoost.\n");
2427 return STATUS_SUCCESS;
2429 case ThreadBasicInformation:
2430 case ThreadTimes:
2431 case ThreadPriority:
2432 case ThreadDescriptorTableEntry:
2433 case ThreadEventPair_Reusable:
2434 case ThreadPerformanceCount:
2435 case ThreadAmILastThread:
2436 case ThreadSetTlsArrayAddress:
2437 case ThreadIsIoPending:
2438 default:
2439 FIXME( "info class %d not supported yet\n", class );
2440 return STATUS_NOT_IMPLEMENTED;
2445 /******************************************************************************
2446 * NtGetCurrentProcessorNumber (NTDLL.@)
2448 ULONG WINAPI NtGetCurrentProcessorNumber(void)
2450 ULONG processor;
2452 #if defined(__linux__) && defined(__NR_getcpu)
2453 int res = syscall(__NR_getcpu, &processor, NULL, NULL);
2454 if (res != -1) return processor;
2455 #endif
2457 if (peb->NumberOfProcessors > 1)
2459 ULONG_PTR thread_mask, processor_mask;
2461 if (!NtQueryInformationThread( GetCurrentThread(), ThreadAffinityMask,
2462 &thread_mask, sizeof(thread_mask), NULL ))
2464 for (processor = 0; processor < peb->NumberOfProcessors; processor++)
2466 processor_mask = (1 << processor);
2467 if (thread_mask & processor_mask)
2469 if (thread_mask != processor_mask)
2470 FIXME( "need multicore support (%d processors)\n",
2471 (int)peb->NumberOfProcessors );
2472 return processor;
2477 /* fallback to the first processor */
2478 return 0;
2482 /******************************************************************************
2483 * NtGetNextThread (NTDLL.@)
2485 NTSTATUS WINAPI NtGetNextThread( HANDLE process, HANDLE thread, ACCESS_MASK access, ULONG attributes,
2486 ULONG flags, HANDLE *handle )
2488 HANDLE ret_handle = 0;
2489 unsigned int ret;
2491 TRACE( "process %p, thread %p, access %#x, attributes %#x, flags %#x, handle %p.\n",
2492 process, thread, (int)access, (int)attributes, (int)flags, handle );
2494 SERVER_START_REQ( get_next_thread )
2496 req->process = wine_server_obj_handle( process );
2497 req->last = wine_server_obj_handle( thread );
2498 req->access = access;
2499 req->attributes = attributes;
2500 req->flags = flags;
2501 if (!(ret = wine_server_call( req ))) ret_handle = wine_server_ptr_handle( reply->handle );
2503 SERVER_END_REQ;
2505 *handle = ret_handle;
2506 return ret;