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