ntdll: Fix ARM vs AMD64 typo.
[wine.git] / dlls / ntdll / unix / thread.c
blobbb8c1c2936b0a0198bb34066d4fdbc85567f9c10
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 <limits.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <pthread.h>
35 #include <signal.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 #include <sys/mman.h>
39 #ifdef HAVE_SYS_TIMES_H
40 #include <sys/times.h>
41 #endif
42 #ifdef HAVE_SYS_SYSCALL_H
43 #include <sys/syscall.h>
44 #endif
45 #ifdef HAVE_SYS_SYSCTL_H
46 #include <sys/sysctl.h>
47 #endif
48 #ifdef HAVE_SYS_PARAM_H
49 #include <sys/param.h>
50 #endif
51 #ifdef HAVE_SYS_QUEUE_H
52 #include <sys/queue.h>
53 #endif
54 #ifdef HAVE_SYS_USER_H
55 #include <sys/user.h>
56 #endif
57 #ifdef HAVE_LIBPROCSTAT_H
58 #include <libprocstat.h>
59 #endif
61 #define NONAMELESSUNION
62 #define NONAMELESSSTRUCT
63 #include "ntstatus.h"
64 #define WIN32_NO_STATUS
65 #include "winternl.h"
66 #include "ddk/wdm.h"
67 #include "wine/server.h"
68 #include "wine/debug.h"
69 #include "unix_private.h"
71 WINE_DEFAULT_DEBUG_CHANNEL(thread);
72 WINE_DECLARE_DEBUG_CHANNEL(seh);
73 WINE_DECLARE_DEBUG_CHANNEL(threadname);
75 static int nb_threads = 1;
77 static inline int get_unix_exit_code( NTSTATUS status )
79 /* prevent a nonzero exit code to end up truncated to zero in unix */
80 if (status && !(status & 0xff)) return 1;
81 return status;
85 /***********************************************************************
86 * fpux_to_fpu
88 * Build a standard i386 FPU context from an extended one.
90 void fpux_to_fpu( I386_FLOATING_SAVE_AREA *fpu, const XMM_SAVE_AREA32 *fpux )
92 unsigned int i, tag, stack_top;
94 fpu->ControlWord = fpux->ControlWord;
95 fpu->StatusWord = fpux->StatusWord;
96 fpu->ErrorOffset = fpux->ErrorOffset;
97 fpu->ErrorSelector = fpux->ErrorSelector | (fpux->ErrorOpcode << 16);
98 fpu->DataOffset = fpux->DataOffset;
99 fpu->DataSelector = fpux->DataSelector;
100 fpu->Cr0NpxState = fpux->StatusWord | 0xffff0000;
102 stack_top = (fpux->StatusWord >> 11) & 7;
103 fpu->TagWord = 0xffff0000;
104 for (i = 0; i < 8; i++)
106 memcpy( &fpu->RegisterArea[10 * i], &fpux->FloatRegisters[i], 10 );
107 if (!(fpux->TagWord & (1 << i))) tag = 3; /* empty */
108 else
110 const M128A *reg = &fpux->FloatRegisters[(i - stack_top) & 7];
111 if ((reg->High & 0x7fff) == 0x7fff) /* exponent all ones */
113 tag = 2; /* special */
115 else if (!(reg->High & 0x7fff)) /* exponent all zeroes */
117 if (reg->Low) tag = 2; /* special */
118 else tag = 1; /* zero */
120 else
122 if (reg->Low >> 63) tag = 0; /* valid */
123 else tag = 2; /* special */
126 fpu->TagWord |= tag << (2 * i);
131 /***********************************************************************
132 * fpu_to_fpux
134 * Fill extended i386 FPU context from standard one.
136 void fpu_to_fpux( XMM_SAVE_AREA32 *fpux, const I386_FLOATING_SAVE_AREA *fpu )
138 unsigned int i;
140 fpux->ControlWord = fpu->ControlWord;
141 fpux->StatusWord = fpu->StatusWord;
142 fpux->ErrorOffset = fpu->ErrorOffset;
143 fpux->ErrorSelector = fpu->ErrorSelector;
144 fpux->ErrorOpcode = fpu->ErrorSelector >> 16;
145 fpux->DataOffset = fpu->DataOffset;
146 fpux->DataSelector = fpu->DataSelector;
147 fpux->TagWord = 0;
148 for (i = 0; i < 8; i++)
150 if (((fpu->TagWord >> (i * 2)) & 3) != 3) fpux->TagWord |= 1 << i;
151 memcpy( &fpux->FloatRegisters[i], &fpu->RegisterArea[10 * i], 10 );
156 /***********************************************************************
157 * get_server_context_flags
159 static unsigned int get_server_context_flags( const void *context, USHORT machine )
161 unsigned int flags, ret = 0;
163 switch (machine)
165 case IMAGE_FILE_MACHINE_I386:
166 flags = ((const I386_CONTEXT *)context)->ContextFlags & ~CONTEXT_i386;
167 if (flags & CONTEXT_I386_CONTROL) ret |= SERVER_CTX_CONTROL;
168 if (flags & CONTEXT_I386_INTEGER) ret |= SERVER_CTX_INTEGER;
169 if (flags & CONTEXT_I386_SEGMENTS) ret |= SERVER_CTX_SEGMENTS;
170 if (flags & CONTEXT_I386_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
171 if (flags & CONTEXT_I386_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
172 if (flags & CONTEXT_I386_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS | SERVER_CTX_FLOATING_POINT;
173 if (flags & CONTEXT_I386_XSTATE) ret |= SERVER_CTX_YMM_REGISTERS;
174 break;
175 case IMAGE_FILE_MACHINE_AMD64:
176 flags = ((const AMD64_CONTEXT *)context)->ContextFlags & ~CONTEXT_AMD64;
177 if (flags & CONTEXT_AMD64_CONTROL) ret |= SERVER_CTX_CONTROL;
178 if (flags & CONTEXT_AMD64_INTEGER) ret |= SERVER_CTX_INTEGER;
179 if (flags & CONTEXT_AMD64_SEGMENTS) ret |= SERVER_CTX_SEGMENTS;
180 if (flags & CONTEXT_AMD64_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
181 if (flags & CONTEXT_AMD64_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
182 if (flags & CONTEXT_AMD64_XSTATE) ret |= SERVER_CTX_YMM_REGISTERS;
183 break;
184 case IMAGE_FILE_MACHINE_ARMNT:
185 flags = ((const ARM_CONTEXT *)context)->ContextFlags & ~CONTEXT_ARM;
186 if (flags & CONTEXT_ARM_CONTROL) ret |= SERVER_CTX_CONTROL;
187 if (flags & CONTEXT_ARM_INTEGER) ret |= SERVER_CTX_INTEGER;
188 if (flags & CONTEXT_ARM_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
189 if (flags & CONTEXT_ARM_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
190 break;
191 case IMAGE_FILE_MACHINE_ARM64:
192 flags = ((const ARM64_NT_CONTEXT *)context)->ContextFlags & ~CONTEXT_ARM64;
193 if (flags & CONTEXT_ARM64_CONTROL) ret |= SERVER_CTX_CONTROL;
194 if (flags & CONTEXT_ARM64_INTEGER) ret |= SERVER_CTX_INTEGER;
195 if (flags & CONTEXT_ARM64_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
196 if (flags & CONTEXT_ARM64_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
197 break;
199 return ret;
203 /***********************************************************************
204 * context_to_server
206 * Convert a register context to the server format.
208 static NTSTATUS context_to_server( context_t *to, USHORT to_machine, const void *src, USHORT from_machine )
210 DWORD i, flags;
212 memset( to, 0, sizeof(*to) );
213 to->machine = to_machine;
215 switch (MAKELONG( from_machine, to_machine ))
217 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_I386 ):
219 const I386_CONTEXT *from = src;
221 flags = from->ContextFlags & ~CONTEXT_i386;
222 if (flags & CONTEXT_I386_CONTROL)
224 to->flags |= SERVER_CTX_CONTROL;
225 to->ctl.i386_regs.ebp = from->Ebp;
226 to->ctl.i386_regs.esp = from->Esp;
227 to->ctl.i386_regs.eip = from->Eip;
228 to->ctl.i386_regs.cs = from->SegCs;
229 to->ctl.i386_regs.ss = from->SegSs;
230 to->ctl.i386_regs.eflags = from->EFlags;
232 if (flags & CONTEXT_I386_INTEGER)
234 to->flags |= SERVER_CTX_INTEGER;
235 to->integer.i386_regs.eax = from->Eax;
236 to->integer.i386_regs.ebx = from->Ebx;
237 to->integer.i386_regs.ecx = from->Ecx;
238 to->integer.i386_regs.edx = from->Edx;
239 to->integer.i386_regs.esi = from->Esi;
240 to->integer.i386_regs.edi = from->Edi;
242 if (flags & CONTEXT_I386_SEGMENTS)
244 to->flags |= SERVER_CTX_SEGMENTS;
245 to->seg.i386_regs.ds = from->SegDs;
246 to->seg.i386_regs.es = from->SegEs;
247 to->seg.i386_regs.fs = from->SegFs;
248 to->seg.i386_regs.gs = from->SegGs;
250 if (flags & CONTEXT_I386_FLOATING_POINT)
252 to->flags |= SERVER_CTX_FLOATING_POINT;
253 to->fp.i386_regs.ctrl = from->FloatSave.ControlWord;
254 to->fp.i386_regs.status = from->FloatSave.StatusWord;
255 to->fp.i386_regs.tag = from->FloatSave.TagWord;
256 to->fp.i386_regs.err_off = from->FloatSave.ErrorOffset;
257 to->fp.i386_regs.err_sel = from->FloatSave.ErrorSelector;
258 to->fp.i386_regs.data_off = from->FloatSave.DataOffset;
259 to->fp.i386_regs.data_sel = from->FloatSave.DataSelector;
260 to->fp.i386_regs.cr0npx = from->FloatSave.Cr0NpxState;
261 memcpy( to->fp.i386_regs.regs, from->FloatSave.RegisterArea, sizeof(to->fp.i386_regs.regs) );
263 if (flags & CONTEXT_I386_DEBUG_REGISTERS)
265 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
266 to->debug.i386_regs.dr0 = from->Dr0;
267 to->debug.i386_regs.dr1 = from->Dr1;
268 to->debug.i386_regs.dr2 = from->Dr2;
269 to->debug.i386_regs.dr3 = from->Dr3;
270 to->debug.i386_regs.dr6 = from->Dr6;
271 to->debug.i386_regs.dr7 = from->Dr7;
273 if (flags & CONTEXT_I386_EXTENDED_REGISTERS)
275 to->flags |= SERVER_CTX_EXTENDED_REGISTERS;
276 memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) );
278 if (flags & CONTEXT_I386_XSTATE)
280 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
281 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
283 to->flags |= SERVER_CTX_YMM_REGISTERS;
284 if (xs->Mask & 4) memcpy( &to->ymm.regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
286 return STATUS_SUCCESS;
289 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_AMD64 ):
291 const I386_CONTEXT *from = src;
293 flags = from->ContextFlags & ~CONTEXT_i386;
294 if (flags & CONTEXT_I386_CONTROL)
296 to->flags |= SERVER_CTX_CONTROL;
297 to->ctl.x86_64_regs.rbp = from->Ebp;
298 to->ctl.x86_64_regs.rsp = from->Esp;
299 to->ctl.x86_64_regs.rip = from->Eip;
300 to->ctl.x86_64_regs.cs = from->SegCs;
301 to->ctl.x86_64_regs.ss = from->SegSs;
302 to->ctl.x86_64_regs.flags = from->EFlags;
304 if (flags & CONTEXT_I386_INTEGER)
306 to->flags |= SERVER_CTX_INTEGER;
307 to->integer.x86_64_regs.rax = from->Eax;
308 to->integer.x86_64_regs.rbx = from->Ebx;
309 to->integer.x86_64_regs.rcx = from->Ecx;
310 to->integer.x86_64_regs.rdx = from->Edx;
311 to->integer.x86_64_regs.rsi = from->Esi;
312 to->integer.x86_64_regs.rdi = from->Edi;
314 if (flags & CONTEXT_I386_SEGMENTS)
316 to->flags |= SERVER_CTX_SEGMENTS;
317 to->seg.x86_64_regs.ds = from->SegDs;
318 to->seg.x86_64_regs.es = from->SegEs;
319 to->seg.x86_64_regs.fs = from->SegFs;
320 to->seg.x86_64_regs.gs = from->SegGs;
322 if (flags & CONTEXT_I386_DEBUG_REGISTERS)
324 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
325 to->debug.x86_64_regs.dr0 = from->Dr0;
326 to->debug.x86_64_regs.dr1 = from->Dr1;
327 to->debug.x86_64_regs.dr2 = from->Dr2;
328 to->debug.x86_64_regs.dr3 = from->Dr3;
329 to->debug.x86_64_regs.dr6 = from->Dr6;
330 to->debug.x86_64_regs.dr7 = from->Dr7;
332 if (flags & CONTEXT_I386_EXTENDED_REGISTERS)
334 to->flags |= SERVER_CTX_FLOATING_POINT;
335 memcpy( to->fp.x86_64_regs.fpregs, from->ExtendedRegisters, sizeof(to->fp.x86_64_regs.fpregs) );
337 else if (flags & CONTEXT_I386_FLOATING_POINT)
339 to->flags |= SERVER_CTX_FLOATING_POINT;
340 fpu_to_fpux( (XMM_SAVE_AREA32 *)to->fp.x86_64_regs.fpregs, &from->FloatSave );
342 if (flags & CONTEXT_I386_XSTATE)
344 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
345 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
347 to->flags |= SERVER_CTX_YMM_REGISTERS;
348 if (xs->Mask & 4) memcpy( &to->ymm.regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
350 return STATUS_SUCCESS;
353 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_AMD64 ):
355 const AMD64_CONTEXT *from = src;
357 flags = from->ContextFlags & ~CONTEXT_AMD64;
358 if (flags & CONTEXT_AMD64_CONTROL)
360 to->flags |= SERVER_CTX_CONTROL;
361 to->ctl.x86_64_regs.rbp = from->Rbp;
362 to->ctl.x86_64_regs.rip = from->Rip;
363 to->ctl.x86_64_regs.rsp = from->Rsp;
364 to->ctl.x86_64_regs.cs = from->SegCs;
365 to->ctl.x86_64_regs.ss = from->SegSs;
366 to->ctl.x86_64_regs.flags = from->EFlags;
368 if (flags & CONTEXT_AMD64_INTEGER)
370 to->flags |= SERVER_CTX_INTEGER;
371 to->integer.x86_64_regs.rax = from->Rax;
372 to->integer.x86_64_regs.rcx = from->Rcx;
373 to->integer.x86_64_regs.rdx = from->Rdx;
374 to->integer.x86_64_regs.rbx = from->Rbx;
375 to->integer.x86_64_regs.rsi = from->Rsi;
376 to->integer.x86_64_regs.rdi = from->Rdi;
377 to->integer.x86_64_regs.r8 = from->R8;
378 to->integer.x86_64_regs.r9 = from->R9;
379 to->integer.x86_64_regs.r10 = from->R10;
380 to->integer.x86_64_regs.r11 = from->R11;
381 to->integer.x86_64_regs.r12 = from->R12;
382 to->integer.x86_64_regs.r13 = from->R13;
383 to->integer.x86_64_regs.r14 = from->R14;
384 to->integer.x86_64_regs.r15 = from->R15;
386 if (flags & CONTEXT_AMD64_SEGMENTS)
388 to->flags |= SERVER_CTX_SEGMENTS;
389 to->seg.x86_64_regs.ds = from->SegDs;
390 to->seg.x86_64_regs.es = from->SegEs;
391 to->seg.x86_64_regs.fs = from->SegFs;
392 to->seg.x86_64_regs.gs = from->SegGs;
394 if (flags & CONTEXT_AMD64_FLOATING_POINT)
396 to->flags |= SERVER_CTX_FLOATING_POINT;
397 memcpy( to->fp.x86_64_regs.fpregs, &from->u.FltSave, sizeof(to->fp.x86_64_regs.fpregs) );
399 if (flags & CONTEXT_AMD64_DEBUG_REGISTERS)
401 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
402 to->debug.x86_64_regs.dr0 = from->Dr0;
403 to->debug.x86_64_regs.dr1 = from->Dr1;
404 to->debug.x86_64_regs.dr2 = from->Dr2;
405 to->debug.x86_64_regs.dr3 = from->Dr3;
406 to->debug.x86_64_regs.dr6 = from->Dr6;
407 to->debug.x86_64_regs.dr7 = from->Dr7;
409 if (flags & CONTEXT_AMD64_XSTATE)
411 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
412 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
414 to->flags |= SERVER_CTX_YMM_REGISTERS;
415 if (xs->Mask & 4) memcpy( &to->ymm.regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
417 return STATUS_SUCCESS;
420 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386 ):
422 const AMD64_CONTEXT *from = src;
424 flags = from->ContextFlags & ~CONTEXT_AMD64;
425 if (flags & CONTEXT_AMD64_CONTROL)
427 to->flags |= SERVER_CTX_CONTROL;
428 to->ctl.i386_regs.ebp = from->Rbp;
429 to->ctl.i386_regs.eip = from->Rip;
430 to->ctl.i386_regs.esp = from->Rsp;
431 to->ctl.i386_regs.cs = from->SegCs;
432 to->ctl.i386_regs.ss = from->SegSs;
433 to->ctl.i386_regs.eflags = from->EFlags;
435 if (flags & CONTEXT_AMD64_INTEGER)
437 to->flags |= SERVER_CTX_INTEGER;
438 to->integer.i386_regs.eax = from->Rax;
439 to->integer.i386_regs.ecx = from->Rcx;
440 to->integer.i386_regs.edx = from->Rdx;
441 to->integer.i386_regs.ebx = from->Rbx;
442 to->integer.i386_regs.esi = from->Rsi;
443 to->integer.i386_regs.edi = from->Rdi;
445 if (flags & CONTEXT_AMD64_SEGMENTS)
447 to->flags |= SERVER_CTX_SEGMENTS;
448 to->seg.i386_regs.ds = from->SegDs;
449 to->seg.i386_regs.es = from->SegEs;
450 to->seg.i386_regs.fs = from->SegFs;
451 to->seg.i386_regs.gs = from->SegGs;
453 if (flags & CONTEXT_AMD64_FLOATING_POINT)
455 I386_FLOATING_SAVE_AREA fpu;
457 to->flags |= SERVER_CTX_EXTENDED_REGISTERS | SERVER_CTX_FLOATING_POINT;
458 memcpy( to->ext.i386_regs, &from->u.FltSave, sizeof(to->ext.i386_regs) );
459 fpux_to_fpu( &fpu, &from->u.FltSave );
460 to->fp.i386_regs.ctrl = fpu.ControlWord;
461 to->fp.i386_regs.status = fpu.StatusWord;
462 to->fp.i386_regs.tag = fpu.TagWord;
463 to->fp.i386_regs.err_off = fpu.ErrorOffset;
464 to->fp.i386_regs.err_sel = fpu.ErrorSelector;
465 to->fp.i386_regs.data_off = fpu.DataOffset;
466 to->fp.i386_regs.data_sel = fpu.DataSelector;
467 to->fp.i386_regs.cr0npx = fpu.Cr0NpxState;
468 memcpy( to->fp.i386_regs.regs, fpu.RegisterArea, sizeof(to->fp.i386_regs.regs) );
470 if (flags & CONTEXT_AMD64_DEBUG_REGISTERS)
472 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
473 to->debug.i386_regs.dr0 = from->Dr0;
474 to->debug.i386_regs.dr1 = from->Dr1;
475 to->debug.i386_regs.dr2 = from->Dr2;
476 to->debug.i386_regs.dr3 = from->Dr3;
477 to->debug.i386_regs.dr6 = from->Dr6;
478 to->debug.i386_regs.dr7 = from->Dr7;
480 if (flags & CONTEXT_AMD64_XSTATE)
482 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
483 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
485 to->flags |= SERVER_CTX_YMM_REGISTERS;
486 if (xs->Mask & 4) memcpy( &to->ymm.regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
488 return STATUS_SUCCESS;
491 case MAKELONG( IMAGE_FILE_MACHINE_ARMNT, IMAGE_FILE_MACHINE_ARMNT ):
493 const ARM_CONTEXT *from = src;
495 flags = from->ContextFlags & ~CONTEXT_ARM;
496 if (flags & CONTEXT_ARM_CONTROL)
498 to->flags |= SERVER_CTX_CONTROL;
499 to->ctl.arm_regs.sp = from->Sp;
500 to->ctl.arm_regs.lr = from->Lr;
501 to->ctl.arm_regs.pc = from->Pc;
502 to->ctl.arm_regs.cpsr = from->Cpsr;
504 if (flags & CONTEXT_ARM_INTEGER)
506 to->flags |= SERVER_CTX_INTEGER;
507 to->integer.arm_regs.r[0] = from->R0;
508 to->integer.arm_regs.r[1] = from->R1;
509 to->integer.arm_regs.r[2] = from->R2;
510 to->integer.arm_regs.r[3] = from->R3;
511 to->integer.arm_regs.r[4] = from->R4;
512 to->integer.arm_regs.r[5] = from->R5;
513 to->integer.arm_regs.r[6] = from->R6;
514 to->integer.arm_regs.r[7] = from->R7;
515 to->integer.arm_regs.r[8] = from->R8;
516 to->integer.arm_regs.r[9] = from->R9;
517 to->integer.arm_regs.r[10] = from->R10;
518 to->integer.arm_regs.r[11] = from->R11;
519 to->integer.arm_regs.r[12] = from->R12;
521 if (flags & CONTEXT_ARM_FLOATING_POINT)
523 to->flags |= SERVER_CTX_FLOATING_POINT;
524 for (i = 0; i < 32; i++) to->fp.arm_regs.d[i] = from->u.D[i];
525 to->fp.arm_regs.fpscr = from->Fpscr;
527 if (flags & CONTEXT_ARM_DEBUG_REGISTERS)
529 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
530 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bvr[i] = from->Bvr[i];
531 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bcr[i] = from->Bcr[i];
532 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wvr[i] = from->Wvr[i];
533 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wcr[i] = from->Wcr[i];
535 return STATUS_SUCCESS;
538 case MAKELONG( IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_ARM64 ):
540 const ARM64_NT_CONTEXT *from = src;
542 flags = from->ContextFlags & ~CONTEXT_ARM64;
543 if (flags & CONTEXT_ARM64_CONTROL)
545 to->flags |= SERVER_CTX_CONTROL;
546 to->integer.arm64_regs.x[29] = from->u.s.Fp;
547 to->integer.arm64_regs.x[30] = from->u.s.Lr;
548 to->ctl.arm64_regs.sp = from->Sp;
549 to->ctl.arm64_regs.pc = from->Pc;
550 to->ctl.arm64_regs.pstate = from->Cpsr;
552 if (flags & CONTEXT_ARM64_INTEGER)
554 to->flags |= SERVER_CTX_INTEGER;
555 for (i = 0; i <= 28; i++) to->integer.arm64_regs.x[i] = from->u.X[i];
557 if (flags & CONTEXT_ARM64_FLOATING_POINT)
559 to->flags |= SERVER_CTX_FLOATING_POINT;
560 for (i = 0; i < 32; i++)
562 to->fp.arm64_regs.q[i].low = from->V[i].s.Low;
563 to->fp.arm64_regs.q[i].high = from->V[i].s.High;
565 to->fp.arm64_regs.fpcr = from->Fpcr;
566 to->fp.arm64_regs.fpsr = from->Fpsr;
568 if (flags & CONTEXT_ARM64_DEBUG_REGISTERS)
570 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
571 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bcr[i] = from->Bcr[i];
572 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bvr[i] = from->Bvr[i];
573 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wcr[i] = from->Wcr[i];
574 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wvr[i] = from->Wvr[i];
576 return STATUS_SUCCESS;
579 default:
580 return STATUS_INVALID_PARAMETER;
585 /***********************************************************************
586 * context_from_server
588 * Convert a register context from the server format.
590 static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT machine )
592 DWORD i, to_flags;
594 switch (MAKELONG( from->machine, machine ))
596 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_I386 ):
598 I386_CONTEXT *to = dst;
600 to_flags = to->ContextFlags & ~CONTEXT_i386;
601 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_I386_CONTROL))
603 to->ContextFlags |= CONTEXT_I386_CONTROL;
604 to->Ebp = from->ctl.i386_regs.ebp;
605 to->Esp = from->ctl.i386_regs.esp;
606 to->Eip = from->ctl.i386_regs.eip;
607 to->SegCs = from->ctl.i386_regs.cs;
608 to->SegSs = from->ctl.i386_regs.ss;
609 to->EFlags = from->ctl.i386_regs.eflags;
611 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_I386_INTEGER))
613 to->ContextFlags |= CONTEXT_I386_INTEGER;
614 to->Eax = from->integer.i386_regs.eax;
615 to->Ebx = from->integer.i386_regs.ebx;
616 to->Ecx = from->integer.i386_regs.ecx;
617 to->Edx = from->integer.i386_regs.edx;
618 to->Esi = from->integer.i386_regs.esi;
619 to->Edi = from->integer.i386_regs.edi;
621 if ((from->flags & SERVER_CTX_SEGMENTS) && (to_flags & CONTEXT_I386_SEGMENTS))
623 to->ContextFlags |= CONTEXT_I386_SEGMENTS;
624 to->SegDs = from->seg.i386_regs.ds;
625 to->SegEs = from->seg.i386_regs.es;
626 to->SegFs = from->seg.i386_regs.fs;
627 to->SegGs = from->seg.i386_regs.gs;
629 if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_I386_FLOATING_POINT))
631 to->ContextFlags |= CONTEXT_I386_FLOATING_POINT;
632 to->FloatSave.ControlWord = from->fp.i386_regs.ctrl;
633 to->FloatSave.StatusWord = from->fp.i386_regs.status;
634 to->FloatSave.TagWord = from->fp.i386_regs.tag;
635 to->FloatSave.ErrorOffset = from->fp.i386_regs.err_off;
636 to->FloatSave.ErrorSelector = from->fp.i386_regs.err_sel;
637 to->FloatSave.DataOffset = from->fp.i386_regs.data_off;
638 to->FloatSave.DataSelector = from->fp.i386_regs.data_sel;
639 to->FloatSave.Cr0NpxState = from->fp.i386_regs.cr0npx;
640 memcpy( to->FloatSave.RegisterArea, from->fp.i386_regs.regs, sizeof(to->FloatSave.RegisterArea) );
642 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_I386_DEBUG_REGISTERS))
644 to->ContextFlags |= CONTEXT_I386_DEBUG_REGISTERS;
645 to->Dr0 = from->debug.i386_regs.dr0;
646 to->Dr1 = from->debug.i386_regs.dr1;
647 to->Dr2 = from->debug.i386_regs.dr2;
648 to->Dr3 = from->debug.i386_regs.dr3;
649 to->Dr6 = from->debug.i386_regs.dr6;
650 to->Dr7 = from->debug.i386_regs.dr7;
652 if ((from->flags & SERVER_CTX_EXTENDED_REGISTERS) && (to_flags & CONTEXT_I386_EXTENDED_REGISTERS))
654 to->ContextFlags |= CONTEXT_I386_EXTENDED_REGISTERS;
655 memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) );
657 if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_I386_XSTATE))
659 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
660 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
662 xs->Mask &= ~4;
663 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
664 for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++)
666 if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue;
667 memcpy( &xs->YmmContext, &from->ymm.regs, sizeof(xs->YmmContext) );
668 xs->Mask |= 4;
669 break;
672 return STATUS_SUCCESS;
675 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386 ):
677 I386_CONTEXT *to = dst;
679 to_flags = to->ContextFlags & ~CONTEXT_i386;
680 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_I386_CONTROL))
682 to->ContextFlags |= CONTEXT_I386_CONTROL;
683 to->Ebp = from->ctl.x86_64_regs.rbp;
684 to->Esp = from->ctl.x86_64_regs.rsp;
685 to->Eip = from->ctl.x86_64_regs.rip;
686 to->SegCs = from->ctl.x86_64_regs.cs;
687 to->SegSs = from->ctl.x86_64_regs.ss;
688 to->EFlags = from->ctl.x86_64_regs.flags;
690 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_I386_INTEGER))
692 to->ContextFlags |= CONTEXT_I386_INTEGER;
693 to->Eax = from->integer.x86_64_regs.rax;
694 to->Ebx = from->integer.x86_64_regs.rbx;
695 to->Ecx = from->integer.x86_64_regs.rcx;
696 to->Edx = from->integer.x86_64_regs.rdx;
697 to->Esi = from->integer.x86_64_regs.rsi;
698 to->Edi = from->integer.x86_64_regs.rdi;
700 if ((from->flags & SERVER_CTX_SEGMENTS) && (to_flags & CONTEXT_I386_SEGMENTS))
702 to->ContextFlags |= CONTEXT_I386_SEGMENTS;
703 to->SegDs = from->seg.x86_64_regs.ds;
704 to->SegEs = from->seg.x86_64_regs.es;
705 to->SegFs = from->seg.x86_64_regs.fs;
706 to->SegGs = from->seg.x86_64_regs.gs;
708 if (from->flags & SERVER_CTX_FLOATING_POINT)
710 if (to_flags & CONTEXT_I386_EXTENDED_REGISTERS)
712 to->ContextFlags |= CONTEXT_I386_EXTENDED_REGISTERS;
713 memcpy( to->ExtendedRegisters, from->fp.x86_64_regs.fpregs, sizeof(to->ExtendedRegisters) );
715 if (to_flags & CONTEXT_I386_FLOATING_POINT)
717 to->ContextFlags |= CONTEXT_I386_FLOATING_POINT;
718 fpux_to_fpu( &to->FloatSave, (XMM_SAVE_AREA32 *)from->fp.x86_64_regs.fpregs );
721 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_I386_DEBUG_REGISTERS))
723 to->ContextFlags |= CONTEXT_I386_DEBUG_REGISTERS;
724 to->Dr0 = from->debug.x86_64_regs.dr0;
725 to->Dr1 = from->debug.x86_64_regs.dr1;
726 to->Dr2 = from->debug.x86_64_regs.dr2;
727 to->Dr3 = from->debug.x86_64_regs.dr3;
728 to->Dr6 = from->debug.x86_64_regs.dr6;
729 to->Dr7 = from->debug.x86_64_regs.dr7;
731 if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_I386_XSTATE))
733 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
734 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
736 xs->Mask &= ~4;
737 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
738 for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++)
740 if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue;
741 memcpy( &xs->YmmContext, &from->ymm.regs, sizeof(xs->YmmContext) );
742 xs->Mask |= 4;
743 break;
746 return STATUS_SUCCESS;
749 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_AMD64 ):
751 AMD64_CONTEXT *to = dst;
753 to_flags = to->ContextFlags & ~CONTEXT_AMD64;
754 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_AMD64_CONTROL))
756 to->ContextFlags |= CONTEXT_AMD64_CONTROL;
757 to->Rbp = from->ctl.x86_64_regs.rbp;
758 to->Rip = from->ctl.x86_64_regs.rip;
759 to->Rsp = from->ctl.x86_64_regs.rsp;
760 to->SegCs = from->ctl.x86_64_regs.cs;
761 to->SegSs = from->ctl.x86_64_regs.ss;
762 to->EFlags = from->ctl.x86_64_regs.flags;
764 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_AMD64_INTEGER))
766 to->ContextFlags |= CONTEXT_AMD64_INTEGER;
767 to->Rax = from->integer.x86_64_regs.rax;
768 to->Rcx = from->integer.x86_64_regs.rcx;
769 to->Rdx = from->integer.x86_64_regs.rdx;
770 to->Rbx = from->integer.x86_64_regs.rbx;
771 to->Rsi = from->integer.x86_64_regs.rsi;
772 to->Rdi = from->integer.x86_64_regs.rdi;
773 to->R8 = from->integer.x86_64_regs.r8;
774 to->R9 = from->integer.x86_64_regs.r9;
775 to->R10 = from->integer.x86_64_regs.r10;
776 to->R11 = from->integer.x86_64_regs.r11;
777 to->R12 = from->integer.x86_64_regs.r12;
778 to->R13 = from->integer.x86_64_regs.r13;
779 to->R14 = from->integer.x86_64_regs.r14;
780 to->R15 = from->integer.x86_64_regs.r15;
782 if ((from->flags & SERVER_CTX_SEGMENTS) && (to_flags & CONTEXT_AMD64_SEGMENTS))
784 to->ContextFlags |= CONTEXT_AMD64_SEGMENTS;
785 to->SegDs = from->seg.x86_64_regs.ds;
786 to->SegEs = from->seg.x86_64_regs.es;
787 to->SegFs = from->seg.x86_64_regs.fs;
788 to->SegGs = from->seg.x86_64_regs.gs;
790 if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_AMD64_FLOATING_POINT))
792 to->ContextFlags |= CONTEXT_AMD64_FLOATING_POINT;
793 memcpy( &to->u.FltSave, from->fp.x86_64_regs.fpregs, sizeof(from->fp.x86_64_regs.fpregs) );
794 to->MxCsr = to->u.FltSave.MxCsr;
796 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_AMD64_DEBUG_REGISTERS))
798 to->ContextFlags |= CONTEXT_AMD64_DEBUG_REGISTERS;
799 to->Dr0 = from->debug.x86_64_regs.dr0;
800 to->Dr1 = from->debug.x86_64_regs.dr1;
801 to->Dr2 = from->debug.x86_64_regs.dr2;
802 to->Dr3 = from->debug.x86_64_regs.dr3;
803 to->Dr6 = from->debug.x86_64_regs.dr6;
804 to->Dr7 = from->debug.x86_64_regs.dr7;
806 if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_AMD64_XSTATE))
808 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
809 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
811 xs->Mask &= ~4;
812 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
813 for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++)
815 if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue;
816 memcpy( &xs->YmmContext, &from->ymm.regs, sizeof(xs->YmmContext) );
817 xs->Mask |= 4;
818 break;
821 return STATUS_SUCCESS;
824 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_AMD64 ):
826 AMD64_CONTEXT *to = dst;
828 to_flags = to->ContextFlags & ~CONTEXT_AMD64;
829 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_AMD64_CONTROL))
831 to->ContextFlags |= CONTEXT_AMD64_CONTROL;
832 to->Rbp = from->ctl.i386_regs.ebp;
833 to->Rip = from->ctl.i386_regs.eip;
834 to->Rsp = from->ctl.i386_regs.esp;
835 to->SegCs = from->ctl.i386_regs.cs;
836 to->SegSs = from->ctl.i386_regs.ss;
837 to->EFlags = from->ctl.i386_regs.eflags;
839 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_AMD64_INTEGER))
841 to->ContextFlags |= CONTEXT_AMD64_INTEGER;
842 to->Rax = from->integer.i386_regs.eax;
843 to->Rcx = from->integer.i386_regs.ecx;
844 to->Rdx = from->integer.i386_regs.edx;
845 to->Rbx = from->integer.i386_regs.ebx;
846 to->Rsi = from->integer.i386_regs.esi;
847 to->Rdi = from->integer.i386_regs.edi;
849 if ((from->flags & SERVER_CTX_SEGMENTS) && (to_flags & CONTEXT_AMD64_SEGMENTS))
851 to->ContextFlags |= CONTEXT_AMD64_SEGMENTS;
852 to->SegDs = from->seg.i386_regs.ds;
853 to->SegEs = from->seg.i386_regs.es;
854 to->SegFs = from->seg.i386_regs.fs;
855 to->SegGs = from->seg.i386_regs.gs;
857 if ((from->flags & SERVER_CTX_EXTENDED_REGISTERS) && (to_flags & CONTEXT_AMD64_FLOATING_POINT))
859 to->ContextFlags |= CONTEXT_AMD64_FLOATING_POINT;
860 memcpy( &to->u.FltSave, from->ext.i386_regs, sizeof(to->u.FltSave) );
862 else if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_AMD64_FLOATING_POINT))
864 I386_FLOATING_SAVE_AREA fpu;
866 to->ContextFlags |= CONTEXT_AMD64_FLOATING_POINT;
867 fpu.ControlWord = from->fp.i386_regs.ctrl;
868 fpu.StatusWord = from->fp.i386_regs.status;
869 fpu.TagWord = from->fp.i386_regs.tag;
870 fpu.ErrorOffset = from->fp.i386_regs.err_off;
871 fpu.ErrorSelector = from->fp.i386_regs.err_sel;
872 fpu.DataOffset = from->fp.i386_regs.data_off;
873 fpu.DataSelector = from->fp.i386_regs.data_sel;
874 fpu.Cr0NpxState = from->fp.i386_regs.cr0npx;
875 memcpy( fpu.RegisterArea, from->fp.i386_regs.regs, sizeof(fpu.RegisterArea) );
876 fpu_to_fpux( &to->u.FltSave, &fpu );
878 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_AMD64_DEBUG_REGISTERS))
880 to->ContextFlags |= CONTEXT_AMD64_DEBUG_REGISTERS;
881 to->Dr0 = from->debug.i386_regs.dr0;
882 to->Dr1 = from->debug.i386_regs.dr1;
883 to->Dr2 = from->debug.i386_regs.dr2;
884 to->Dr3 = from->debug.i386_regs.dr3;
885 to->Dr6 = from->debug.i386_regs.dr6;
886 to->Dr7 = from->debug.i386_regs.dr7;
888 if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_AMD64_XSTATE))
890 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
891 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
893 xs->Mask &= ~4;
894 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
895 for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++)
897 if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue;
898 memcpy( &xs->YmmContext, &from->ymm.regs, sizeof(xs->YmmContext) );
899 xs->Mask |= 4;
900 break;
903 return STATUS_SUCCESS;
906 case MAKELONG( IMAGE_FILE_MACHINE_ARMNT, IMAGE_FILE_MACHINE_ARMNT ):
908 ARM_CONTEXT *to = dst;
910 to_flags = to->ContextFlags & ~CONTEXT_ARM;
911 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_ARM_CONTROL))
913 to->ContextFlags |= CONTEXT_ARM_CONTROL;
914 to->Sp = from->ctl.arm_regs.sp;
915 to->Lr = from->ctl.arm_regs.lr;
916 to->Pc = from->ctl.arm_regs.pc;
917 to->Cpsr = from->ctl.arm_regs.cpsr;
919 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_ARM_INTEGER))
921 to->ContextFlags |= CONTEXT_ARM_INTEGER;
922 to->R0 = from->integer.arm_regs.r[0];
923 to->R1 = from->integer.arm_regs.r[1];
924 to->R2 = from->integer.arm_regs.r[2];
925 to->R3 = from->integer.arm_regs.r[3];
926 to->R4 = from->integer.arm_regs.r[4];
927 to->R5 = from->integer.arm_regs.r[5];
928 to->R6 = from->integer.arm_regs.r[6];
929 to->R7 = from->integer.arm_regs.r[7];
930 to->R8 = from->integer.arm_regs.r[8];
931 to->R9 = from->integer.arm_regs.r[9];
932 to->R10 = from->integer.arm_regs.r[10];
933 to->R11 = from->integer.arm_regs.r[11];
934 to->R12 = from->integer.arm_regs.r[12];
936 if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_ARM_FLOATING_POINT))
938 to->ContextFlags |= CONTEXT_ARM_FLOATING_POINT;
939 for (i = 0; i < 32; i++) to->u.D[i] = from->fp.arm_regs.d[i];
940 to->Fpscr = from->fp.arm_regs.fpscr;
942 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_ARM_DEBUG_REGISTERS))
944 to->ContextFlags |= CONTEXT_ARM_DEBUG_REGISTERS;
945 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm_regs.bvr[i];
946 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm_regs.bcr[i];
947 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm_regs.wvr[i];
948 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm_regs.wcr[i];
950 return STATUS_SUCCESS;
953 case MAKELONG( IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_ARM64 ):
955 ARM64_NT_CONTEXT *to = dst;
957 to_flags = to->ContextFlags & ~CONTEXT_ARM64;
958 to->ContextFlags = CONTEXT_ARM64;
959 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_ARM64_CONTROL))
961 to->ContextFlags |= CONTEXT_ARM64_CONTROL;
962 to->u.s.Fp = from->integer.arm64_regs.x[29];
963 to->u.s.Lr = from->integer.arm64_regs.x[30];
964 to->Sp = from->ctl.arm64_regs.sp;
965 to->Pc = from->ctl.arm64_regs.pc;
966 to->Cpsr = from->ctl.arm64_regs.pstate;
968 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_ARM64_INTEGER))
970 to->ContextFlags |= CONTEXT_ARM64_INTEGER;
971 for (i = 0; i <= 28; i++) to->u.X[i] = from->integer.arm64_regs.x[i];
973 if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_ARM64_FLOATING_POINT))
975 to->ContextFlags |= CONTEXT_ARM64_FLOATING_POINT;
976 for (i = 0; i < 32; i++)
978 to->V[i].s.Low = from->fp.arm64_regs.q[i].low;
979 to->V[i].s.High = from->fp.arm64_regs.q[i].high;
981 to->Fpcr = from->fp.arm64_regs.fpcr;
982 to->Fpsr = from->fp.arm64_regs.fpsr;
984 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_ARM64_DEBUG_REGISTERS))
986 to->ContextFlags |= CONTEXT_ARM64_DEBUG_REGISTERS;
987 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm64_regs.bcr[i];
988 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm64_regs.bvr[i];
989 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm64_regs.wcr[i];
990 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm64_regs.wvr[i];
992 return STATUS_SUCCESS;
995 default:
996 return STATUS_INVALID_PARAMETER;
1001 /***********************************************************************
1002 * contexts_to_server
1004 static void contexts_to_server( context_t server_contexts[2], CONTEXT *context )
1006 unsigned int count = 0;
1007 void *native_context = get_native_context( context );
1008 void *wow_context = get_wow_context( context );
1010 if (native_context)
1012 context_to_server( &server_contexts[count++], native_machine, native_context, native_machine );
1013 if (wow_context) context_to_server( &server_contexts[count++], main_image_info.Machine,
1014 wow_context, main_image_info.Machine );
1015 else if (native_machine != main_image_info.Machine)
1016 context_to_server( &server_contexts[count++], main_image_info.Machine,
1017 native_context, native_machine );
1019 else
1020 context_to_server( &server_contexts[count++], native_machine,
1021 wow_context, main_image_info.Machine );
1023 if (count < 2) memset( &server_contexts[1], 0, sizeof(server_contexts[1]) );
1027 /***********************************************************************
1028 * contexts_from_server
1030 static void contexts_from_server( CONTEXT *context, context_t server_contexts[2] )
1032 void *native_context = get_native_context( context );
1033 void *wow_context = get_wow_context( context );
1035 if (native_context)
1037 context_from_server( native_context, &server_contexts[0], native_machine );
1038 if (wow_context) context_from_server( wow_context, &server_contexts[1], main_image_info.Machine );
1040 else context_from_server( wow_context, &server_contexts[0], main_image_info.Machine );
1044 /***********************************************************************
1045 * pthread_exit_wrapper
1047 static void pthread_exit_wrapper( int status )
1049 close( ntdll_get_thread_data()->wait_fd[0] );
1050 close( ntdll_get_thread_data()->wait_fd[1] );
1051 close( ntdll_get_thread_data()->reply_fd );
1052 close( ntdll_get_thread_data()->request_fd );
1053 pthread_exit( UIntToPtr(status) );
1057 /***********************************************************************
1058 * start_thread
1060 * Startup routine for a newly created thread.
1062 static void start_thread( TEB *teb )
1064 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1065 BOOL suspend;
1067 thread_data->pthread_id = pthread_self();
1068 signal_init_thread( teb );
1069 server_init_thread( thread_data->start, &suspend );
1070 signal_start_thread( thread_data->start, thread_data->param, suspend, teb );
1074 /***********************************************************************
1075 * get_machine_context_size
1077 static SIZE_T get_machine_context_size( USHORT machine )
1079 switch (machine)
1081 case IMAGE_FILE_MACHINE_I386: return sizeof(I386_CONTEXT);
1082 case IMAGE_FILE_MACHINE_ARMNT: return sizeof(ARM_CONTEXT);
1083 case IMAGE_FILE_MACHINE_AMD64: return sizeof(AMD64_CONTEXT);
1084 case IMAGE_FILE_MACHINE_ARM64: return sizeof(ARM64_NT_CONTEXT);
1085 default: return 0;
1090 /***********************************************************************
1091 * get_cpu_area
1093 * cf. RtlWow64GetCurrentCpuArea
1095 void *get_cpu_area( USHORT machine )
1097 WOW64_CPURESERVED *cpu;
1098 ULONG align;
1100 if (!NtCurrentTeb()->WowTebOffset) return NULL;
1101 #ifdef _WIN64
1102 cpu = NtCurrentTeb()->TlsSlots[WOW64_TLS_CPURESERVED];
1103 #else
1104 cpu = ULongToPtr( NtCurrentTeb64()->TlsSlots[WOW64_TLS_CPURESERVED] );
1105 #endif
1106 if (cpu->Machine != machine) return NULL;
1107 switch (cpu->Machine)
1109 case IMAGE_FILE_MACHINE_I386: align = TYPE_ALIGNMENT(I386_CONTEXT); break;
1110 case IMAGE_FILE_MACHINE_AMD64: align = TYPE_ALIGNMENT(AMD64_CONTEXT); break;
1111 case IMAGE_FILE_MACHINE_ARMNT: align = TYPE_ALIGNMENT(ARM_CONTEXT); break;
1112 case IMAGE_FILE_MACHINE_ARM64: align = TYPE_ALIGNMENT(ARM64_NT_CONTEXT); break;
1113 default: return NULL;
1115 return (void *)(((ULONG_PTR)(cpu + 1) + align - 1) & ~((ULONG_PTR)align - 1));
1119 /***********************************************************************
1120 * set_thread_id
1122 void set_thread_id( TEB *teb, DWORD pid, DWORD tid )
1124 WOW_TEB *wow_teb = get_wow_teb( teb );
1126 teb->ClientId.UniqueProcess = ULongToHandle( pid );
1127 teb->ClientId.UniqueThread = ULongToHandle( tid );
1128 teb->RealClientId = teb->ClientId;
1129 if (wow_teb)
1131 wow_teb->ClientId.UniqueProcess = pid;
1132 wow_teb->ClientId.UniqueThread = tid;
1133 wow_teb->RealClientId = wow_teb->ClientId;
1138 /***********************************************************************
1139 * init_thread_stack
1141 NTSTATUS init_thread_stack( TEB *teb, ULONG_PTR zero_bits, SIZE_T reserve_size, SIZE_T commit_size )
1143 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1144 WOW_TEB *wow_teb = get_wow_teb( teb );
1145 INITIAL_TEB stack;
1146 NTSTATUS status;
1148 if (wow_teb)
1150 WOW64_CPURESERVED *cpu;
1151 SIZE_T cpusize = sizeof(WOW64_CPURESERVED) +
1152 ((get_machine_context_size( main_image_info.Machine ) + 7) & ~7) + sizeof(ULONG64);
1154 #ifdef _WIN64
1155 /* 32-bit stack */
1156 if ((status = virtual_alloc_thread_stack( &stack, zero_bits ? zero_bits : 0x7fffffff,
1157 reserve_size, commit_size, 0 )))
1158 return status;
1159 wow_teb->Tib.StackBase = PtrToUlong( stack.StackBase );
1160 wow_teb->Tib.StackLimit = PtrToUlong( stack.StackLimit );
1161 wow_teb->DeallocationStack = PtrToUlong( stack.DeallocationStack );
1163 /* 64-bit stack */
1164 if ((status = virtual_alloc_thread_stack( &stack, 0, 0x40000, 0x40000, kernel_stack_size )))
1165 return status;
1166 cpu = (WOW64_CPURESERVED *)(((ULONG_PTR)stack.StackBase - cpusize) & ~15);
1167 cpu->Machine = main_image_info.Machine;
1168 teb->Tib.StackBase = teb->TlsSlots[WOW64_TLS_CPURESERVED] = cpu;
1169 teb->Tib.StackLimit = stack.StackLimit;
1170 teb->DeallocationStack = stack.DeallocationStack;
1171 thread_data->kernel_stack = stack.StackBase;
1172 return STATUS_SUCCESS;
1173 #else
1174 /* 64-bit stack */
1175 if ((status = virtual_alloc_thread_stack( &stack, 0, 0x40000, 0x40000, 0 ))) return status;
1177 cpu = (WOW64_CPURESERVED *)(((ULONG_PTR)stack.StackBase - cpusize) & ~15);
1178 cpu->Machine = main_image_info.Machine;
1179 wow_teb->Tib.StackBase = wow_teb->TlsSlots[WOW64_TLS_CPURESERVED] = PtrToUlong( cpu );
1180 wow_teb->Tib.StackLimit = PtrToUlong( stack.StackLimit );
1181 wow_teb->DeallocationStack = PtrToUlong( stack.DeallocationStack );
1182 #endif
1185 /* native stack */
1186 if ((status = virtual_alloc_thread_stack( &stack, zero_bits, reserve_size,
1187 commit_size, kernel_stack_size )))
1188 return status;
1189 teb->Tib.StackBase = stack.StackBase;
1190 teb->Tib.StackLimit = stack.StackLimit;
1191 teb->DeallocationStack = stack.DeallocationStack;
1192 thread_data->kernel_stack = stack.StackBase;
1193 return STATUS_SUCCESS;
1197 /***********************************************************************
1198 * update_attr_list
1200 * Update the output attributes.
1202 static void update_attr_list( PS_ATTRIBUTE_LIST *attr, const CLIENT_ID *id, TEB *teb )
1204 SIZE_T i, count = (attr->TotalLength - sizeof(attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
1206 for (i = 0; i < count; i++)
1208 if (attr->Attributes[i].Attribute == PS_ATTRIBUTE_CLIENT_ID)
1210 SIZE_T size = min( attr->Attributes[i].Size, sizeof(*id) );
1211 memcpy( attr->Attributes[i].ValuePtr, id, size );
1212 if (attr->Attributes[i].ReturnLength) *attr->Attributes[i].ReturnLength = size;
1214 else if (attr->Attributes[i].Attribute == PS_ATTRIBUTE_TEB_ADDRESS)
1216 SIZE_T size = min( attr->Attributes[i].Size, sizeof(teb) );
1217 memcpy( attr->Attributes[i].ValuePtr, &teb, size );
1218 if (attr->Attributes[i].ReturnLength) *attr->Attributes[i].ReturnLength = size;
1223 /***********************************************************************
1224 * NtCreateThread (NTDLL.@)
1226 NTSTATUS WINAPI NtCreateThread( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
1227 HANDLE process, CLIENT_ID *id, CONTEXT *ctx, INITIAL_TEB *teb,
1228 BOOLEAN suspended )
1230 FIXME( "%p %d %p %p %p %p %p %d, stub!\n", handle, access, attr, process, id, ctx, teb, suspended );
1231 return STATUS_NOT_IMPLEMENTED;
1234 /***********************************************************************
1235 * NtCreateThreadEx (NTDLL.@)
1237 NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
1238 HANDLE process, PRTL_THREAD_START_ROUTINE start, void *param,
1239 ULONG flags, ULONG_PTR zero_bits, SIZE_T stack_commit,
1240 SIZE_T stack_reserve, PS_ATTRIBUTE_LIST *attr_list )
1242 static const ULONG supported_flags = THREAD_CREATE_FLAGS_CREATE_SUSPENDED | THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER;
1243 sigset_t sigset;
1244 pthread_t pthread_id;
1245 pthread_attr_t pthread_attr;
1246 data_size_t len;
1247 struct object_attributes *objattr;
1248 struct ntdll_thread_data *thread_data;
1249 DWORD tid = 0;
1250 int request_pipe[2];
1251 TEB *teb;
1252 NTSTATUS status;
1254 if (flags & ~supported_flags)
1255 FIXME( "Unsupported flags %#x.\n", flags );
1257 if (zero_bits > 21 && zero_bits < 32) return STATUS_INVALID_PARAMETER_3;
1258 #ifndef _WIN64
1259 if (!is_wow64 && zero_bits >= 32) return STATUS_INVALID_PARAMETER_3;
1260 #endif
1262 if (process != NtCurrentProcess())
1264 apc_call_t call;
1265 apc_result_t result;
1267 memset( &call, 0, sizeof(call) );
1269 call.create_thread.type = APC_CREATE_THREAD;
1270 call.create_thread.flags = flags;
1271 call.create_thread.func = wine_server_client_ptr( start );
1272 call.create_thread.arg = wine_server_client_ptr( param );
1273 call.create_thread.zero_bits = zero_bits;
1274 call.create_thread.reserve = stack_reserve;
1275 call.create_thread.commit = stack_commit;
1276 status = server_queue_process_apc( process, &call, &result );
1277 if (status != STATUS_SUCCESS) return status;
1279 if (result.create_thread.status == STATUS_SUCCESS)
1281 CLIENT_ID client_id;
1282 TEB *teb = wine_server_get_ptr( result.create_thread.teb );
1283 *handle = wine_server_ptr_handle( result.create_thread.handle );
1284 client_id.UniqueProcess = ULongToHandle( result.create_thread.pid );
1285 client_id.UniqueThread = ULongToHandle( result.create_thread.tid );
1286 if (attr_list) update_attr_list( attr_list, &client_id, teb );
1288 return result.create_thread.status;
1291 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
1293 if (server_pipe( request_pipe ) == -1)
1295 free( objattr );
1296 return STATUS_TOO_MANY_OPENED_FILES;
1298 wine_server_send_fd( request_pipe[0] );
1300 if (!access) access = THREAD_ALL_ACCESS;
1302 SERVER_START_REQ( new_thread )
1304 req->process = wine_server_obj_handle( process );
1305 req->access = access;
1306 req->flags = flags;
1307 req->request_fd = request_pipe[0];
1308 wine_server_add_data( req, objattr, len );
1309 if (!(status = wine_server_call( req )))
1311 *handle = wine_server_ptr_handle( reply->handle );
1312 tid = reply->tid;
1314 close( request_pipe[0] );
1316 SERVER_END_REQ;
1318 free( objattr );
1319 if (status)
1321 close( request_pipe[1] );
1322 return status;
1325 pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
1327 if ((status = virtual_alloc_teb( &teb ))) goto done;
1329 if ((status = init_thread_stack( teb, zero_bits, stack_reserve, stack_commit )))
1331 virtual_free_teb( teb );
1332 goto done;
1335 set_thread_id( teb, GetCurrentProcessId(), tid );
1337 thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1338 thread_data->request_fd = request_pipe[1];
1339 thread_data->start = start;
1340 thread_data->param = param;
1342 pthread_attr_init( &pthread_attr );
1343 pthread_attr_setstack( &pthread_attr, teb->DeallocationStack,
1344 (char *)thread_data->kernel_stack + kernel_stack_size - (char *)teb->DeallocationStack );
1345 pthread_attr_setguardsize( &pthread_attr, 0 );
1346 pthread_attr_setscope( &pthread_attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a kernel thread */
1347 InterlockedIncrement( &nb_threads );
1348 if (pthread_create( &pthread_id, &pthread_attr, (void * (*)(void *))start_thread, teb ))
1350 InterlockedDecrement( &nb_threads );
1351 virtual_free_teb( teb );
1352 status = STATUS_NO_MEMORY;
1354 pthread_attr_destroy( &pthread_attr );
1356 done:
1357 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
1358 if (status)
1360 NtClose( *handle );
1361 close( request_pipe[1] );
1362 return status;
1364 if (attr_list) update_attr_list( attr_list, &teb->ClientId, teb );
1365 return STATUS_SUCCESS;
1369 /***********************************************************************
1370 * abort_thread
1372 void abort_thread( int status )
1374 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
1375 if (InterlockedDecrement( &nb_threads ) <= 0) abort_process( status );
1376 signal_exit_thread( status, pthread_exit_wrapper, NtCurrentTeb() );
1380 /***********************************************************************
1381 * abort_process
1383 void abort_process( int status )
1385 _exit( get_unix_exit_code( status ));
1389 /***********************************************************************
1390 * exit_thread
1392 static DECLSPEC_NORETURN void exit_thread( int status )
1394 static void *prev_teb;
1395 TEB *teb;
1397 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
1399 if ((teb = InterlockedExchangePointer( &prev_teb, NtCurrentTeb() )))
1401 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1403 if (thread_data->pthread_id)
1405 pthread_join( thread_data->pthread_id, NULL );
1406 virtual_free_teb( teb );
1409 signal_exit_thread( status, pthread_exit_wrapper, NtCurrentTeb() );
1413 /***********************************************************************
1414 * exit_process
1416 void exit_process( int status )
1418 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
1419 signal_exit_thread( get_unix_exit_code( status ), process_exit_wrapper, NtCurrentTeb() );
1423 /**********************************************************************
1424 * wait_suspend
1426 * Wait until the thread is no longer suspended.
1428 void wait_suspend( CONTEXT *context )
1430 int saved_errno = errno;
1431 context_t server_contexts[2];
1433 contexts_to_server( server_contexts, context );
1434 /* wait with 0 timeout, will only return once the thread is no longer suspended */
1435 server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, server_contexts, NULL );
1436 contexts_from_server( context, server_contexts );
1437 errno = saved_errno;
1441 /**********************************************************************
1442 * send_debug_event
1444 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
1446 NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1448 NTSTATUS ret;
1449 DWORD i;
1450 obj_handle_t handle = 0;
1451 client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
1452 select_op_t select_op;
1453 sigset_t old_set;
1455 if (!peb->BeingDebugged) return 0; /* no debugger present */
1457 pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set );
1459 for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++)
1460 params[i] = rec->ExceptionInformation[i];
1462 SERVER_START_REQ( queue_exception_event )
1464 req->first = first_chance;
1465 req->code = rec->ExceptionCode;
1466 req->flags = rec->ExceptionFlags;
1467 req->record = wine_server_client_ptr( rec->ExceptionRecord );
1468 req->address = wine_server_client_ptr( rec->ExceptionAddress );
1469 req->len = i * sizeof(params[0]);
1470 wine_server_add_data( req, params, req->len );
1471 if (!(ret = wine_server_call( req ))) handle = reply->handle;
1473 SERVER_END_REQ;
1475 if (handle)
1477 context_t server_contexts[2];
1479 select_op.wait.op = SELECT_WAIT;
1480 select_op.wait.handles[0] = handle;
1482 contexts_to_server( server_contexts, context );
1483 server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE,
1484 TIMEOUT_INFINITE, server_contexts, NULL );
1486 SERVER_START_REQ( get_exception_status )
1488 req->handle = handle;
1489 ret = wine_server_call( req );
1491 SERVER_END_REQ;
1492 if (ret >= 0) contexts_from_server( context, server_contexts );
1495 pthread_sigmask( SIG_SETMASK, &old_set, NULL );
1496 return ret;
1500 /*******************************************************************
1501 * NtRaiseException (NTDLL.@)
1503 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1505 NTSTATUS status = send_debug_event( rec, context, first_chance );
1507 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
1508 return NtContinue( context, FALSE );
1510 if (first_chance) return call_user_exception_dispatcher( rec, context );
1512 if (rec->ExceptionFlags & EH_STACK_INVALID)
1513 ERR_(seh)("Exception frame is not in stack limits => unable to dispatch exception.\n");
1514 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
1515 ERR_(seh)("Process attempted to continue execution after noncontinuable exception.\n");
1516 else
1517 ERR_(seh)("Unhandled exception code %x flags %x addr %p\n",
1518 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
1520 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
1521 return STATUS_SUCCESS;
1525 /***********************************************************************
1526 * NtOpenThread (NTDLL.@)
1528 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
1529 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
1531 NTSTATUS ret;
1533 *handle = 0;
1535 SERVER_START_REQ( open_thread )
1537 req->tid = HandleToULong(id->UniqueThread);
1538 req->access = access;
1539 req->attributes = attr ? attr->Attributes : 0;
1540 ret = wine_server_call( req );
1541 *handle = wine_server_ptr_handle( reply->handle );
1543 SERVER_END_REQ;
1544 return ret;
1548 /******************************************************************************
1549 * NtSuspendThread (NTDLL.@)
1551 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count )
1553 NTSTATUS ret;
1555 SERVER_START_REQ( suspend_thread )
1557 req->handle = wine_server_obj_handle( handle );
1558 if (!(ret = wine_server_call( req )))
1560 if (count) *count = reply->count;
1563 SERVER_END_REQ;
1564 return ret;
1568 /******************************************************************************
1569 * NtResumeThread (NTDLL.@)
1571 NTSTATUS WINAPI NtResumeThread( HANDLE handle, ULONG *count )
1573 NTSTATUS ret;
1575 SERVER_START_REQ( resume_thread )
1577 req->handle = wine_server_obj_handle( handle );
1578 if (!(ret = wine_server_call( req )))
1580 if (count) *count = reply->count;
1583 SERVER_END_REQ;
1584 return ret;
1588 /******************************************************************************
1589 * NtAlertResumeThread (NTDLL.@)
1591 NTSTATUS WINAPI NtAlertResumeThread( HANDLE handle, ULONG *count )
1593 FIXME( "stub: should alert thread %p\n", handle );
1594 return NtResumeThread( handle, count );
1598 /******************************************************************************
1599 * NtAlertThread (NTDLL.@)
1601 NTSTATUS WINAPI NtAlertThread( HANDLE handle )
1603 FIXME( "stub: %p\n", handle );
1604 return STATUS_NOT_IMPLEMENTED;
1608 /******************************************************************************
1609 * NtTerminateThread (NTDLL.@)
1611 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
1613 NTSTATUS ret;
1614 BOOL self;
1616 SERVER_START_REQ( terminate_thread )
1618 req->handle = wine_server_obj_handle( handle );
1619 req->exit_code = exit_code;
1620 ret = wine_server_call( req );
1621 self = !ret && reply->self;
1623 SERVER_END_REQ;
1625 if (self)
1627 server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, NULL, NULL );
1628 exit_thread( exit_code );
1630 return ret;
1634 /******************************************************************************
1635 * NtQueueApcThread (NTDLL.@)
1637 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
1638 ULONG_PTR arg2, ULONG_PTR arg3 )
1640 NTSTATUS ret;
1642 SERVER_START_REQ( queue_apc )
1644 req->handle = wine_server_obj_handle( handle );
1645 if (func)
1647 req->call.type = APC_USER;
1648 req->call.user.func = wine_server_client_ptr( func );
1649 req->call.user.args[0] = arg1;
1650 req->call.user.args[1] = arg2;
1651 req->call.user.args[2] = arg3;
1653 else req->call.type = APC_NONE; /* wake up only */
1654 ret = wine_server_call( req );
1656 SERVER_END_REQ;
1657 return ret;
1661 /***********************************************************************
1662 * set_thread_context
1664 NTSTATUS set_thread_context( HANDLE handle, const void *context, BOOL *self, USHORT machine )
1666 context_t server_contexts[2];
1667 unsigned int count = 0;
1668 NTSTATUS ret;
1670 context_to_server( &server_contexts[count++], native_machine, context, machine );
1671 if (machine != native_machine)
1672 context_to_server( &server_contexts[count++], machine, context, machine );
1674 SERVER_START_REQ( set_thread_context )
1676 req->handle = wine_server_obj_handle( handle );
1677 wine_server_add_data( req, server_contexts, count * sizeof(server_contexts[0]) );
1678 ret = wine_server_call( req );
1679 *self = reply->self;
1681 SERVER_END_REQ;
1683 return ret;
1687 /***********************************************************************
1688 * get_thread_context
1690 NTSTATUS get_thread_context( HANDLE handle, void *context, BOOL *self, USHORT machine )
1692 NTSTATUS ret;
1693 HANDLE context_handle;
1694 context_t server_contexts[2];
1695 unsigned int count;
1696 unsigned int flags = get_server_context_flags( context, machine );
1698 SERVER_START_REQ( get_thread_context )
1700 req->handle = wine_server_obj_handle( handle );
1701 req->flags = flags;
1702 req->machine = machine;
1703 wine_server_set_reply( req, server_contexts, sizeof(server_contexts) );
1704 ret = wine_server_call( req );
1705 *self = reply->self;
1706 context_handle = wine_server_ptr_handle( reply->handle );
1707 count = wine_server_reply_size( reply ) / sizeof(server_contexts[0]);
1709 SERVER_END_REQ;
1711 if (ret == STATUS_PENDING)
1713 NtWaitForSingleObject( context_handle, FALSE, NULL );
1715 SERVER_START_REQ( get_thread_context )
1717 req->context = wine_server_obj_handle( context_handle );
1718 req->flags = flags;
1719 req->machine = machine;
1720 wine_server_set_reply( req, server_contexts, sizeof(server_contexts) );
1721 ret = wine_server_call( req );
1722 count = wine_server_reply_size( reply ) / sizeof(server_contexts[0]);
1724 SERVER_END_REQ;
1726 if (!ret)
1728 ret = context_from_server( context, &server_contexts[0], machine );
1729 if (!ret && count > 1) ret = context_from_server( context, &server_contexts[1], machine );
1731 return ret;
1735 /***********************************************************************
1736 * ntdll_set_exception_jmp_buf
1738 void ntdll_set_exception_jmp_buf( __wine_jmp_buf *jmp )
1740 assert( !jmp || !ntdll_get_thread_data()->jmp_buf );
1741 ntdll_get_thread_data()->jmp_buf = jmp;
1745 BOOL get_thread_times(int unix_pid, int unix_tid, LARGE_INTEGER *kernel_time, LARGE_INTEGER *user_time)
1747 #ifdef linux
1748 unsigned long clocks_per_sec = sysconf( _SC_CLK_TCK );
1749 unsigned long usr, sys;
1750 const char *pos;
1751 char buf[512];
1752 FILE *f;
1753 int i;
1755 if (unix_tid == -1)
1756 sprintf( buf, "/proc/%u/stat", unix_pid );
1757 else
1758 sprintf( buf, "/proc/%u/task/%u/stat", unix_pid, unix_tid );
1759 if (!(f = fopen( buf, "r" )))
1761 WARN("Failed to open %s: %s\n", buf, strerror(errno));
1762 return FALSE;
1765 pos = fgets( buf, sizeof(buf), f );
1766 fclose( f );
1768 /* the process name is printed unescaped, so we have to skip to the last ')'
1769 * to avoid misinterpreting the string */
1770 if (pos) pos = strrchr( pos, ')' );
1771 if (pos) pos = strchr( pos + 1, ' ' );
1772 if (pos) pos++;
1774 /* skip over the following fields: state, ppid, pgid, sid, tty_nr, tty_pgrp,
1775 * task->flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
1776 for (i = 0; i < 11 && pos; i++)
1778 pos = strchr( pos + 1, ' ' );
1779 if (pos) pos++;
1782 /* the next two values are user and system time */
1783 if (pos && (sscanf( pos, "%lu %lu", &usr, &sys ) == 2))
1785 kernel_time->QuadPart = (ULONGLONG)sys * 10000000 / clocks_per_sec;
1786 user_time->QuadPart = (ULONGLONG)usr * 10000000 / clocks_per_sec;
1787 return TRUE;
1790 ERR("Failed to parse %s\n", debugstr_a(buf));
1791 return FALSE;
1792 #elif defined(HAVE_LIBPROCSTAT)
1793 struct procstat *pstat;
1794 struct kinfo_proc *kip;
1795 unsigned int proc_count;
1796 BOOL ret = FALSE;
1798 pstat = procstat_open_sysctl();
1799 if (!pstat)
1800 return FALSE;
1801 if (unix_tid == -1)
1802 kip = procstat_getprocs(pstat, KERN_PROC_PID, unix_pid, &proc_count);
1803 else
1804 kip = procstat_getprocs(pstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, unix_pid, &proc_count);
1805 if (kip)
1807 unsigned int i;
1808 for (i = 0; i < proc_count; i++)
1810 if (unix_tid == -1 || kip[i].ki_tid == unix_tid)
1812 kernel_time->QuadPart = 10000000 * (ULONGLONG)kip[i].ki_rusage.ru_stime.tv_sec +
1813 10 * (ULONGLONG)kip[i].ki_rusage.ru_stime.tv_usec;
1814 user_time->QuadPart = 10000000 * (ULONGLONG)kip[i].ki_rusage.ru_utime.tv_sec +
1815 10 * (ULONGLONG)kip[i].ki_rusage.ru_utime.tv_usec;
1816 ret = TRUE;
1817 break;
1820 procstat_freeprocs(pstat, kip);
1822 procstat_close(pstat);
1823 return ret;
1824 #else
1825 static int once;
1826 if (!once++) FIXME("not implemented on this platform\n");
1827 return FALSE;
1828 #endif
1831 #ifndef _WIN64
1832 static BOOL is_process_wow64( const CLIENT_ID *id )
1834 HANDLE handle;
1835 ULONG_PTR info;
1836 BOOL ret = FALSE;
1838 if (id->UniqueProcess == ULongToHandle(GetCurrentProcessId())) return is_wow64;
1839 if (!NtOpenProcess( &handle, PROCESS_QUERY_LIMITED_INFORMATION, NULL, id ))
1841 if (!NtQueryInformationProcess( handle, ProcessWow64Information, &info, sizeof(info), NULL ))
1842 ret = !!info;
1843 NtClose( handle );
1845 return ret;
1847 #endif
1849 /******************************************************************************
1850 * NtQueryInformationThread (NTDLL.@)
1852 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
1853 void *data, ULONG length, ULONG *ret_len )
1855 NTSTATUS status;
1857 TRACE("(%p,%d,%p,%x,%p)\n", handle, class, data, length, ret_len);
1859 switch (class)
1861 case ThreadBasicInformation:
1863 THREAD_BASIC_INFORMATION info;
1864 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1866 SERVER_START_REQ( get_thread_info )
1868 req->handle = wine_server_obj_handle( handle );
1869 if (!(status = wine_server_call( req )))
1871 info.ExitStatus = reply->exit_code;
1872 info.TebBaseAddress = wine_server_get_ptr( reply->teb );
1873 info.ClientId.UniqueProcess = ULongToHandle(reply->pid);
1874 info.ClientId.UniqueThread = ULongToHandle(reply->tid);
1875 info.AffinityMask = reply->affinity & affinity_mask;
1876 info.Priority = reply->priority;
1877 info.BasePriority = reply->priority; /* FIXME */
1880 SERVER_END_REQ;
1881 if (status == STATUS_SUCCESS)
1883 #ifndef _WIN64
1884 if (is_wow64)
1886 if (is_process_wow64( &info.ClientId ))
1887 info.TebBaseAddress = (char *)info.TebBaseAddress + teb_offset;
1888 else
1889 info.TebBaseAddress = NULL;
1891 #endif
1892 if (data) memcpy( data, &info, min( length, sizeof(info) ));
1893 if (ret_len) *ret_len = min( length, sizeof(info) );
1895 return status;
1898 case ThreadAffinityMask:
1900 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1901 ULONG_PTR affinity = 0;
1903 SERVER_START_REQ( get_thread_info )
1905 req->handle = wine_server_obj_handle( handle );
1906 req->access = THREAD_QUERY_INFORMATION;
1907 if (!(status = wine_server_call( req ))) affinity = reply->affinity & affinity_mask;
1909 SERVER_END_REQ;
1910 if (status == STATUS_SUCCESS)
1912 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
1913 if (ret_len) *ret_len = min( length, sizeof(affinity) );
1915 return status;
1918 case ThreadTimes:
1920 KERNEL_USER_TIMES kusrt;
1921 int unix_pid, unix_tid;
1923 SERVER_START_REQ( get_thread_times )
1925 req->handle = wine_server_obj_handle( handle );
1926 status = wine_server_call( req );
1927 if (status == STATUS_SUCCESS)
1929 kusrt.CreateTime.QuadPart = reply->creation_time;
1930 kusrt.ExitTime.QuadPart = reply->exit_time;
1931 unix_pid = reply->unix_pid;
1932 unix_tid = reply->unix_tid;
1935 SERVER_END_REQ;
1936 if (status == STATUS_SUCCESS)
1938 BOOL ret = FALSE;
1940 kusrt.KernelTime.QuadPart = kusrt.UserTime.QuadPart = 0;
1941 if (unix_pid != -1 && unix_tid != -1)
1942 ret = get_thread_times( unix_pid, unix_tid, &kusrt.KernelTime, &kusrt.UserTime );
1943 if (!ret && handle == GetCurrentThread())
1945 /* fall back to process times */
1946 struct tms time_buf;
1947 long clocks_per_sec = sysconf(_SC_CLK_TCK);
1949 times(&time_buf);
1950 kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
1951 kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
1953 if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
1954 if (ret_len) *ret_len = min( length, sizeof(kusrt) );
1956 return status;
1959 case ThreadDescriptorTableEntry:
1960 return get_thread_ldt_entry( handle, data, length, ret_len );
1962 case ThreadAmILastThread:
1964 if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
1965 SERVER_START_REQ( get_thread_info )
1967 req->handle = wine_server_obj_handle( handle );
1968 status = wine_server_call( req );
1969 if (status == STATUS_SUCCESS)
1971 ULONG last = reply->last;
1972 if (data) memcpy( data, &last, sizeof(last) );
1973 if (ret_len) *ret_len = sizeof(last);
1976 SERVER_END_REQ;
1977 return status;
1980 case ThreadQuerySetWin32StartAddress:
1982 SERVER_START_REQ( get_thread_info )
1984 req->handle = wine_server_obj_handle( handle );
1985 req->access = THREAD_QUERY_INFORMATION;
1986 status = wine_server_call( req );
1987 if (status == STATUS_SUCCESS)
1989 PRTL_THREAD_START_ROUTINE entry = wine_server_get_ptr( reply->entry_point );
1990 if (data) memcpy( data, &entry, min( length, sizeof(entry) ) );
1991 if (ret_len) *ret_len = min( length, sizeof(entry) );
1994 SERVER_END_REQ;
1995 return status;
1998 case ThreadGroupInformation:
2000 const ULONG_PTR affinity_mask = get_system_affinity_mask();
2001 GROUP_AFFINITY affinity;
2003 memset( &affinity, 0, sizeof(affinity) );
2004 affinity.Group = 0; /* Wine only supports max 64 processors */
2006 SERVER_START_REQ( get_thread_info )
2008 req->handle = wine_server_obj_handle( handle );
2009 if (!(status = wine_server_call( req ))) affinity.Mask = reply->affinity & affinity_mask;
2011 SERVER_END_REQ;
2012 if (status == STATUS_SUCCESS)
2014 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
2015 if (ret_len) *ret_len = min( length, sizeof(affinity) );
2017 return status;
2020 case ThreadIsIoPending:
2021 FIXME( "ThreadIsIoPending info class not supported yet\n" );
2022 if (length != sizeof(BOOL)) return STATUS_INFO_LENGTH_MISMATCH;
2023 if (!data) return STATUS_ACCESS_DENIED;
2024 *(BOOL*)data = FALSE;
2025 if (ret_len) *ret_len = sizeof(BOOL);
2026 return STATUS_SUCCESS;
2028 case ThreadSuspendCount:
2029 if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2030 if (!data) return STATUS_ACCESS_VIOLATION;
2032 SERVER_START_REQ( get_thread_info )
2034 req->handle = wine_server_obj_handle( handle );
2035 if (!(status = wine_server_call( req ))) *(ULONG *)data = reply->suspend_count;
2037 SERVER_END_REQ;
2038 return status;
2040 case ThreadNameInformation:
2042 THREAD_NAME_INFORMATION *info = data;
2043 data_size_t len, desc_len = 0;
2044 WCHAR *ptr;
2046 len = length >= sizeof(*info) ? length - sizeof(*info) : 0;
2047 ptr = info ? (WCHAR *)(info + 1) : NULL;
2049 SERVER_START_REQ( get_thread_info )
2051 req->handle = wine_server_obj_handle( handle );
2052 if (ptr) wine_server_set_reply( req, ptr, len );
2053 status = wine_server_call( req );
2054 desc_len = reply->desc_len;
2056 SERVER_END_REQ;
2058 if (!info) status = STATUS_BUFFER_TOO_SMALL;
2059 else if (status == STATUS_SUCCESS)
2061 info->ThreadName.Length = info->ThreadName.MaximumLength = desc_len;
2062 info->ThreadName.Buffer = ptr;
2065 if (ret_len && (status == STATUS_SUCCESS || status == STATUS_BUFFER_TOO_SMALL))
2066 *ret_len = sizeof(*info) + desc_len;
2067 return status;
2070 case ThreadWow64Context:
2071 return get_thread_wow64_context( handle, data, length );
2073 case ThreadHideFromDebugger:
2074 if (length != sizeof(BOOLEAN)) return STATUS_INFO_LENGTH_MISMATCH;
2075 if (!data) return STATUS_ACCESS_VIOLATION;
2076 SERVER_START_REQ( get_thread_info )
2078 req->handle = wine_server_obj_handle( handle );
2079 req->access = THREAD_QUERY_INFORMATION;
2080 if ((status = wine_server_call( req ))) return status;
2081 *(BOOLEAN*)data = reply->dbg_hidden;
2083 SERVER_END_REQ;
2084 if (ret_len) *ret_len = sizeof(BOOLEAN);
2085 return STATUS_SUCCESS;
2087 case ThreadEnableAlignmentFaultFixup:
2088 return STATUS_INVALID_INFO_CLASS;
2090 case ThreadPriority:
2091 case ThreadBasePriority:
2092 case ThreadImpersonationToken:
2093 case ThreadEventPair_Reusable:
2094 case ThreadZeroTlsCell:
2095 case ThreadPerformanceCount:
2096 case ThreadIdealProcessor:
2097 case ThreadPriorityBoost:
2098 case ThreadSetTlsArrayAddress:
2099 default:
2100 FIXME( "info class %d not supported yet\n", class );
2101 return STATUS_NOT_IMPLEMENTED;
2106 /******************************************************************************
2107 * NtSetInformationThread (NTDLL.@)
2109 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
2110 const void *data, ULONG length )
2112 NTSTATUS status;
2114 TRACE("(%p,%d,%p,%x)\n", handle, class, data, length);
2116 switch (class)
2118 case ThreadZeroTlsCell:
2119 if (handle == GetCurrentThread())
2121 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
2122 return virtual_clear_tls_index( *(const ULONG *)data );
2124 FIXME( "ZeroTlsCell not supported on other threads\n" );
2125 return STATUS_NOT_IMPLEMENTED;
2127 case ThreadImpersonationToken:
2129 const HANDLE *token = data;
2131 if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
2132 TRACE("Setting ThreadImpersonationToken handle to %p\n", *token );
2133 SERVER_START_REQ( set_thread_info )
2135 req->handle = wine_server_obj_handle( handle );
2136 req->token = wine_server_obj_handle( *token );
2137 req->mask = SET_THREAD_INFO_TOKEN;
2138 status = wine_server_call( req );
2140 SERVER_END_REQ;
2141 return status;
2144 case ThreadBasePriority:
2146 const DWORD *pprio = data;
2147 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
2148 SERVER_START_REQ( set_thread_info )
2150 req->handle = wine_server_obj_handle( handle );
2151 req->priority = *pprio;
2152 req->mask = SET_THREAD_INFO_PRIORITY;
2153 status = wine_server_call( req );
2155 SERVER_END_REQ;
2156 return status;
2159 case ThreadAffinityMask:
2161 const ULONG_PTR affinity_mask = get_system_affinity_mask();
2162 ULONG_PTR req_aff;
2164 if (length != sizeof(ULONG_PTR)) return STATUS_INVALID_PARAMETER;
2165 req_aff = *(const ULONG_PTR *)data & affinity_mask;
2166 if (!req_aff) return STATUS_INVALID_PARAMETER;
2168 SERVER_START_REQ( set_thread_info )
2170 req->handle = wine_server_obj_handle( handle );
2171 req->affinity = req_aff;
2172 req->mask = SET_THREAD_INFO_AFFINITY;
2173 status = wine_server_call( req );
2175 SERVER_END_REQ;
2176 return status;
2179 case ThreadHideFromDebugger:
2180 if (length) return STATUS_INFO_LENGTH_MISMATCH;
2181 SERVER_START_REQ( set_thread_info )
2183 req->handle = wine_server_obj_handle( handle );
2184 req->mask = SET_THREAD_INFO_DBG_HIDDEN;
2185 status = wine_server_call( req );
2187 SERVER_END_REQ;
2188 return status;
2190 case ThreadQuerySetWin32StartAddress:
2192 const PRTL_THREAD_START_ROUTINE *entry = data;
2193 if (length != sizeof(PRTL_THREAD_START_ROUTINE)) return STATUS_INVALID_PARAMETER;
2194 SERVER_START_REQ( set_thread_info )
2196 req->handle = wine_server_obj_handle( handle );
2197 req->mask = SET_THREAD_INFO_ENTRYPOINT;
2198 req->entry_point = wine_server_client_ptr( *entry );
2199 status = wine_server_call( req );
2201 SERVER_END_REQ;
2202 return status;
2205 case ThreadGroupInformation:
2207 const ULONG_PTR affinity_mask = get_system_affinity_mask();
2208 const GROUP_AFFINITY *req_aff;
2210 if (length != sizeof(*req_aff)) return STATUS_INVALID_PARAMETER;
2211 if (!data) return STATUS_ACCESS_VIOLATION;
2212 req_aff = data;
2214 /* On Windows the request fails if the reserved fields are set */
2215 if (req_aff->Reserved[0] || req_aff->Reserved[1] || req_aff->Reserved[2])
2216 return STATUS_INVALID_PARAMETER;
2218 /* Wine only supports max 64 processors */
2219 if (req_aff->Group) return STATUS_INVALID_PARAMETER;
2220 if (req_aff->Mask & ~affinity_mask) return STATUS_INVALID_PARAMETER;
2221 if (!req_aff->Mask) return STATUS_INVALID_PARAMETER;
2222 SERVER_START_REQ( set_thread_info )
2224 req->handle = wine_server_obj_handle( handle );
2225 req->affinity = req_aff->Mask;
2226 req->mask = SET_THREAD_INFO_AFFINITY;
2227 status = wine_server_call( req );
2229 SERVER_END_REQ;
2230 return status;
2233 case ThreadNameInformation:
2235 const THREAD_NAME_INFORMATION *info = data;
2236 THREAD_BASIC_INFORMATION tbi;
2238 if (length != sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
2239 if (!info) return STATUS_ACCESS_VIOLATION;
2240 if (info->ThreadName.Length && !info->ThreadName.Buffer) return STATUS_ACCESS_VIOLATION;
2242 if (handle == GetCurrentThread())
2243 WARN_(threadname)( "Thread renamed to %s\n", debugstr_us(&info->ThreadName) );
2244 else if (!NtQueryInformationThread( handle, ThreadBasicInformation, &tbi, sizeof(tbi), NULL ))
2245 WARN_(threadname)( "Thread ID %04x renamed to %s\n", HandleToULong( tbi.ClientId.UniqueThread ), debugstr_us(&info->ThreadName) );
2246 else
2247 WARN_(threadname)( "Thread handle %p renamed to %s\n", handle, debugstr_us(&info->ThreadName) );
2249 SERVER_START_REQ( set_thread_info )
2251 req->handle = wine_server_obj_handle( handle );
2252 req->mask = SET_THREAD_INFO_DESCRIPTION;
2253 wine_server_add_data( req, info->ThreadName.Buffer, info->ThreadName.Length );
2254 status = wine_server_call( req );
2256 SERVER_END_REQ;
2257 return status;
2260 case ThreadWow64Context:
2261 return set_thread_wow64_context( handle, data, length );
2263 case ThreadEnableAlignmentFaultFixup:
2264 if (length != sizeof(BOOLEAN)) return STATUS_INFO_LENGTH_MISMATCH;
2265 if (!data) return STATUS_ACCESS_VIOLATION;
2266 FIXME( "ThreadEnableAlignmentFaultFixup stub!\n" );
2267 return STATUS_SUCCESS;
2269 case ThreadPowerThrottlingState:
2270 if (length != sizeof(THREAD_POWER_THROTTLING_STATE)) return STATUS_INFO_LENGTH_MISMATCH;
2271 if (!data) return STATUS_ACCESS_VIOLATION;
2272 FIXME( "ThreadPowerThrottling stub!\n" );
2273 return STATUS_SUCCESS;
2275 case ThreadBasicInformation:
2276 case ThreadTimes:
2277 case ThreadPriority:
2278 case ThreadDescriptorTableEntry:
2279 case ThreadEventPair_Reusable:
2280 case ThreadPerformanceCount:
2281 case ThreadAmILastThread:
2282 case ThreadIdealProcessor:
2283 case ThreadPriorityBoost:
2284 case ThreadSetTlsArrayAddress:
2285 case ThreadIsIoPending:
2286 default:
2287 FIXME( "info class %d not supported yet\n", class );
2288 return STATUS_NOT_IMPLEMENTED;
2293 /******************************************************************************
2294 * NtGetCurrentProcessorNumber (NTDLL.@)
2296 ULONG WINAPI NtGetCurrentProcessorNumber(void)
2298 ULONG processor;
2300 #if defined(__linux__) && defined(__NR_getcpu)
2301 int res = syscall(__NR_getcpu, &processor, NULL, NULL);
2302 if (res != -1) return processor;
2303 #endif
2305 if (peb->NumberOfProcessors > 1)
2307 ULONG_PTR thread_mask, processor_mask;
2309 if (!NtQueryInformationThread( GetCurrentThread(), ThreadAffinityMask,
2310 &thread_mask, sizeof(thread_mask), NULL ))
2312 for (processor = 0; processor < peb->NumberOfProcessors; processor++)
2314 processor_mask = (1 << processor);
2315 if (thread_mask & processor_mask)
2317 if (thread_mask != processor_mask)
2318 FIXME( "need multicore support (%d processors)\n",
2319 peb->NumberOfProcessors );
2320 return processor;
2325 /* fallback to the first processor */
2326 return 0;
2330 /******************************************************************************
2331 * NtGetNextThread (NTDLL.@)
2333 NTSTATUS WINAPI NtGetNextThread( HANDLE process, HANDLE thread, ACCESS_MASK access, ULONG attributes,
2334 ULONG flags, HANDLE *handle )
2336 HANDLE ret_handle = 0;
2337 NTSTATUS ret;
2339 TRACE( "process %p, thread %p, access %#x, attributes %#x, flags %#x, handle %p.\n",
2340 process, thread, access, attributes, flags, handle );
2342 SERVER_START_REQ( get_next_thread )
2344 req->process = wine_server_obj_handle( process );
2345 req->last = wine_server_obj_handle( thread );
2346 req->access = access;
2347 req->attributes = attributes;
2348 req->flags = flags;
2349 if (!(ret = wine_server_call( req ))) ret_handle = wine_server_ptr_handle( reply->handle );
2351 SERVER_END_REQ;
2353 *handle = ret_handle;
2354 return ret;