maintainers: Update the Direct3D section.
[wine.git] / dlls / ntdll / unix / thread.c
blob503230e46348340c497bd681191436c262513014
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);
74 static int nb_threads = 1;
76 static inline int get_unix_exit_code( NTSTATUS status )
78 /* prevent a nonzero exit code to end up truncated to zero in unix */
79 if (status && !(status & 0xff)) return 1;
80 return status;
84 /***********************************************************************
85 * fpux_to_fpu
87 * Build a standard i386 FPU context from an extended one.
89 void fpux_to_fpu( I386_FLOATING_SAVE_AREA *fpu, const XMM_SAVE_AREA32 *fpux )
91 unsigned int i, tag, stack_top;
93 fpu->ControlWord = fpux->ControlWord;
94 fpu->StatusWord = fpux->StatusWord;
95 fpu->ErrorOffset = fpux->ErrorOffset;
96 fpu->ErrorSelector = fpux->ErrorSelector | (fpux->ErrorOpcode << 16);
97 fpu->DataOffset = fpux->DataOffset;
98 fpu->DataSelector = fpux->DataSelector;
99 fpu->Cr0NpxState = fpux->StatusWord | 0xffff0000;
101 stack_top = (fpux->StatusWord >> 11) & 7;
102 fpu->TagWord = 0xffff0000;
103 for (i = 0; i < 8; i++)
105 memcpy( &fpu->RegisterArea[10 * i], &fpux->FloatRegisters[i], 10 );
106 if (!(fpux->TagWord & (1 << i))) tag = 3; /* empty */
107 else
109 const M128A *reg = &fpux->FloatRegisters[(i - stack_top) & 7];
110 if ((reg->High & 0x7fff) == 0x7fff) /* exponent all ones */
112 tag = 2; /* special */
114 else if (!(reg->High & 0x7fff)) /* exponent all zeroes */
116 if (reg->Low) tag = 2; /* special */
117 else tag = 1; /* zero */
119 else
121 if (reg->Low >> 63) tag = 0; /* valid */
122 else tag = 2; /* special */
125 fpu->TagWord |= tag << (2 * i);
130 /***********************************************************************
131 * fpu_to_fpux
133 * Fill extended i386 FPU context from standard one.
135 void fpu_to_fpux( XMM_SAVE_AREA32 *fpux, const I386_FLOATING_SAVE_AREA *fpu )
137 unsigned int i;
139 fpux->ControlWord = fpu->ControlWord;
140 fpux->StatusWord = fpu->StatusWord;
141 fpux->ErrorOffset = fpu->ErrorOffset;
142 fpux->ErrorSelector = fpu->ErrorSelector;
143 fpux->ErrorOpcode = fpu->ErrorSelector >> 16;
144 fpux->DataOffset = fpu->DataOffset;
145 fpux->DataSelector = fpu->DataSelector;
146 fpux->TagWord = 0;
147 for (i = 0; i < 8; i++)
149 if (((fpu->TagWord >> (i * 2)) & 3) != 3) fpux->TagWord |= 1 << i;
150 memcpy( &fpux->FloatRegisters[i], &fpu->RegisterArea[10 * i], 10 );
155 /***********************************************************************
156 * get_server_context_flags
158 static unsigned int get_server_context_flags( const void *context, USHORT machine )
160 unsigned int flags, ret = 0;
162 switch (machine)
164 case IMAGE_FILE_MACHINE_I386:
165 flags = ((const I386_CONTEXT *)context)->ContextFlags & ~CONTEXT_i386;
166 if (flags & CONTEXT_I386_CONTROL) ret |= SERVER_CTX_CONTROL;
167 if (flags & CONTEXT_I386_INTEGER) ret |= SERVER_CTX_INTEGER;
168 if (flags & CONTEXT_I386_SEGMENTS) ret |= SERVER_CTX_SEGMENTS;
169 if (flags & CONTEXT_I386_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
170 if (flags & CONTEXT_I386_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
171 if (flags & CONTEXT_I386_EXTENDED_REGISTERS) ret |= SERVER_CTX_EXTENDED_REGISTERS | SERVER_CTX_FLOATING_POINT;
172 if (flags & CONTEXT_I386_XSTATE) ret |= SERVER_CTX_YMM_REGISTERS;
173 break;
174 case IMAGE_FILE_MACHINE_AMD64:
175 flags = ((const AMD64_CONTEXT *)context)->ContextFlags & ~CONTEXT_AMD64;
176 if (flags & CONTEXT_AMD64_CONTROL) ret |= SERVER_CTX_CONTROL;
177 if (flags & CONTEXT_AMD64_INTEGER) ret |= SERVER_CTX_INTEGER;
178 if (flags & CONTEXT_AMD64_SEGMENTS) ret |= SERVER_CTX_SEGMENTS;
179 if (flags & CONTEXT_AMD64_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
180 if (flags & CONTEXT_AMD64_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
181 if (flags & CONTEXT_AMD64_XSTATE) ret |= SERVER_CTX_YMM_REGISTERS;
182 break;
183 case IMAGE_FILE_MACHINE_ARMNT:
184 flags = ((const ARM_CONTEXT *)context)->ContextFlags & ~CONTEXT_ARM;
185 if (flags & CONTEXT_ARM_CONTROL) ret |= SERVER_CTX_CONTROL;
186 if (flags & CONTEXT_ARM_INTEGER) ret |= SERVER_CTX_INTEGER;
187 if (flags & CONTEXT_ARM_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
188 if (flags & CONTEXT_ARM_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
189 break;
190 case IMAGE_FILE_MACHINE_ARM64:
191 flags = ((const ARM64_NT_CONTEXT *)context)->ContextFlags & ~CONTEXT_ARM64;
192 if (flags & CONTEXT_ARM64_CONTROL) ret |= SERVER_CTX_CONTROL;
193 if (flags & CONTEXT_ARM64_INTEGER) ret |= SERVER_CTX_INTEGER;
194 if (flags & CONTEXT_ARM64_FLOATING_POINT) ret |= SERVER_CTX_FLOATING_POINT;
195 if (flags & CONTEXT_ARM64_DEBUG_REGISTERS) ret |= SERVER_CTX_DEBUG_REGISTERS;
196 break;
198 return ret;
202 /***********************************************************************
203 * context_to_server
205 * Convert a register context to the server format.
207 static NTSTATUS context_to_server( context_t *to, USHORT to_machine, const void *src, USHORT from_machine )
209 DWORD i, flags;
211 memset( to, 0, sizeof(*to) );
212 to->machine = to_machine;
214 switch (MAKELONG( from_machine, to_machine ))
216 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_I386 ):
218 const I386_CONTEXT *from = src;
220 flags = from->ContextFlags & ~CONTEXT_i386;
221 if (flags & CONTEXT_I386_CONTROL)
223 to->flags |= SERVER_CTX_CONTROL;
224 to->ctl.i386_regs.ebp = from->Ebp;
225 to->ctl.i386_regs.esp = from->Esp;
226 to->ctl.i386_regs.eip = from->Eip;
227 to->ctl.i386_regs.cs = from->SegCs;
228 to->ctl.i386_regs.ss = from->SegSs;
229 to->ctl.i386_regs.eflags = from->EFlags;
231 if (flags & CONTEXT_I386_INTEGER)
233 to->flags |= SERVER_CTX_INTEGER;
234 to->integer.i386_regs.eax = from->Eax;
235 to->integer.i386_regs.ebx = from->Ebx;
236 to->integer.i386_regs.ecx = from->Ecx;
237 to->integer.i386_regs.edx = from->Edx;
238 to->integer.i386_regs.esi = from->Esi;
239 to->integer.i386_regs.edi = from->Edi;
241 if (flags & CONTEXT_I386_SEGMENTS)
243 to->flags |= SERVER_CTX_SEGMENTS;
244 to->seg.i386_regs.ds = from->SegDs;
245 to->seg.i386_regs.es = from->SegEs;
246 to->seg.i386_regs.fs = from->SegFs;
247 to->seg.i386_regs.gs = from->SegGs;
249 if (flags & CONTEXT_I386_FLOATING_POINT)
251 to->flags |= SERVER_CTX_FLOATING_POINT;
252 to->fp.i386_regs.ctrl = from->FloatSave.ControlWord;
253 to->fp.i386_regs.status = from->FloatSave.StatusWord;
254 to->fp.i386_regs.tag = from->FloatSave.TagWord;
255 to->fp.i386_regs.err_off = from->FloatSave.ErrorOffset;
256 to->fp.i386_regs.err_sel = from->FloatSave.ErrorSelector;
257 to->fp.i386_regs.data_off = from->FloatSave.DataOffset;
258 to->fp.i386_regs.data_sel = from->FloatSave.DataSelector;
259 to->fp.i386_regs.cr0npx = from->FloatSave.Cr0NpxState;
260 memcpy( to->fp.i386_regs.regs, from->FloatSave.RegisterArea, sizeof(to->fp.i386_regs.regs) );
262 if (flags & CONTEXT_I386_DEBUG_REGISTERS)
264 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
265 to->debug.i386_regs.dr0 = from->Dr0;
266 to->debug.i386_regs.dr1 = from->Dr1;
267 to->debug.i386_regs.dr2 = from->Dr2;
268 to->debug.i386_regs.dr3 = from->Dr3;
269 to->debug.i386_regs.dr6 = from->Dr6;
270 to->debug.i386_regs.dr7 = from->Dr7;
272 if (flags & CONTEXT_I386_EXTENDED_REGISTERS)
274 to->flags |= SERVER_CTX_EXTENDED_REGISTERS;
275 memcpy( to->ext.i386_regs, from->ExtendedRegisters, sizeof(to->ext.i386_regs) );
277 if (flags & CONTEXT_I386_XSTATE)
279 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
280 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
282 to->flags |= SERVER_CTX_YMM_REGISTERS;
283 if (xs->Mask & 4) memcpy( &to->ymm.regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
285 return STATUS_SUCCESS;
288 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_AMD64 ):
290 const I386_CONTEXT *from = src;
292 flags = from->ContextFlags & ~CONTEXT_i386;
293 if (flags & CONTEXT_I386_CONTROL)
295 to->flags |= SERVER_CTX_CONTROL;
296 to->ctl.x86_64_regs.rbp = from->Ebp;
297 to->ctl.x86_64_regs.rsp = from->Esp;
298 to->ctl.x86_64_regs.rip = from->Eip;
299 to->ctl.x86_64_regs.cs = from->SegCs;
300 to->ctl.x86_64_regs.ss = from->SegSs;
301 to->ctl.x86_64_regs.flags = from->EFlags;
303 if (flags & CONTEXT_I386_INTEGER)
305 to->flags |= SERVER_CTX_INTEGER;
306 to->integer.x86_64_regs.rax = from->Eax;
307 to->integer.x86_64_regs.rbx = from->Ebx;
308 to->integer.x86_64_regs.rcx = from->Ecx;
309 to->integer.x86_64_regs.rdx = from->Edx;
310 to->integer.x86_64_regs.rsi = from->Esi;
311 to->integer.x86_64_regs.rdi = from->Edi;
313 if (flags & CONTEXT_I386_SEGMENTS)
315 to->flags |= SERVER_CTX_SEGMENTS;
316 to->seg.x86_64_regs.ds = from->SegDs;
317 to->seg.x86_64_regs.es = from->SegEs;
318 to->seg.x86_64_regs.fs = from->SegFs;
319 to->seg.x86_64_regs.gs = from->SegGs;
321 if (flags & CONTEXT_I386_DEBUG_REGISTERS)
323 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
324 to->debug.x86_64_regs.dr0 = from->Dr0;
325 to->debug.x86_64_regs.dr1 = from->Dr1;
326 to->debug.x86_64_regs.dr2 = from->Dr2;
327 to->debug.x86_64_regs.dr3 = from->Dr3;
328 to->debug.x86_64_regs.dr6 = from->Dr6;
329 to->debug.x86_64_regs.dr7 = from->Dr7;
331 if (flags & CONTEXT_I386_EXTENDED_REGISTERS)
333 to->flags |= SERVER_CTX_FLOATING_POINT;
334 memcpy( to->fp.x86_64_regs.fpregs, from->ExtendedRegisters, sizeof(to->fp.x86_64_regs.fpregs) );
336 else if (flags & CONTEXT_I386_FLOATING_POINT)
338 to->flags |= SERVER_CTX_FLOATING_POINT;
339 fpu_to_fpux( (XMM_SAVE_AREA32 *)to->fp.x86_64_regs.fpregs, &from->FloatSave );
341 if (flags & CONTEXT_I386_XSTATE)
343 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
344 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
346 to->flags |= SERVER_CTX_YMM_REGISTERS;
347 if (xs->Mask & 4) memcpy( &to->ymm.regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
349 return STATUS_SUCCESS;
352 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_AMD64 ):
354 const AMD64_CONTEXT *from = src;
356 flags = from->ContextFlags & ~CONTEXT_AMD64;
357 if (flags & CONTEXT_AMD64_CONTROL)
359 to->flags |= SERVER_CTX_CONTROL;
360 to->ctl.x86_64_regs.rbp = from->Rbp;
361 to->ctl.x86_64_regs.rip = from->Rip;
362 to->ctl.x86_64_regs.rsp = from->Rsp;
363 to->ctl.x86_64_regs.cs = from->SegCs;
364 to->ctl.x86_64_regs.ss = from->SegSs;
365 to->ctl.x86_64_regs.flags = from->EFlags;
367 if (flags & CONTEXT_AMD64_INTEGER)
369 to->flags |= SERVER_CTX_INTEGER;
370 to->integer.x86_64_regs.rax = from->Rax;
371 to->integer.x86_64_regs.rcx = from->Rcx;
372 to->integer.x86_64_regs.rdx = from->Rdx;
373 to->integer.x86_64_regs.rbx = from->Rbx;
374 to->integer.x86_64_regs.rsi = from->Rsi;
375 to->integer.x86_64_regs.rdi = from->Rdi;
376 to->integer.x86_64_regs.r8 = from->R8;
377 to->integer.x86_64_regs.r9 = from->R9;
378 to->integer.x86_64_regs.r10 = from->R10;
379 to->integer.x86_64_regs.r11 = from->R11;
380 to->integer.x86_64_regs.r12 = from->R12;
381 to->integer.x86_64_regs.r13 = from->R13;
382 to->integer.x86_64_regs.r14 = from->R14;
383 to->integer.x86_64_regs.r15 = from->R15;
385 if (flags & CONTEXT_AMD64_SEGMENTS)
387 to->flags |= SERVER_CTX_SEGMENTS;
388 to->seg.x86_64_regs.ds = from->SegDs;
389 to->seg.x86_64_regs.es = from->SegEs;
390 to->seg.x86_64_regs.fs = from->SegFs;
391 to->seg.x86_64_regs.gs = from->SegGs;
393 if (flags & CONTEXT_AMD64_FLOATING_POINT)
395 to->flags |= SERVER_CTX_FLOATING_POINT;
396 memcpy( to->fp.x86_64_regs.fpregs, &from->u.FltSave, sizeof(to->fp.x86_64_regs.fpregs) );
398 if (flags & CONTEXT_AMD64_DEBUG_REGISTERS)
400 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
401 to->debug.x86_64_regs.dr0 = from->Dr0;
402 to->debug.x86_64_regs.dr1 = from->Dr1;
403 to->debug.x86_64_regs.dr2 = from->Dr2;
404 to->debug.x86_64_regs.dr3 = from->Dr3;
405 to->debug.x86_64_regs.dr6 = from->Dr6;
406 to->debug.x86_64_regs.dr7 = from->Dr7;
408 if (flags & CONTEXT_AMD64_XSTATE)
410 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
411 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
413 to->flags |= SERVER_CTX_YMM_REGISTERS;
414 if (xs->Mask & 4) memcpy( &to->ymm.regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
416 return STATUS_SUCCESS;
419 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386 ):
421 const AMD64_CONTEXT *from = src;
423 flags = from->ContextFlags & ~CONTEXT_AMD64;
424 if (flags & CONTEXT_AMD64_CONTROL)
426 to->flags |= SERVER_CTX_CONTROL;
427 to->ctl.i386_regs.ebp = from->Rbp;
428 to->ctl.i386_regs.eip = from->Rip;
429 to->ctl.i386_regs.esp = from->Rsp;
430 to->ctl.i386_regs.cs = from->SegCs;
431 to->ctl.i386_regs.ss = from->SegSs;
432 to->ctl.i386_regs.eflags = from->EFlags;
434 if (flags & CONTEXT_AMD64_INTEGER)
436 to->flags |= SERVER_CTX_INTEGER;
437 to->integer.i386_regs.eax = from->Rax;
438 to->integer.i386_regs.ecx = from->Rcx;
439 to->integer.i386_regs.edx = from->Rdx;
440 to->integer.i386_regs.ebx = from->Rbx;
441 to->integer.i386_regs.esi = from->Rsi;
442 to->integer.i386_regs.edi = from->Rdi;
444 if (flags & CONTEXT_AMD64_SEGMENTS)
446 to->flags |= SERVER_CTX_SEGMENTS;
447 to->seg.i386_regs.ds = from->SegDs;
448 to->seg.i386_regs.es = from->SegEs;
449 to->seg.i386_regs.fs = from->SegFs;
450 to->seg.i386_regs.gs = from->SegGs;
452 if (flags & CONTEXT_AMD64_FLOATING_POINT)
454 I386_FLOATING_SAVE_AREA fpu;
456 to->flags |= SERVER_CTX_EXTENDED_REGISTERS | SERVER_CTX_FLOATING_POINT;
457 memcpy( to->ext.i386_regs, &from->u.FltSave, sizeof(to->ext.i386_regs) );
458 fpux_to_fpu( &fpu, &from->u.FltSave );
459 to->fp.i386_regs.ctrl = fpu.ControlWord;
460 to->fp.i386_regs.status = fpu.StatusWord;
461 to->fp.i386_regs.tag = fpu.TagWord;
462 to->fp.i386_regs.err_off = fpu.ErrorOffset;
463 to->fp.i386_regs.err_sel = fpu.ErrorSelector;
464 to->fp.i386_regs.data_off = fpu.DataOffset;
465 to->fp.i386_regs.data_sel = fpu.DataSelector;
466 to->fp.i386_regs.cr0npx = fpu.Cr0NpxState;
467 memcpy( to->fp.i386_regs.regs, fpu.RegisterArea, sizeof(to->fp.i386_regs.regs) );
469 if (flags & CONTEXT_AMD64_DEBUG_REGISTERS)
471 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
472 to->debug.i386_regs.dr0 = from->Dr0;
473 to->debug.i386_regs.dr1 = from->Dr1;
474 to->debug.i386_regs.dr2 = from->Dr2;
475 to->debug.i386_regs.dr3 = from->Dr3;
476 to->debug.i386_regs.dr6 = from->Dr6;
477 to->debug.i386_regs.dr7 = from->Dr7;
479 if (flags & CONTEXT_AMD64_XSTATE)
481 const CONTEXT_EX *xctx = (const CONTEXT_EX *)(from + 1);
482 const XSTATE *xs = (const XSTATE *)((const char *)xctx + xctx->XState.Offset);
484 to->flags |= SERVER_CTX_YMM_REGISTERS;
485 if (xs->Mask & 4) memcpy( &to->ymm.regs.ymm_high, &xs->YmmContext, sizeof(xs->YmmContext) );
487 return STATUS_SUCCESS;
490 case MAKELONG( IMAGE_FILE_MACHINE_ARMNT, IMAGE_FILE_MACHINE_ARMNT ):
492 const ARM_CONTEXT *from = src;
494 flags = from->ContextFlags & ~CONTEXT_ARM;
495 if (flags & CONTEXT_ARM_CONTROL)
497 to->flags |= SERVER_CTX_CONTROL;
498 to->ctl.arm_regs.sp = from->Sp;
499 to->ctl.arm_regs.lr = from->Lr;
500 to->ctl.arm_regs.pc = from->Pc;
501 to->ctl.arm_regs.cpsr = from->Cpsr;
503 if (flags & CONTEXT_ARM_INTEGER)
505 to->flags |= SERVER_CTX_INTEGER;
506 to->integer.arm_regs.r[0] = from->R0;
507 to->integer.arm_regs.r[1] = from->R1;
508 to->integer.arm_regs.r[2] = from->R2;
509 to->integer.arm_regs.r[3] = from->R3;
510 to->integer.arm_regs.r[4] = from->R4;
511 to->integer.arm_regs.r[5] = from->R5;
512 to->integer.arm_regs.r[6] = from->R6;
513 to->integer.arm_regs.r[7] = from->R7;
514 to->integer.arm_regs.r[8] = from->R8;
515 to->integer.arm_regs.r[9] = from->R9;
516 to->integer.arm_regs.r[10] = from->R10;
517 to->integer.arm_regs.r[11] = from->R11;
518 to->integer.arm_regs.r[12] = from->R12;
520 if (flags & CONTEXT_ARM_FLOATING_POINT)
522 to->flags |= SERVER_CTX_FLOATING_POINT;
523 for (i = 0; i < 32; i++) to->fp.arm_regs.d[i] = from->u.D[i];
524 to->fp.arm_regs.fpscr = from->Fpscr;
526 if (flags & CONTEXT_ARM_DEBUG_REGISTERS)
528 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
529 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bvr[i] = from->Bvr[i];
530 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->debug.arm_regs.bcr[i] = from->Bcr[i];
531 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wvr[i] = from->Wvr[i];
532 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->debug.arm_regs.wcr[i] = from->Wcr[i];
534 return STATUS_SUCCESS;
537 case MAKELONG( IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_ARM64 ):
539 const ARM64_NT_CONTEXT *from = src;
541 flags = from->ContextFlags & ~CONTEXT_ARM64;
542 if (flags & CONTEXT_ARM64_CONTROL)
544 to->flags |= SERVER_CTX_CONTROL;
545 to->integer.arm64_regs.x[29] = from->u.s.Fp;
546 to->integer.arm64_regs.x[30] = from->u.s.Lr;
547 to->ctl.arm64_regs.sp = from->Sp;
548 to->ctl.arm64_regs.pc = from->Pc;
549 to->ctl.arm64_regs.pstate = from->Cpsr;
551 if (flags & CONTEXT_ARM64_INTEGER)
553 to->flags |= SERVER_CTX_INTEGER;
554 for (i = 0; i <= 28; i++) to->integer.arm64_regs.x[i] = from->u.X[i];
556 if (flags & CONTEXT_ARM64_FLOATING_POINT)
558 to->flags |= SERVER_CTX_FLOATING_POINT;
559 for (i = 0; i < 32; i++)
561 to->fp.arm64_regs.q[i].low = from->V[i].s.Low;
562 to->fp.arm64_regs.q[i].high = from->V[i].s.High;
564 to->fp.arm64_regs.fpcr = from->Fpcr;
565 to->fp.arm64_regs.fpsr = from->Fpsr;
567 if (flags & CONTEXT_ARM64_DEBUG_REGISTERS)
569 to->flags |= SERVER_CTX_DEBUG_REGISTERS;
570 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bcr[i] = from->Bcr[i];
571 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->debug.arm64_regs.bvr[i] = from->Bvr[i];
572 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wcr[i] = from->Wcr[i];
573 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->debug.arm64_regs.wvr[i] = from->Wvr[i];
575 return STATUS_SUCCESS;
578 default:
579 return STATUS_INVALID_PARAMETER;
584 /***********************************************************************
585 * context_from_server
587 * Convert a register context from the server format.
589 static NTSTATUS context_from_server( void *dst, const context_t *from, USHORT machine )
591 DWORD i, to_flags;
593 switch (MAKELONG( from->machine, machine ))
595 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_I386 ):
597 I386_CONTEXT *to = dst;
599 to_flags = to->ContextFlags & ~CONTEXT_i386;
600 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_I386_CONTROL))
602 to->ContextFlags |= CONTEXT_I386_CONTROL;
603 to->Ebp = from->ctl.i386_regs.ebp;
604 to->Esp = from->ctl.i386_regs.esp;
605 to->Eip = from->ctl.i386_regs.eip;
606 to->SegCs = from->ctl.i386_regs.cs;
607 to->SegSs = from->ctl.i386_regs.ss;
608 to->EFlags = from->ctl.i386_regs.eflags;
610 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_I386_INTEGER))
612 to->ContextFlags |= CONTEXT_I386_INTEGER;
613 to->Eax = from->integer.i386_regs.eax;
614 to->Ebx = from->integer.i386_regs.ebx;
615 to->Ecx = from->integer.i386_regs.ecx;
616 to->Edx = from->integer.i386_regs.edx;
617 to->Esi = from->integer.i386_regs.esi;
618 to->Edi = from->integer.i386_regs.edi;
620 if ((from->flags & SERVER_CTX_SEGMENTS) && (to_flags & CONTEXT_I386_SEGMENTS))
622 to->ContextFlags |= CONTEXT_I386_SEGMENTS;
623 to->SegDs = from->seg.i386_regs.ds;
624 to->SegEs = from->seg.i386_regs.es;
625 to->SegFs = from->seg.i386_regs.fs;
626 to->SegGs = from->seg.i386_regs.gs;
628 if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_I386_FLOATING_POINT))
630 to->ContextFlags |= CONTEXT_I386_FLOATING_POINT;
631 to->FloatSave.ControlWord = from->fp.i386_regs.ctrl;
632 to->FloatSave.StatusWord = from->fp.i386_regs.status;
633 to->FloatSave.TagWord = from->fp.i386_regs.tag;
634 to->FloatSave.ErrorOffset = from->fp.i386_regs.err_off;
635 to->FloatSave.ErrorSelector = from->fp.i386_regs.err_sel;
636 to->FloatSave.DataOffset = from->fp.i386_regs.data_off;
637 to->FloatSave.DataSelector = from->fp.i386_regs.data_sel;
638 to->FloatSave.Cr0NpxState = from->fp.i386_regs.cr0npx;
639 memcpy( to->FloatSave.RegisterArea, from->fp.i386_regs.regs, sizeof(to->FloatSave.RegisterArea) );
641 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_I386_DEBUG_REGISTERS))
643 to->ContextFlags |= CONTEXT_I386_DEBUG_REGISTERS;
644 to->Dr0 = from->debug.i386_regs.dr0;
645 to->Dr1 = from->debug.i386_regs.dr1;
646 to->Dr2 = from->debug.i386_regs.dr2;
647 to->Dr3 = from->debug.i386_regs.dr3;
648 to->Dr6 = from->debug.i386_regs.dr6;
649 to->Dr7 = from->debug.i386_regs.dr7;
651 if ((from->flags & SERVER_CTX_EXTENDED_REGISTERS) && (to_flags & CONTEXT_I386_EXTENDED_REGISTERS))
653 to->ContextFlags |= CONTEXT_I386_EXTENDED_REGISTERS;
654 memcpy( to->ExtendedRegisters, from->ext.i386_regs, sizeof(to->ExtendedRegisters) );
656 if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_I386_XSTATE))
658 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
659 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
661 xs->Mask &= ~4;
662 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
663 for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++)
665 if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue;
666 memcpy( &xs->YmmContext, &from->ymm.regs, sizeof(xs->YmmContext) );
667 xs->Mask |= 4;
668 break;
671 return STATUS_SUCCESS;
674 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386 ):
676 I386_CONTEXT *to = dst;
678 to_flags = to->ContextFlags & ~CONTEXT_i386;
679 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_I386_CONTROL))
681 to->ContextFlags |= CONTEXT_I386_CONTROL;
682 to->Ebp = from->ctl.x86_64_regs.rbp;
683 to->Esp = from->ctl.x86_64_regs.rsp;
684 to->Eip = from->ctl.x86_64_regs.rip;
685 to->SegCs = from->ctl.x86_64_regs.cs;
686 to->SegSs = from->ctl.x86_64_regs.ss;
687 to->EFlags = from->ctl.x86_64_regs.flags;
689 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_I386_INTEGER))
691 to->ContextFlags |= CONTEXT_I386_INTEGER;
692 to->Eax = from->integer.x86_64_regs.rax;
693 to->Ebx = from->integer.x86_64_regs.rbx;
694 to->Ecx = from->integer.x86_64_regs.rcx;
695 to->Edx = from->integer.x86_64_regs.rdx;
696 to->Esi = from->integer.x86_64_regs.rsi;
697 to->Edi = from->integer.x86_64_regs.rdi;
699 if ((from->flags & SERVER_CTX_SEGMENTS) && (to_flags & CONTEXT_I386_SEGMENTS))
701 to->ContextFlags |= CONTEXT_I386_SEGMENTS;
702 to->SegDs = from->seg.x86_64_regs.ds;
703 to->SegEs = from->seg.x86_64_regs.es;
704 to->SegFs = from->seg.x86_64_regs.fs;
705 to->SegGs = from->seg.x86_64_regs.gs;
707 if (from->flags & SERVER_CTX_FLOATING_POINT)
709 if (to_flags & CONTEXT_I386_EXTENDED_REGISTERS)
711 to->ContextFlags |= CONTEXT_I386_EXTENDED_REGISTERS;
712 memcpy( to->ExtendedRegisters, from->fp.x86_64_regs.fpregs, sizeof(to->ExtendedRegisters) );
714 if (to_flags & CONTEXT_I386_FLOATING_POINT)
716 to->ContextFlags |= CONTEXT_I386_FLOATING_POINT;
717 fpux_to_fpu( &to->FloatSave, (XMM_SAVE_AREA32 *)from->fp.x86_64_regs.fpregs );
720 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_I386_DEBUG_REGISTERS))
722 to->ContextFlags |= CONTEXT_I386_DEBUG_REGISTERS;
723 to->Dr0 = from->debug.x86_64_regs.dr0;
724 to->Dr1 = from->debug.x86_64_regs.dr1;
725 to->Dr2 = from->debug.x86_64_regs.dr2;
726 to->Dr3 = from->debug.x86_64_regs.dr3;
727 to->Dr6 = from->debug.x86_64_regs.dr6;
728 to->Dr7 = from->debug.x86_64_regs.dr7;
730 if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_I386_XSTATE))
732 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
733 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
735 xs->Mask &= ~4;
736 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
737 for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++)
739 if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue;
740 memcpy( &xs->YmmContext, &from->ymm.regs, sizeof(xs->YmmContext) );
741 xs->Mask |= 4;
742 break;
745 return STATUS_SUCCESS;
748 case MAKELONG( IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_AMD64 ):
750 AMD64_CONTEXT *to = dst;
752 to_flags = to->ContextFlags & ~CONTEXT_AMD64;
753 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_AMD64_CONTROL))
755 to->ContextFlags |= CONTEXT_AMD64_CONTROL;
756 to->Rbp = from->ctl.x86_64_regs.rbp;
757 to->Rip = from->ctl.x86_64_regs.rip;
758 to->Rsp = from->ctl.x86_64_regs.rsp;
759 to->SegCs = from->ctl.x86_64_regs.cs;
760 to->SegSs = from->ctl.x86_64_regs.ss;
761 to->EFlags = from->ctl.x86_64_regs.flags;
763 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_AMD64_INTEGER))
765 to->ContextFlags |= CONTEXT_AMD64_INTEGER;
766 to->Rax = from->integer.x86_64_regs.rax;
767 to->Rcx = from->integer.x86_64_regs.rcx;
768 to->Rdx = from->integer.x86_64_regs.rdx;
769 to->Rbx = from->integer.x86_64_regs.rbx;
770 to->Rsi = from->integer.x86_64_regs.rsi;
771 to->Rdi = from->integer.x86_64_regs.rdi;
772 to->R8 = from->integer.x86_64_regs.r8;
773 to->R9 = from->integer.x86_64_regs.r9;
774 to->R10 = from->integer.x86_64_regs.r10;
775 to->R11 = from->integer.x86_64_regs.r11;
776 to->R12 = from->integer.x86_64_regs.r12;
777 to->R13 = from->integer.x86_64_regs.r13;
778 to->R14 = from->integer.x86_64_regs.r14;
779 to->R15 = from->integer.x86_64_regs.r15;
781 if ((from->flags & SERVER_CTX_SEGMENTS) && (to_flags & CONTEXT_AMD64_SEGMENTS))
783 to->ContextFlags |= CONTEXT_AMD64_SEGMENTS;
784 to->SegDs = from->seg.x86_64_regs.ds;
785 to->SegEs = from->seg.x86_64_regs.es;
786 to->SegFs = from->seg.x86_64_regs.fs;
787 to->SegGs = from->seg.x86_64_regs.gs;
789 if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_AMD64_FLOATING_POINT))
791 to->ContextFlags |= CONTEXT_AMD64_FLOATING_POINT;
792 memcpy( &to->u.FltSave, from->fp.x86_64_regs.fpregs, sizeof(from->fp.x86_64_regs.fpregs) );
793 to->MxCsr = to->u.FltSave.MxCsr;
795 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_AMD64_DEBUG_REGISTERS))
797 to->ContextFlags |= CONTEXT_AMD64_DEBUG_REGISTERS;
798 to->Dr0 = from->debug.x86_64_regs.dr0;
799 to->Dr1 = from->debug.x86_64_regs.dr1;
800 to->Dr2 = from->debug.x86_64_regs.dr2;
801 to->Dr3 = from->debug.x86_64_regs.dr3;
802 to->Dr6 = from->debug.x86_64_regs.dr6;
803 to->Dr7 = from->debug.x86_64_regs.dr7;
805 if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_AMD64_XSTATE))
807 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
808 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
810 xs->Mask &= ~4;
811 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
812 for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++)
814 if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue;
815 memcpy( &xs->YmmContext, &from->ymm.regs, sizeof(xs->YmmContext) );
816 xs->Mask |= 4;
817 break;
820 return STATUS_SUCCESS;
823 case MAKELONG( IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_AMD64 ):
825 AMD64_CONTEXT *to = dst;
827 to_flags = to->ContextFlags & ~CONTEXT_AMD64;
828 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_AMD64_CONTROL))
830 to->ContextFlags |= CONTEXT_AMD64_CONTROL;
831 to->Rbp = from->ctl.i386_regs.ebp;
832 to->Rip = from->ctl.i386_regs.eip;
833 to->Rsp = from->ctl.i386_regs.esp;
834 to->SegCs = from->ctl.i386_regs.cs;
835 to->SegSs = from->ctl.i386_regs.ss;
836 to->EFlags = from->ctl.i386_regs.eflags;
838 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_AMD64_INTEGER))
840 to->ContextFlags |= CONTEXT_AMD64_INTEGER;
841 to->Rax = from->integer.i386_regs.eax;
842 to->Rcx = from->integer.i386_regs.ecx;
843 to->Rdx = from->integer.i386_regs.edx;
844 to->Rbx = from->integer.i386_regs.ebx;
845 to->Rsi = from->integer.i386_regs.esi;
846 to->Rdi = from->integer.i386_regs.edi;
848 if ((from->flags & SERVER_CTX_SEGMENTS) && (to_flags & CONTEXT_AMD64_SEGMENTS))
850 to->ContextFlags |= CONTEXT_AMD64_SEGMENTS;
851 to->SegDs = from->seg.i386_regs.ds;
852 to->SegEs = from->seg.i386_regs.es;
853 to->SegFs = from->seg.i386_regs.fs;
854 to->SegGs = from->seg.i386_regs.gs;
856 if ((from->flags & SERVER_CTX_EXTENDED_REGISTERS) && (to_flags & CONTEXT_AMD64_FLOATING_POINT))
858 to->ContextFlags |= CONTEXT_AMD64_FLOATING_POINT;
859 memcpy( &to->u.FltSave, from->ext.i386_regs, sizeof(to->u.FltSave) );
861 else if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_AMD64_FLOATING_POINT))
863 I386_FLOATING_SAVE_AREA fpu;
865 to->ContextFlags |= CONTEXT_AMD64_FLOATING_POINT;
866 fpu.ControlWord = from->fp.i386_regs.ctrl;
867 fpu.StatusWord = from->fp.i386_regs.status;
868 fpu.TagWord = from->fp.i386_regs.tag;
869 fpu.ErrorOffset = from->fp.i386_regs.err_off;
870 fpu.ErrorSelector = from->fp.i386_regs.err_sel;
871 fpu.DataOffset = from->fp.i386_regs.data_off;
872 fpu.DataSelector = from->fp.i386_regs.data_sel;
873 fpu.Cr0NpxState = from->fp.i386_regs.cr0npx;
874 memcpy( fpu.RegisterArea, from->fp.i386_regs.regs, sizeof(fpu.RegisterArea) );
875 fpu_to_fpux( &to->u.FltSave, &fpu );
877 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_AMD64_DEBUG_REGISTERS))
879 to->ContextFlags |= CONTEXT_AMD64_DEBUG_REGISTERS;
880 to->Dr0 = from->debug.i386_regs.dr0;
881 to->Dr1 = from->debug.i386_regs.dr1;
882 to->Dr2 = from->debug.i386_regs.dr2;
883 to->Dr3 = from->debug.i386_regs.dr3;
884 to->Dr6 = from->debug.i386_regs.dr6;
885 to->Dr7 = from->debug.i386_regs.dr7;
887 if ((from->flags & SERVER_CTX_YMM_REGISTERS) && (to_flags & CONTEXT_AMD64_XSTATE))
889 CONTEXT_EX *xctx = (CONTEXT_EX *)(to + 1);
890 XSTATE *xs = (XSTATE *)((char *)xctx + xctx->XState.Offset);
892 xs->Mask &= ~4;
893 if (user_shared_data->XState.CompactionEnabled) xs->CompactionMask = 0x8000000000000004;
894 for (i = 0; i < ARRAY_SIZE( from->ymm.regs.ymm_high); i++)
896 if (!from->ymm.regs.ymm_high[i].low && !from->ymm.regs.ymm_high[i].high) continue;
897 memcpy( &xs->YmmContext, &from->ymm.regs, sizeof(xs->YmmContext) );
898 xs->Mask |= 4;
899 break;
902 return STATUS_SUCCESS;
905 case MAKELONG( IMAGE_FILE_MACHINE_ARMNT, IMAGE_FILE_MACHINE_ARMNT ):
907 ARM_CONTEXT *to = dst;
909 to_flags = to->ContextFlags & ~CONTEXT_ARM;
910 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_ARM_CONTROL))
912 to->ContextFlags |= CONTEXT_ARM_CONTROL;
913 to->Sp = from->ctl.arm_regs.sp;
914 to->Lr = from->ctl.arm_regs.lr;
915 to->Pc = from->ctl.arm_regs.pc;
916 to->Cpsr = from->ctl.arm_regs.cpsr;
918 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_ARM_INTEGER))
920 to->ContextFlags |= CONTEXT_ARM_INTEGER;
921 to->R0 = from->integer.arm_regs.r[0];
922 to->R1 = from->integer.arm_regs.r[1];
923 to->R2 = from->integer.arm_regs.r[2];
924 to->R3 = from->integer.arm_regs.r[3];
925 to->R4 = from->integer.arm_regs.r[4];
926 to->R5 = from->integer.arm_regs.r[5];
927 to->R6 = from->integer.arm_regs.r[6];
928 to->R7 = from->integer.arm_regs.r[7];
929 to->R8 = from->integer.arm_regs.r[8];
930 to->R9 = from->integer.arm_regs.r[9];
931 to->R10 = from->integer.arm_regs.r[10];
932 to->R11 = from->integer.arm_regs.r[11];
933 to->R12 = from->integer.arm_regs.r[12];
935 if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_ARM_FLOATING_POINT))
937 to->ContextFlags |= CONTEXT_ARM_FLOATING_POINT;
938 for (i = 0; i < 32; i++) to->u.D[i] = from->fp.arm_regs.d[i];
939 to->Fpscr = from->fp.arm_regs.fpscr;
941 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_ARM_DEBUG_REGISTERS))
943 to->ContextFlags |= CONTEXT_ARM_DEBUG_REGISTERS;
944 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm_regs.bvr[i];
945 for (i = 0; i < ARM_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm_regs.bcr[i];
946 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm_regs.wvr[i];
947 for (i = 0; i < ARM_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm_regs.wcr[i];
949 return STATUS_SUCCESS;
952 case MAKELONG( IMAGE_FILE_MACHINE_ARM64, IMAGE_FILE_MACHINE_ARM64 ):
954 ARM64_NT_CONTEXT *to = dst;
956 to_flags = to->ContextFlags & ~CONTEXT_ARM64;
957 to->ContextFlags = CONTEXT_ARM64;
958 if ((from->flags & SERVER_CTX_CONTROL) && (to_flags & CONTEXT_ARM64_CONTROL))
960 to->ContextFlags |= CONTEXT_ARM64_CONTROL;
961 to->u.s.Fp = from->integer.arm64_regs.x[29];
962 to->u.s.Lr = from->integer.arm64_regs.x[30];
963 to->Sp = from->ctl.arm64_regs.sp;
964 to->Pc = from->ctl.arm64_regs.pc;
965 to->Cpsr = from->ctl.arm64_regs.pstate;
967 if ((from->flags & SERVER_CTX_INTEGER) && (to_flags & CONTEXT_ARM64_INTEGER))
969 to->ContextFlags |= CONTEXT_ARM64_INTEGER;
970 for (i = 0; i <= 28; i++) to->u.X[i] = from->integer.arm64_regs.x[i];
972 if ((from->flags & SERVER_CTX_FLOATING_POINT) && (to_flags & CONTEXT_ARM64_FLOATING_POINT))
974 to->ContextFlags |= CONTEXT_ARM64_FLOATING_POINT;
975 for (i = 0; i < 32; i++)
977 to->V[i].s.Low = from->fp.arm64_regs.q[i].low;
978 to->V[i].s.High = from->fp.arm64_regs.q[i].high;
980 to->Fpcr = from->fp.arm64_regs.fpcr;
981 to->Fpsr = from->fp.arm64_regs.fpsr;
983 if ((from->flags & SERVER_CTX_DEBUG_REGISTERS) && (to_flags & CONTEXT_ARM64_DEBUG_REGISTERS))
985 to->ContextFlags |= CONTEXT_ARM64_DEBUG_REGISTERS;
986 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bcr[i] = from->debug.arm64_regs.bcr[i];
987 for (i = 0; i < ARM64_MAX_BREAKPOINTS; i++) to->Bvr[i] = from->debug.arm64_regs.bvr[i];
988 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wcr[i] = from->debug.arm64_regs.wcr[i];
989 for (i = 0; i < ARM64_MAX_WATCHPOINTS; i++) to->Wvr[i] = from->debug.arm64_regs.wvr[i];
991 return STATUS_SUCCESS;
994 default:
995 return STATUS_INVALID_PARAMETER;
1000 /***********************************************************************
1001 * contexts_to_server
1003 static void contexts_to_server( context_t server_contexts[2], CONTEXT *context )
1005 unsigned int count = 0;
1006 void *native_context = get_native_context( context );
1007 void *wow_context = get_wow_context( context );
1009 if (native_context)
1011 context_to_server( &server_contexts[count++], native_machine, native_context, native_machine );
1012 if (wow_context) context_to_server( &server_contexts[count++], main_image_info.Machine,
1013 wow_context, main_image_info.Machine );
1014 else if (native_machine != main_image_info.Machine)
1015 context_to_server( &server_contexts[count++], main_image_info.Machine,
1016 native_context, native_machine );
1018 else
1019 context_to_server( &server_contexts[count++], native_machine,
1020 wow_context, main_image_info.Machine );
1022 if (count < 2) memset( &server_contexts[1], 0, sizeof(server_contexts[1]) );
1026 /***********************************************************************
1027 * contexts_from_server
1029 static void contexts_from_server( CONTEXT *context, context_t server_contexts[2] )
1031 void *native_context = get_native_context( context );
1032 void *wow_context = get_wow_context( context );
1034 if (native_context)
1036 context_from_server( native_context, &server_contexts[0], native_machine );
1037 if (wow_context) context_from_server( wow_context, &server_contexts[1], main_image_info.Machine );
1039 else context_from_server( wow_context, &server_contexts[0], main_image_info.Machine );
1043 /***********************************************************************
1044 * pthread_exit_wrapper
1046 static void pthread_exit_wrapper( int status )
1048 close( ntdll_get_thread_data()->wait_fd[0] );
1049 close( ntdll_get_thread_data()->wait_fd[1] );
1050 close( ntdll_get_thread_data()->reply_fd );
1051 close( ntdll_get_thread_data()->request_fd );
1052 pthread_exit( UIntToPtr(status) );
1056 /***********************************************************************
1057 * start_thread
1059 * Startup routine for a newly created thread.
1061 static void start_thread( TEB *teb )
1063 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1064 BOOL suspend;
1066 thread_data->pthread_id = pthread_self();
1067 signal_init_thread( teb );
1068 server_init_thread( thread_data->start, &suspend );
1069 signal_start_thread( thread_data->start, thread_data->param, suspend, teb );
1073 /***********************************************************************
1074 * get_machine_context_size
1076 static SIZE_T get_machine_context_size( USHORT machine )
1078 switch (machine)
1080 case IMAGE_FILE_MACHINE_I386: return sizeof(I386_CONTEXT);
1081 case IMAGE_FILE_MACHINE_ARMNT: return sizeof(ARM_CONTEXT);
1082 case IMAGE_FILE_MACHINE_AMD64: return sizeof(AMD64_CONTEXT);
1083 case IMAGE_FILE_MACHINE_ARM64: return sizeof(ARM64_NT_CONTEXT);
1084 default: return 0;
1089 /***********************************************************************
1090 * get_cpu_area
1092 * cf. RtlWow64GetCurrentCpuArea
1094 void *get_cpu_area( USHORT machine )
1096 WOW64_CPURESERVED *cpu;
1097 ULONG align;
1099 if (!NtCurrentTeb()->WowTebOffset) return NULL;
1100 #ifdef _WIN64
1101 cpu = NtCurrentTeb()->TlsSlots[WOW64_TLS_CPURESERVED];
1102 #else
1103 cpu = ULongToPtr( NtCurrentTeb64()->TlsSlots[WOW64_TLS_CPURESERVED] );
1104 #endif
1105 if (cpu->Machine != machine) return NULL;
1106 switch (cpu->Machine)
1108 case IMAGE_FILE_MACHINE_I386: align = TYPE_ALIGNMENT(I386_CONTEXT); break;
1109 case IMAGE_FILE_MACHINE_AMD64: align = TYPE_ALIGNMENT(ARM_CONTEXT); break;
1110 case IMAGE_FILE_MACHINE_ARMNT: align = TYPE_ALIGNMENT(AMD64_CONTEXT); break;
1111 case IMAGE_FILE_MACHINE_ARM64: align = TYPE_ALIGNMENT(ARM64_NT_CONTEXT); break;
1112 default: return NULL;
1114 return (void *)(((ULONG_PTR)(cpu + 1) + align - 1) & ~(align - 1));
1118 /***********************************************************************
1119 * set_thread_id
1121 void set_thread_id( TEB *teb, DWORD pid, DWORD tid )
1123 WOW_TEB *wow_teb = get_wow_teb( teb );
1125 teb->ClientId.UniqueProcess = ULongToHandle( pid );
1126 teb->ClientId.UniqueThread = ULongToHandle( tid );
1127 teb->RealClientId = teb->ClientId;
1128 if (wow_teb)
1130 wow_teb->ClientId.UniqueProcess = pid;
1131 wow_teb->ClientId.UniqueThread = tid;
1132 wow_teb->RealClientId = wow_teb->ClientId;
1137 /***********************************************************************
1138 * init_thread_stack
1140 NTSTATUS init_thread_stack( TEB *teb, ULONG_PTR zero_bits, SIZE_T reserve_size, SIZE_T commit_size )
1142 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1143 WOW_TEB *wow_teb = get_wow_teb( teb );
1144 INITIAL_TEB stack;
1145 NTSTATUS status;
1147 if (wow_teb)
1149 WOW64_CPURESERVED *cpu;
1150 SIZE_T cpusize = sizeof(WOW64_CPURESERVED) +
1151 ((get_machine_context_size( main_image_info.Machine ) + 7) & ~7) + sizeof(ULONG64);
1153 #ifdef _WIN64
1154 /* 32-bit stack */
1155 if ((status = virtual_alloc_thread_stack( &stack, zero_bits ? zero_bits : 0x7fffffff,
1156 reserve_size, commit_size, 0 )))
1157 return status;
1158 wow_teb->Tib.StackBase = PtrToUlong( stack.StackBase );
1159 wow_teb->Tib.StackLimit = PtrToUlong( stack.StackLimit );
1160 wow_teb->DeallocationStack = PtrToUlong( stack.DeallocationStack );
1162 /* 64-bit stack */
1163 if ((status = virtual_alloc_thread_stack( &stack, 0, 0x40000, 0x40000, kernel_stack_size )))
1164 return status;
1165 cpu = (WOW64_CPURESERVED *)(((ULONG_PTR)stack.StackBase - cpusize) & ~15);
1166 cpu->Machine = main_image_info.Machine;
1167 teb->Tib.StackBase = teb->TlsSlots[WOW64_TLS_CPURESERVED] = cpu;
1168 teb->Tib.StackLimit = stack.StackLimit;
1169 teb->DeallocationStack = stack.DeallocationStack;
1170 thread_data->kernel_stack = stack.StackBase;
1171 return STATUS_SUCCESS;
1172 #else
1173 /* 64-bit stack */
1174 if ((status = virtual_alloc_thread_stack( &stack, 0, 0x40000, 0x40000, 0 ))) return status;
1176 cpu = (WOW64_CPURESERVED *)(((ULONG_PTR)stack.StackBase - cpusize) & ~15);
1177 cpu->Machine = main_image_info.Machine;
1178 wow_teb->Tib.StackBase = wow_teb->TlsSlots[WOW64_TLS_CPURESERVED] = PtrToUlong( cpu );
1179 wow_teb->Tib.StackLimit = PtrToUlong( stack.StackLimit );
1180 wow_teb->DeallocationStack = PtrToUlong( stack.DeallocationStack );
1181 #endif
1184 /* native stack */
1185 if ((status = virtual_alloc_thread_stack( &stack, zero_bits, reserve_size,
1186 commit_size, kernel_stack_size )))
1187 return status;
1188 teb->Tib.StackBase = stack.StackBase;
1189 teb->Tib.StackLimit = stack.StackLimit;
1190 teb->DeallocationStack = stack.DeallocationStack;
1191 thread_data->kernel_stack = stack.StackBase;
1192 return STATUS_SUCCESS;
1196 /***********************************************************************
1197 * update_attr_list
1199 * Update the output attributes.
1201 static void update_attr_list( PS_ATTRIBUTE_LIST *attr, const CLIENT_ID *id, TEB *teb )
1203 SIZE_T i, count = (attr->TotalLength - sizeof(attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
1205 for (i = 0; i < count; i++)
1207 if (attr->Attributes[i].Attribute == PS_ATTRIBUTE_CLIENT_ID)
1209 SIZE_T size = min( attr->Attributes[i].Size, sizeof(*id) );
1210 memcpy( attr->Attributes[i].ValuePtr, id, size );
1211 if (attr->Attributes[i].ReturnLength) *attr->Attributes[i].ReturnLength = size;
1213 else if (attr->Attributes[i].Attribute == PS_ATTRIBUTE_TEB_ADDRESS)
1215 SIZE_T size = min( attr->Attributes[i].Size, sizeof(teb) );
1216 memcpy( attr->Attributes[i].ValuePtr, &teb, size );
1217 if (attr->Attributes[i].ReturnLength) *attr->Attributes[i].ReturnLength = size;
1222 /***********************************************************************
1223 * NtCreateThread (NTDLL.@)
1225 NTSTATUS WINAPI NtCreateThread( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
1226 HANDLE process, CLIENT_ID *id, CONTEXT *ctx, INITIAL_TEB *teb,
1227 BOOLEAN suspended )
1229 FIXME( "%p %d %p %p %p %p %p %d, stub!\n", handle, access, attr, process, id, ctx, teb, suspended );
1230 return STATUS_NOT_IMPLEMENTED;
1233 /***********************************************************************
1234 * NtCreateThreadEx (NTDLL.@)
1236 NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
1237 HANDLE process, PRTL_THREAD_START_ROUTINE start, void *param,
1238 ULONG flags, ULONG_PTR zero_bits, SIZE_T stack_commit,
1239 SIZE_T stack_reserve, PS_ATTRIBUTE_LIST *attr_list )
1241 static const ULONG supported_flags = THREAD_CREATE_FLAGS_CREATE_SUSPENDED | THREAD_CREATE_FLAGS_HIDE_FROM_DEBUGGER;
1242 sigset_t sigset;
1243 pthread_t pthread_id;
1244 pthread_attr_t pthread_attr;
1245 data_size_t len;
1246 struct object_attributes *objattr;
1247 struct ntdll_thread_data *thread_data;
1248 DWORD tid = 0;
1249 int request_pipe[2];
1250 TEB *teb;
1251 NTSTATUS status;
1253 if (flags & ~supported_flags)
1254 FIXME( "Unsupported flags %#x.\n", flags );
1256 if (zero_bits > 21 && zero_bits < 32) return STATUS_INVALID_PARAMETER_3;
1257 #ifndef _WIN64
1258 if (!is_wow64 && zero_bits >= 32) return STATUS_INVALID_PARAMETER_3;
1259 #endif
1261 if (process != NtCurrentProcess())
1263 apc_call_t call;
1264 apc_result_t result;
1266 memset( &call, 0, sizeof(call) );
1268 call.create_thread.type = APC_CREATE_THREAD;
1269 call.create_thread.flags = flags;
1270 call.create_thread.func = wine_server_client_ptr( start );
1271 call.create_thread.arg = wine_server_client_ptr( param );
1272 call.create_thread.zero_bits = zero_bits;
1273 call.create_thread.reserve = stack_reserve;
1274 call.create_thread.commit = stack_commit;
1275 status = server_queue_process_apc( process, &call, &result );
1276 if (status != STATUS_SUCCESS) return status;
1278 if (result.create_thread.status == STATUS_SUCCESS)
1280 CLIENT_ID client_id;
1281 TEB *teb = wine_server_get_ptr( result.create_thread.teb );
1282 *handle = wine_server_ptr_handle( result.create_thread.handle );
1283 client_id.UniqueProcess = ULongToHandle( result.create_thread.pid );
1284 client_id.UniqueThread = ULongToHandle( result.create_thread.tid );
1285 if (attr_list) update_attr_list( attr_list, &client_id, teb );
1287 return result.create_thread.status;
1290 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
1292 if (server_pipe( request_pipe ) == -1)
1294 free( objattr );
1295 return STATUS_TOO_MANY_OPENED_FILES;
1297 wine_server_send_fd( request_pipe[0] );
1299 if (!access) access = THREAD_ALL_ACCESS;
1301 SERVER_START_REQ( new_thread )
1303 req->process = wine_server_obj_handle( process );
1304 req->access = access;
1305 req->flags = flags;
1306 req->request_fd = request_pipe[0];
1307 wine_server_add_data( req, objattr, len );
1308 if (!(status = wine_server_call( req )))
1310 *handle = wine_server_ptr_handle( reply->handle );
1311 tid = reply->tid;
1313 close( request_pipe[0] );
1315 SERVER_END_REQ;
1317 free( objattr );
1318 if (status)
1320 close( request_pipe[1] );
1321 return status;
1324 pthread_sigmask( SIG_BLOCK, &server_block_set, &sigset );
1326 if ((status = virtual_alloc_teb( &teb ))) goto done;
1328 if ((status = init_thread_stack( teb, zero_bits, stack_reserve, stack_commit )))
1330 virtual_free_teb( teb );
1331 goto done;
1334 set_thread_id( teb, GetCurrentProcessId(), tid );
1336 thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1337 thread_data->request_fd = request_pipe[1];
1338 thread_data->start = start;
1339 thread_data->param = param;
1341 pthread_attr_init( &pthread_attr );
1342 pthread_attr_setstack( &pthread_attr, teb->DeallocationStack,
1343 (char *)thread_data->kernel_stack + kernel_stack_size - (char *)teb->DeallocationStack );
1344 pthread_attr_setguardsize( &pthread_attr, 0 );
1345 pthread_attr_setscope( &pthread_attr, PTHREAD_SCOPE_SYSTEM ); /* force creating a kernel thread */
1346 InterlockedIncrement( &nb_threads );
1347 if (pthread_create( &pthread_id, &pthread_attr, (void * (*)(void *))start_thread, teb ))
1349 InterlockedDecrement( &nb_threads );
1350 virtual_free_teb( teb );
1351 status = STATUS_NO_MEMORY;
1353 pthread_attr_destroy( &pthread_attr );
1355 done:
1356 pthread_sigmask( SIG_SETMASK, &sigset, NULL );
1357 if (status)
1359 NtClose( *handle );
1360 close( request_pipe[1] );
1361 return status;
1363 if (attr_list) update_attr_list( attr_list, &teb->ClientId, teb );
1364 return STATUS_SUCCESS;
1368 /***********************************************************************
1369 * abort_thread
1371 void abort_thread( int status )
1373 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
1374 if (InterlockedDecrement( &nb_threads ) <= 0) abort_process( status );
1375 signal_exit_thread( status, pthread_exit_wrapper, NtCurrentTeb() );
1379 /***********************************************************************
1380 * abort_process
1382 void abort_process( int status )
1384 _exit( get_unix_exit_code( status ));
1388 /***********************************************************************
1389 * exit_thread
1391 static DECLSPEC_NORETURN void exit_thread( int status )
1393 static void *prev_teb;
1394 TEB *teb;
1396 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
1398 if ((teb = InterlockedExchangePointer( &prev_teb, NtCurrentTeb() )))
1400 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
1402 if (thread_data->pthread_id)
1404 pthread_join( thread_data->pthread_id, NULL );
1405 virtual_free_teb( teb );
1408 signal_exit_thread( status, pthread_exit_wrapper, NtCurrentTeb() );
1412 /***********************************************************************
1413 * exit_process
1415 void exit_process( int status )
1417 pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
1418 signal_exit_thread( get_unix_exit_code( status ), process_exit_wrapper, NtCurrentTeb() );
1422 /**********************************************************************
1423 * wait_suspend
1425 * Wait until the thread is no longer suspended.
1427 void wait_suspend( CONTEXT *context )
1429 int saved_errno = errno;
1430 context_t server_contexts[2];
1432 contexts_to_server( server_contexts, context );
1433 /* wait with 0 timeout, will only return once the thread is no longer suspended */
1434 server_select( NULL, 0, SELECT_INTERRUPTIBLE, 0, server_contexts, NULL );
1435 contexts_from_server( context, server_contexts );
1436 errno = saved_errno;
1440 /**********************************************************************
1441 * send_debug_event
1443 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
1445 NTSTATUS send_debug_event( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1447 NTSTATUS ret;
1448 DWORD i;
1449 obj_handle_t handle = 0;
1450 client_ptr_t params[EXCEPTION_MAXIMUM_PARAMETERS];
1451 select_op_t select_op;
1452 sigset_t old_set;
1454 if (!peb->BeingDebugged) return 0; /* no debugger present */
1456 pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set );
1458 for (i = 0; i < min( rec->NumberParameters, EXCEPTION_MAXIMUM_PARAMETERS ); i++)
1459 params[i] = rec->ExceptionInformation[i];
1461 SERVER_START_REQ( queue_exception_event )
1463 req->first = first_chance;
1464 req->code = rec->ExceptionCode;
1465 req->flags = rec->ExceptionFlags;
1466 req->record = wine_server_client_ptr( rec->ExceptionRecord );
1467 req->address = wine_server_client_ptr( rec->ExceptionAddress );
1468 req->len = i * sizeof(params[0]);
1469 wine_server_add_data( req, params, req->len );
1470 if (!(ret = wine_server_call( req ))) handle = reply->handle;
1472 SERVER_END_REQ;
1474 if (handle)
1476 context_t server_contexts[2];
1478 select_op.wait.op = SELECT_WAIT;
1479 select_op.wait.handles[0] = handle;
1481 contexts_to_server( server_contexts, context );
1482 server_select( &select_op, offsetof( select_op_t, wait.handles[1] ), SELECT_INTERRUPTIBLE,
1483 TIMEOUT_INFINITE, server_contexts, NULL );
1485 SERVER_START_REQ( get_exception_status )
1487 req->handle = handle;
1488 ret = wine_server_call( req );
1490 SERVER_END_REQ;
1491 if (ret >= 0) contexts_from_server( context, server_contexts );
1494 pthread_sigmask( SIG_SETMASK, &old_set, NULL );
1495 return ret;
1499 /*******************************************************************
1500 * NtRaiseException (NTDLL.@)
1502 NTSTATUS WINAPI NtRaiseException( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance )
1504 NTSTATUS status = send_debug_event( rec, context, first_chance );
1506 if (status == DBG_CONTINUE || status == DBG_EXCEPTION_HANDLED)
1507 return NtContinue( context, FALSE );
1509 if (first_chance) return call_user_exception_dispatcher( rec, context );
1511 if (rec->ExceptionFlags & EH_STACK_INVALID)
1512 ERR_(seh)("Exception frame is not in stack limits => unable to dispatch exception.\n");
1513 else if (rec->ExceptionCode == STATUS_NONCONTINUABLE_EXCEPTION)
1514 ERR_(seh)("Process attempted to continue execution after noncontinuable exception.\n");
1515 else
1516 ERR_(seh)("Unhandled exception code %x flags %x addr %p\n",
1517 rec->ExceptionCode, rec->ExceptionFlags, rec->ExceptionAddress );
1519 NtTerminateProcess( NtCurrentProcess(), rec->ExceptionCode );
1520 return STATUS_SUCCESS;
1524 /***********************************************************************
1525 * NtOpenThread (NTDLL.@)
1527 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
1528 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
1530 NTSTATUS ret;
1532 *handle = 0;
1534 SERVER_START_REQ( open_thread )
1536 req->tid = HandleToULong(id->UniqueThread);
1537 req->access = access;
1538 req->attributes = attr ? attr->Attributes : 0;
1539 ret = wine_server_call( req );
1540 *handle = wine_server_ptr_handle( reply->handle );
1542 SERVER_END_REQ;
1543 return ret;
1547 /******************************************************************************
1548 * NtSuspendThread (NTDLL.@)
1550 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count )
1552 NTSTATUS ret;
1554 SERVER_START_REQ( suspend_thread )
1556 req->handle = wine_server_obj_handle( handle );
1557 if (!(ret = wine_server_call( req )))
1559 if (count) *count = reply->count;
1562 SERVER_END_REQ;
1563 return ret;
1567 /******************************************************************************
1568 * NtResumeThread (NTDLL.@)
1570 NTSTATUS WINAPI NtResumeThread( HANDLE handle, ULONG *count )
1572 NTSTATUS ret;
1574 SERVER_START_REQ( resume_thread )
1576 req->handle = wine_server_obj_handle( handle );
1577 if (!(ret = wine_server_call( req )))
1579 if (count) *count = reply->count;
1582 SERVER_END_REQ;
1583 return ret;
1587 /******************************************************************************
1588 * NtAlertResumeThread (NTDLL.@)
1590 NTSTATUS WINAPI NtAlertResumeThread( HANDLE handle, ULONG *count )
1592 FIXME( "stub: should alert thread %p\n", handle );
1593 return NtResumeThread( handle, count );
1597 /******************************************************************************
1598 * NtAlertThread (NTDLL.@)
1600 NTSTATUS WINAPI NtAlertThread( HANDLE handle )
1602 FIXME( "stub: %p\n", handle );
1603 return STATUS_NOT_IMPLEMENTED;
1607 /******************************************************************************
1608 * NtTerminateThread (NTDLL.@)
1610 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
1612 NTSTATUS ret;
1613 BOOL self = (handle == GetCurrentThread());
1615 if (!self || exit_code)
1617 SERVER_START_REQ( terminate_thread )
1619 req->handle = wine_server_obj_handle( handle );
1620 req->exit_code = exit_code;
1621 ret = wine_server_call( req );
1622 self = !ret && reply->self;
1624 SERVER_END_REQ;
1626 if (self) exit_thread( exit_code );
1627 return ret;
1631 /******************************************************************************
1632 * NtQueueApcThread (NTDLL.@)
1634 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
1635 ULONG_PTR arg2, ULONG_PTR arg3 )
1637 NTSTATUS ret;
1639 SERVER_START_REQ( queue_apc )
1641 req->handle = wine_server_obj_handle( handle );
1642 if (func)
1644 req->call.type = APC_USER;
1645 req->call.user.func = wine_server_client_ptr( func );
1646 req->call.user.args[0] = arg1;
1647 req->call.user.args[1] = arg2;
1648 req->call.user.args[2] = arg3;
1650 else req->call.type = APC_NONE; /* wake up only */
1651 ret = wine_server_call( req );
1653 SERVER_END_REQ;
1654 return ret;
1658 /***********************************************************************
1659 * set_thread_context
1661 NTSTATUS set_thread_context( HANDLE handle, const void *context, BOOL *self, USHORT machine )
1663 context_t server_contexts[2];
1664 unsigned int count = 0;
1665 NTSTATUS ret;
1667 context_to_server( &server_contexts[count++], native_machine, context, machine );
1668 if (machine != native_machine)
1669 context_to_server( &server_contexts[count++], machine, context, machine );
1671 SERVER_START_REQ( set_thread_context )
1673 req->handle = wine_server_obj_handle( handle );
1674 wine_server_add_data( req, server_contexts, count * sizeof(server_contexts[0]) );
1675 ret = wine_server_call( req );
1676 *self = reply->self;
1678 SERVER_END_REQ;
1680 return ret;
1684 /***********************************************************************
1685 * get_thread_context
1687 NTSTATUS get_thread_context( HANDLE handle, void *context, BOOL *self, USHORT machine )
1689 NTSTATUS ret;
1690 HANDLE context_handle;
1691 context_t server_contexts[2];
1692 unsigned int count;
1693 unsigned int flags = get_server_context_flags( context, machine );
1695 SERVER_START_REQ( get_thread_context )
1697 req->handle = wine_server_obj_handle( handle );
1698 req->flags = flags;
1699 req->machine = machine;
1700 wine_server_set_reply( req, server_contexts, sizeof(server_contexts) );
1701 ret = wine_server_call( req );
1702 *self = reply->self;
1703 context_handle = wine_server_ptr_handle( reply->handle );
1704 count = wine_server_reply_size( reply ) / sizeof(server_contexts[0]);
1706 SERVER_END_REQ;
1708 if (ret == STATUS_PENDING)
1710 NtWaitForSingleObject( context_handle, FALSE, NULL );
1712 SERVER_START_REQ( get_thread_context )
1714 req->context = wine_server_obj_handle( context_handle );
1715 req->flags = flags;
1716 req->machine = machine;
1717 wine_server_set_reply( req, server_contexts, sizeof(server_contexts) );
1718 ret = wine_server_call( req );
1719 count = wine_server_reply_size( reply ) / sizeof(server_contexts[0]);
1721 SERVER_END_REQ;
1723 if (!ret)
1725 ret = context_from_server( context, &server_contexts[0], machine );
1726 if (!ret && count > 1) ret = context_from_server( context, &server_contexts[1], machine );
1728 return ret;
1732 /***********************************************************************
1733 * ntdll_set_exception_jmp_buf
1735 void ntdll_set_exception_jmp_buf( __wine_jmp_buf *jmp )
1737 assert( !jmp || !ntdll_get_thread_data()->jmp_buf );
1738 ntdll_get_thread_data()->jmp_buf = jmp;
1742 BOOL get_thread_times(int unix_pid, int unix_tid, LARGE_INTEGER *kernel_time, LARGE_INTEGER *user_time)
1744 #ifdef linux
1745 unsigned long clocks_per_sec = sysconf( _SC_CLK_TCK );
1746 unsigned long usr, sys;
1747 const char *pos;
1748 char buf[512];
1749 FILE *f;
1750 int i;
1752 if (unix_tid == -1)
1753 sprintf( buf, "/proc/%u/stat", unix_pid );
1754 else
1755 sprintf( buf, "/proc/%u/task/%u/stat", unix_pid, unix_tid );
1756 if (!(f = fopen( buf, "r" )))
1758 WARN("Failed to open %s: %s\n", buf, strerror(errno));
1759 return FALSE;
1762 pos = fgets( buf, sizeof(buf), f );
1763 fclose( f );
1765 /* the process name is printed unescaped, so we have to skip to the last ')'
1766 * to avoid misinterpreting the string */
1767 if (pos) pos = strrchr( pos, ')' );
1768 if (pos) pos = strchr( pos + 1, ' ' );
1769 if (pos) pos++;
1771 /* skip over the following fields: state, ppid, pgid, sid, tty_nr, tty_pgrp,
1772 * task->flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
1773 for (i = 0; i < 11 && pos; i++)
1775 pos = strchr( pos + 1, ' ' );
1776 if (pos) pos++;
1779 /* the next two values are user and system time */
1780 if (pos && (sscanf( pos, "%lu %lu", &usr, &sys ) == 2))
1782 kernel_time->QuadPart = (ULONGLONG)sys * 10000000 / clocks_per_sec;
1783 user_time->QuadPart = (ULONGLONG)usr * 10000000 / clocks_per_sec;
1784 return TRUE;
1787 ERR("Failed to parse %s\n", debugstr_a(buf));
1788 return FALSE;
1789 #elif defined(HAVE_LIBPROCSTAT)
1790 struct procstat *pstat;
1791 struct kinfo_proc *kip;
1792 unsigned int proc_count;
1793 BOOL ret = FALSE;
1795 pstat = procstat_open_sysctl();
1796 if (!pstat)
1797 return FALSE;
1798 if (unix_tid == -1)
1799 kip = procstat_getprocs(pstat, KERN_PROC_PID, unix_pid, &proc_count);
1800 else
1801 kip = procstat_getprocs(pstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, unix_pid, &proc_count);
1802 if (kip)
1804 unsigned int i;
1805 for (i = 0; i < proc_count; i++)
1807 if (unix_tid == -1 || kip[i].ki_tid == unix_tid)
1809 kernel_time->QuadPart = 10000000 * (ULONGLONG)kip[i].ki_rusage.ru_stime.tv_sec +
1810 10 * (ULONGLONG)kip[i].ki_rusage.ru_stime.tv_usec;
1811 user_time->QuadPart = 10000000 * (ULONGLONG)kip[i].ki_rusage.ru_utime.tv_sec +
1812 10 * (ULONGLONG)kip[i].ki_rusage.ru_utime.tv_usec;
1813 ret = TRUE;
1814 break;
1817 procstat_freeprocs(pstat, kip);
1819 procstat_close(pstat);
1820 return ret;
1821 #else
1822 static int once;
1823 if (!once++) FIXME("not implemented on this platform\n");
1824 return FALSE;
1825 #endif
1828 #ifndef _WIN64
1829 static BOOL is_process_wow64( const CLIENT_ID *id )
1831 HANDLE handle;
1832 ULONG_PTR info;
1833 BOOL ret = FALSE;
1835 if (id->UniqueProcess == ULongToHandle(GetCurrentProcessId())) return is_wow64;
1836 if (!NtOpenProcess( &handle, PROCESS_QUERY_LIMITED_INFORMATION, NULL, id ))
1838 if (!NtQueryInformationProcess( handle, ProcessWow64Information, &info, sizeof(info), NULL ))
1839 ret = !!info;
1840 NtClose( handle );
1842 return ret;
1844 #endif
1846 /******************************************************************************
1847 * NtQueryInformationThread (NTDLL.@)
1849 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
1850 void *data, ULONG length, ULONG *ret_len )
1852 NTSTATUS status;
1854 TRACE("(%p,%d,%p,%x,%p)\n", handle, class, data, length, ret_len);
1856 switch (class)
1858 case ThreadBasicInformation:
1860 THREAD_BASIC_INFORMATION info;
1861 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1863 SERVER_START_REQ( get_thread_info )
1865 req->handle = wine_server_obj_handle( handle );
1866 if (!(status = wine_server_call( req )))
1868 info.ExitStatus = reply->exit_code;
1869 info.TebBaseAddress = wine_server_get_ptr( reply->teb );
1870 info.ClientId.UniqueProcess = ULongToHandle(reply->pid);
1871 info.ClientId.UniqueThread = ULongToHandle(reply->tid);
1872 info.AffinityMask = reply->affinity & affinity_mask;
1873 info.Priority = reply->priority;
1874 info.BasePriority = reply->priority; /* FIXME */
1877 SERVER_END_REQ;
1878 if (status == STATUS_SUCCESS)
1880 #ifndef _WIN64
1881 if (is_wow64)
1883 if (is_process_wow64( &info.ClientId ))
1884 info.TebBaseAddress = (char *)info.TebBaseAddress + teb_offset;
1885 else
1886 info.TebBaseAddress = NULL;
1888 #endif
1889 if (data) memcpy( data, &info, min( length, sizeof(info) ));
1890 if (ret_len) *ret_len = min( length, sizeof(info) );
1892 return status;
1895 case ThreadAffinityMask:
1897 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1898 ULONG_PTR affinity = 0;
1900 SERVER_START_REQ( get_thread_info )
1902 req->handle = wine_server_obj_handle( handle );
1903 req->access = THREAD_QUERY_INFORMATION;
1904 if (!(status = wine_server_call( req ))) affinity = reply->affinity & affinity_mask;
1906 SERVER_END_REQ;
1907 if (status == STATUS_SUCCESS)
1909 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
1910 if (ret_len) *ret_len = min( length, sizeof(affinity) );
1912 return status;
1915 case ThreadTimes:
1917 KERNEL_USER_TIMES kusrt;
1918 int unix_pid, unix_tid;
1920 SERVER_START_REQ( get_thread_times )
1922 req->handle = wine_server_obj_handle( handle );
1923 status = wine_server_call( req );
1924 if (status == STATUS_SUCCESS)
1926 kusrt.CreateTime.QuadPart = reply->creation_time;
1927 kusrt.ExitTime.QuadPart = reply->exit_time;
1928 unix_pid = reply->unix_pid;
1929 unix_tid = reply->unix_tid;
1932 SERVER_END_REQ;
1933 if (status == STATUS_SUCCESS)
1935 BOOL ret = FALSE;
1937 kusrt.KernelTime.QuadPart = kusrt.UserTime.QuadPart = 0;
1938 if (unix_pid != -1 && unix_tid != -1)
1939 ret = get_thread_times( unix_pid, unix_tid, &kusrt.KernelTime, &kusrt.UserTime );
1940 if (!ret && handle == GetCurrentThread())
1942 /* fall back to process times */
1943 struct tms time_buf;
1944 long clocks_per_sec = sysconf(_SC_CLK_TCK);
1946 times(&time_buf);
1947 kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
1948 kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
1950 if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
1951 if (ret_len) *ret_len = min( length, sizeof(kusrt) );
1953 return status;
1956 case ThreadDescriptorTableEntry:
1957 return get_thread_ldt_entry( handle, data, length, ret_len );
1959 case ThreadAmILastThread:
1961 if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
1962 SERVER_START_REQ( get_thread_info )
1964 req->handle = wine_server_obj_handle( handle );
1965 status = wine_server_call( req );
1966 if (status == STATUS_SUCCESS)
1968 ULONG last = reply->last;
1969 if (data) memcpy( data, &last, sizeof(last) );
1970 if (ret_len) *ret_len = sizeof(last);
1973 SERVER_END_REQ;
1974 return status;
1977 case ThreadQuerySetWin32StartAddress:
1979 SERVER_START_REQ( get_thread_info )
1981 req->handle = wine_server_obj_handle( handle );
1982 req->access = THREAD_QUERY_INFORMATION;
1983 status = wine_server_call( req );
1984 if (status == STATUS_SUCCESS)
1986 PRTL_THREAD_START_ROUTINE entry = wine_server_get_ptr( reply->entry_point );
1987 if (data) memcpy( data, &entry, min( length, sizeof(entry) ) );
1988 if (ret_len) *ret_len = min( length, sizeof(entry) );
1991 SERVER_END_REQ;
1992 return status;
1995 case ThreadGroupInformation:
1997 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1998 GROUP_AFFINITY affinity;
2000 memset( &affinity, 0, sizeof(affinity) );
2001 affinity.Group = 0; /* Wine only supports max 64 processors */
2003 SERVER_START_REQ( get_thread_info )
2005 req->handle = wine_server_obj_handle( handle );
2006 if (!(status = wine_server_call( req ))) affinity.Mask = reply->affinity & affinity_mask;
2008 SERVER_END_REQ;
2009 if (status == STATUS_SUCCESS)
2011 if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
2012 if (ret_len) *ret_len = min( length, sizeof(affinity) );
2014 return status;
2017 case ThreadIsIoPending:
2018 FIXME( "ThreadIsIoPending info class not supported yet\n" );
2019 if (length != sizeof(BOOL)) return STATUS_INFO_LENGTH_MISMATCH;
2020 if (!data) return STATUS_ACCESS_DENIED;
2021 *(BOOL*)data = FALSE;
2022 if (ret_len) *ret_len = sizeof(BOOL);
2023 return STATUS_SUCCESS;
2025 case ThreadSuspendCount:
2026 if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
2027 if (!data) return STATUS_ACCESS_VIOLATION;
2029 SERVER_START_REQ( get_thread_info )
2031 req->handle = wine_server_obj_handle( handle );
2032 if (!(status = wine_server_call( req ))) *(ULONG *)data = reply->suspend_count;
2034 SERVER_END_REQ;
2035 return status;
2037 case ThreadNameInformation:
2039 THREAD_NAME_INFORMATION *info = data;
2040 data_size_t len, desc_len = 0;
2041 WCHAR *ptr;
2043 len = length >= sizeof(*info) ? length - sizeof(*info) : 0;
2044 ptr = info ? (WCHAR *)(info + 1) : NULL;
2046 SERVER_START_REQ( get_thread_info )
2048 req->handle = wine_server_obj_handle( handle );
2049 if (ptr) wine_server_set_reply( req, ptr, len );
2050 status = wine_server_call( req );
2051 desc_len = reply->desc_len;
2053 SERVER_END_REQ;
2055 if (!info) status = STATUS_BUFFER_TOO_SMALL;
2056 else if (status == STATUS_SUCCESS)
2058 info->ThreadName.Length = info->ThreadName.MaximumLength = desc_len;
2059 info->ThreadName.Buffer = ptr;
2062 if (ret_len && (status == STATUS_SUCCESS || status == STATUS_BUFFER_TOO_SMALL))
2063 *ret_len = sizeof(*info) + desc_len;
2064 return status;
2067 case ThreadWow64Context:
2068 return get_thread_wow64_context( handle, data, length );
2070 case ThreadHideFromDebugger:
2071 if (length != sizeof(BOOLEAN)) return STATUS_INFO_LENGTH_MISMATCH;
2072 if (!data) return STATUS_ACCESS_VIOLATION;
2073 SERVER_START_REQ( get_thread_info )
2075 req->handle = wine_server_obj_handle( handle );
2076 req->access = THREAD_QUERY_INFORMATION;
2077 if ((status = wine_server_call( req ))) return status;
2078 *(BOOLEAN*)data = reply->dbg_hidden;
2080 SERVER_END_REQ;
2081 if (ret_len) *ret_len = sizeof(BOOLEAN);
2082 return STATUS_SUCCESS;
2084 case ThreadEnableAlignmentFaultFixup:
2085 return STATUS_INVALID_INFO_CLASS;
2087 case ThreadPriority:
2088 case ThreadBasePriority:
2089 case ThreadImpersonationToken:
2090 case ThreadEventPair_Reusable:
2091 case ThreadZeroTlsCell:
2092 case ThreadPerformanceCount:
2093 case ThreadIdealProcessor:
2094 case ThreadPriorityBoost:
2095 case ThreadSetTlsArrayAddress:
2096 default:
2097 FIXME( "info class %d not supported yet\n", class );
2098 return STATUS_NOT_IMPLEMENTED;
2103 /******************************************************************************
2104 * NtSetInformationThread (NTDLL.@)
2106 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
2107 const void *data, ULONG length )
2109 NTSTATUS status;
2111 TRACE("(%p,%d,%p,%x)\n", handle, class, data, length);
2113 switch (class)
2115 case ThreadZeroTlsCell:
2116 if (handle == GetCurrentThread())
2118 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
2119 return virtual_clear_tls_index( *(const ULONG *)data );
2121 FIXME( "ZeroTlsCell not supported on other threads\n" );
2122 return STATUS_NOT_IMPLEMENTED;
2124 case ThreadImpersonationToken:
2126 const HANDLE *token = data;
2128 if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
2129 TRACE("Setting ThreadImpersonationToken handle to %p\n", *token );
2130 SERVER_START_REQ( set_thread_info )
2132 req->handle = wine_server_obj_handle( handle );
2133 req->token = wine_server_obj_handle( *token );
2134 req->mask = SET_THREAD_INFO_TOKEN;
2135 status = wine_server_call( req );
2137 SERVER_END_REQ;
2138 return status;
2141 case ThreadBasePriority:
2143 const DWORD *pprio = data;
2144 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
2145 SERVER_START_REQ( set_thread_info )
2147 req->handle = wine_server_obj_handle( handle );
2148 req->priority = *pprio;
2149 req->mask = SET_THREAD_INFO_PRIORITY;
2150 status = wine_server_call( req );
2152 SERVER_END_REQ;
2153 return status;
2156 case ThreadAffinityMask:
2158 const ULONG_PTR affinity_mask = get_system_affinity_mask();
2159 ULONG_PTR req_aff;
2161 if (length != sizeof(ULONG_PTR)) return STATUS_INVALID_PARAMETER;
2162 req_aff = *(const ULONG_PTR *)data & affinity_mask;
2163 if (!req_aff) return STATUS_INVALID_PARAMETER;
2165 SERVER_START_REQ( set_thread_info )
2167 req->handle = wine_server_obj_handle( handle );
2168 req->affinity = req_aff;
2169 req->mask = SET_THREAD_INFO_AFFINITY;
2170 status = wine_server_call( req );
2172 SERVER_END_REQ;
2173 return status;
2176 case ThreadHideFromDebugger:
2177 if (length) return STATUS_INFO_LENGTH_MISMATCH;
2178 SERVER_START_REQ( set_thread_info )
2180 req->handle = wine_server_obj_handle( handle );
2181 req->mask = SET_THREAD_INFO_DBG_HIDDEN;
2182 status = wine_server_call( req );
2184 SERVER_END_REQ;
2185 return status;
2187 case ThreadQuerySetWin32StartAddress:
2189 const PRTL_THREAD_START_ROUTINE *entry = data;
2190 if (length != sizeof(PRTL_THREAD_START_ROUTINE)) return STATUS_INVALID_PARAMETER;
2191 SERVER_START_REQ( set_thread_info )
2193 req->handle = wine_server_obj_handle( handle );
2194 req->mask = SET_THREAD_INFO_ENTRYPOINT;
2195 req->entry_point = wine_server_client_ptr( *entry );
2196 status = wine_server_call( req );
2198 SERVER_END_REQ;
2199 return status;
2202 case ThreadGroupInformation:
2204 const ULONG_PTR affinity_mask = get_system_affinity_mask();
2205 const GROUP_AFFINITY *req_aff;
2207 if (length != sizeof(*req_aff)) return STATUS_INVALID_PARAMETER;
2208 if (!data) return STATUS_ACCESS_VIOLATION;
2209 req_aff = data;
2211 /* On Windows the request fails if the reserved fields are set */
2212 if (req_aff->Reserved[0] || req_aff->Reserved[1] || req_aff->Reserved[2])
2213 return STATUS_INVALID_PARAMETER;
2215 /* Wine only supports max 64 processors */
2216 if (req_aff->Group) return STATUS_INVALID_PARAMETER;
2217 if (req_aff->Mask & ~affinity_mask) return STATUS_INVALID_PARAMETER;
2218 if (!req_aff->Mask) return STATUS_INVALID_PARAMETER;
2219 SERVER_START_REQ( set_thread_info )
2221 req->handle = wine_server_obj_handle( handle );
2222 req->affinity = req_aff->Mask;
2223 req->mask = SET_THREAD_INFO_AFFINITY;
2224 status = wine_server_call( req );
2226 SERVER_END_REQ;
2227 return status;
2230 case ThreadNameInformation:
2232 const THREAD_NAME_INFORMATION *info = data;
2234 if (length != sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
2235 if (!info) return STATUS_ACCESS_VIOLATION;
2236 if (info->ThreadName.Length && !info->ThreadName.Buffer) return STATUS_ACCESS_VIOLATION;
2238 SERVER_START_REQ( set_thread_info )
2240 req->handle = wine_server_obj_handle( handle );
2241 req->mask = SET_THREAD_INFO_DESCRIPTION;
2242 wine_server_add_data( req, info->ThreadName.Buffer, info->ThreadName.Length );
2243 status = wine_server_call( req );
2245 SERVER_END_REQ;
2246 return status;
2249 case ThreadWow64Context:
2250 return set_thread_wow64_context( handle, data, length );
2252 case ThreadEnableAlignmentFaultFixup:
2253 if (length != sizeof(BOOLEAN)) return STATUS_INFO_LENGTH_MISMATCH;
2254 if (!data) return STATUS_ACCESS_VIOLATION;
2255 FIXME( "ThreadEnableAlignmentFaultFixup stub!\n" );
2256 return STATUS_SUCCESS;
2258 case ThreadBasicInformation:
2259 case ThreadTimes:
2260 case ThreadPriority:
2261 case ThreadDescriptorTableEntry:
2262 case ThreadEventPair_Reusable:
2263 case ThreadPerformanceCount:
2264 case ThreadAmILastThread:
2265 case ThreadIdealProcessor:
2266 case ThreadPriorityBoost:
2267 case ThreadSetTlsArrayAddress:
2268 case ThreadIsIoPending:
2269 default:
2270 FIXME( "info class %d not supported yet\n", class );
2271 return STATUS_NOT_IMPLEMENTED;
2276 /******************************************************************************
2277 * NtGetCurrentProcessorNumber (NTDLL.@)
2279 ULONG WINAPI NtGetCurrentProcessorNumber(void)
2281 ULONG processor;
2283 #if defined(__linux__) && defined(__NR_getcpu)
2284 int res = syscall(__NR_getcpu, &processor, NULL, NULL);
2285 if (res != -1) return processor;
2286 #endif
2288 if (peb->NumberOfProcessors > 1)
2290 ULONG_PTR thread_mask, processor_mask;
2292 if (!NtQueryInformationThread( GetCurrentThread(), ThreadAffinityMask,
2293 &thread_mask, sizeof(thread_mask), NULL ))
2295 for (processor = 0; processor < peb->NumberOfProcessors; processor++)
2297 processor_mask = (1 << processor);
2298 if (thread_mask & processor_mask)
2300 if (thread_mask != processor_mask)
2301 FIXME( "need multicore support (%d processors)\n",
2302 peb->NumberOfProcessors );
2303 return processor;
2308 /* fallback to the first processor */
2309 return 0;
2313 /******************************************************************************
2314 * NtGetNextThread (NTDLL.@)
2316 NTSTATUS WINAPI NtGetNextThread( HANDLE process, HANDLE thread, ACCESS_MASK access, ULONG attributes,
2317 ULONG flags, HANDLE *handle )
2319 HANDLE ret_handle = 0;
2320 NTSTATUS ret;
2322 TRACE( "process %p, thread %p, access %#x, attributes %#x, flags %#x, handle %p.\n",
2323 process, thread, access, attributes, flags, handle );
2325 SERVER_START_REQ( get_next_thread )
2327 req->process = wine_server_obj_handle( process );
2328 req->last = wine_server_obj_handle( thread );
2329 req->access = access;
2330 req->attributes = attributes;
2331 req->flags = flags;
2332 if (!(ret = wine_server_call( req ))) ret_handle = wine_server_ptr_handle( reply->handle );
2334 SERVER_END_REQ;
2336 *handle = ret_handle;
2337 return ret;