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>
47 #define NONAMELESSUNION
49 #define WIN32_NO_STATUS
52 #include "wine/server.h"
53 #include "wine/debug.h"
54 #include "wine/exception.h"
55 #include "unix_private.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(seh
);
59 #ifndef PTHREAD_STACK_MIN
60 #define PTHREAD_STACK_MIN 16384
63 static int nb_threads
= 1;
65 static inline int get_unix_exit_code( NTSTATUS status
)
67 /* prevent a nonzero exit code to end up truncated to zero in unix */
68 if (status
&& !(status
& 0xff)) return 1;
73 /***********************************************************************
74 * pthread_exit_wrapper
76 static void pthread_exit_wrapper( int status
)
78 close( ntdll_get_thread_data()->wait_fd
[0] );
79 close( ntdll_get_thread_data()->wait_fd
[1] );
80 close( ntdll_get_thread_data()->reply_fd
);
81 close( ntdll_get_thread_data()->request_fd
);
82 pthread_exit( UIntToPtr(status
) );
86 /***********************************************************************
89 * Startup routine for a newly created thread.
91 static void start_thread( TEB
*teb
)
93 struct ntdll_thread_data
*thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
94 struct debug_info debug_info
;
97 debug_info
.str_pos
= debug_info
.out_pos
= 0;
98 thread_data
->debug_info
= &debug_info
;
99 thread_data
->pthread_id
= pthread_self();
100 signal_init_thread( teb
);
101 server_init_thread( thread_data
->start
, &suspend
);
102 signal_start_thread( thread_data
->start
, thread_data
->param
, suspend
,
103 pRtlUserThreadStart
, pLdrInitializeThunk
, teb
);
107 /***********************************************************************
110 * Update the output attributes.
112 static void update_attr_list( PS_ATTRIBUTE_LIST
*attr
, const CLIENT_ID
*id
, TEB
*teb
)
114 SIZE_T i
, count
= (attr
->TotalLength
- sizeof(attr
->TotalLength
)) / sizeof(PS_ATTRIBUTE
);
116 for (i
= 0; i
< count
; i
++)
118 if (attr
->Attributes
[i
].Attribute
== PS_ATTRIBUTE_CLIENT_ID
)
120 SIZE_T size
= min( attr
->Attributes
[i
].Size
, sizeof(*id
) );
121 memcpy( attr
->Attributes
[i
].ValuePtr
, id
, size
);
122 if (attr
->Attributes
[i
].ReturnLength
) *attr
->Attributes
[i
].ReturnLength
= size
;
124 else if (attr
->Attributes
[i
].Attribute
== PS_ATTRIBUTE_TEB_ADDRESS
)
126 SIZE_T size
= min( attr
->Attributes
[i
].Size
, sizeof(teb
) );
127 memcpy( attr
->Attributes
[i
].ValuePtr
, &teb
, size
);
128 if (attr
->Attributes
[i
].ReturnLength
) *attr
->Attributes
[i
].ReturnLength
= size
;
134 /***********************************************************************
135 * NtCreateThreadEx (NTDLL.@)
137 NTSTATUS WINAPI
NtCreateThreadEx( HANDLE
*handle
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
138 HANDLE process
, PRTL_THREAD_START_ROUTINE start
, void *param
,
139 ULONG flags
, SIZE_T zero_bits
, SIZE_T stack_commit
,
140 SIZE_T stack_reserve
, PS_ATTRIBUTE_LIST
*attr_list
)
143 pthread_t pthread_id
;
144 pthread_attr_t pthread_attr
;
146 struct object_attributes
*objattr
;
147 struct ntdll_thread_data
*thread_data
;
150 SIZE_T extra_stack
= PTHREAD_STACK_MIN
;
156 if (process
!= NtCurrentProcess())
161 memset( &call
, 0, sizeof(call
) );
163 call
.create_thread
.type
= APC_CREATE_THREAD
;
164 call
.create_thread
.flags
= flags
;
165 call
.create_thread
.func
= wine_server_client_ptr( start
);
166 call
.create_thread
.arg
= wine_server_client_ptr( param
);
167 call
.create_thread
.reserve
= stack_reserve
;
168 call
.create_thread
.commit
= stack_commit
;
169 status
= server_queue_process_apc( process
, &call
, &result
);
170 if (status
!= STATUS_SUCCESS
) return status
;
172 if (result
.create_thread
.status
== STATUS_SUCCESS
)
174 TEB
*teb
= wine_server_get_ptr( result
.create_thread
.teb
);
175 *handle
= wine_server_ptr_handle( result
.create_thread
.handle
);
176 client_id
.UniqueProcess
= ULongToHandle( result
.create_thread
.pid
);
177 client_id
.UniqueThread
= ULongToHandle( result
.create_thread
.tid
);
178 if (attr_list
) update_attr_list( attr_list
, &client_id
, teb
);
180 return result
.create_thread
.status
;
183 if ((status
= alloc_object_attributes( attr
, &objattr
, &len
))) return status
;
185 if (server_pipe( request_pipe
) == -1)
188 return STATUS_TOO_MANY_OPENED_FILES
;
190 wine_server_send_fd( request_pipe
[0] );
192 if (!access
) access
= THREAD_ALL_ACCESS
;
194 SERVER_START_REQ( new_thread
)
196 req
->process
= wine_server_obj_handle( process
);
197 req
->access
= access
;
198 req
->suspend
= flags
& THREAD_CREATE_FLAGS_CREATE_SUSPENDED
;
199 req
->request_fd
= request_pipe
[0];
200 wine_server_add_data( req
, objattr
, len
);
201 if (!(status
= wine_server_call( req
)))
203 *handle
= wine_server_ptr_handle( reply
->handle
);
206 close( request_pipe
[0] );
213 close( request_pipe
[1] );
217 pthread_sigmask( SIG_BLOCK
, &server_block_set
, &sigset
);
219 if ((status
= virtual_alloc_teb( &teb
))) goto done
;
221 if ((status
= virtual_alloc_thread_stack( &stack
, stack_reserve
, stack_commit
, &extra_stack
)))
223 virtual_free_teb( teb
);
227 client_id
.UniqueProcess
= ULongToHandle( GetCurrentProcessId() );
228 client_id
.UniqueThread
= ULongToHandle( tid
);
229 teb
->ClientId
= client_id
;
231 teb
->Tib
.StackBase
= stack
.StackBase
;
232 teb
->Tib
.StackLimit
= stack
.StackLimit
;
233 teb
->DeallocationStack
= stack
.DeallocationStack
;
235 thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
236 thread_data
->request_fd
= request_pipe
[1];
237 thread_data
->start_stack
= (char *)teb
->Tib
.StackBase
;
238 thread_data
->start
= start
;
239 thread_data
->param
= param
;
241 pthread_attr_init( &pthread_attr
);
242 pthread_attr_setstack( &pthread_attr
, teb
->DeallocationStack
,
243 (char *)teb
->Tib
.StackBase
+ extra_stack
- (char *)teb
->DeallocationStack
);
244 pthread_attr_setguardsize( &pthread_attr
, 0 );
245 pthread_attr_setscope( &pthread_attr
, PTHREAD_SCOPE_SYSTEM
); /* force creating a kernel thread */
246 InterlockedIncrement( &nb_threads
);
247 if (pthread_create( &pthread_id
, &pthread_attr
, (void * (*)(void *))start_thread
, teb
))
249 InterlockedDecrement( &nb_threads
);
250 virtual_free_teb( teb
);
251 status
= STATUS_NO_MEMORY
;
253 pthread_attr_destroy( &pthread_attr
);
256 pthread_sigmask( SIG_SETMASK
, &sigset
, NULL
);
260 close( request_pipe
[1] );
263 if (attr_list
) update_attr_list( attr_list
, &client_id
, teb
);
264 return STATUS_SUCCESS
;
268 /***********************************************************************
271 void abort_thread( int status
)
273 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
274 if (InterlockedDecrement( &nb_threads
) <= 0) abort_process( status
);
275 signal_exit_thread( status
, pthread_exit_wrapper
);
279 /***********************************************************************
282 void abort_process( int status
)
284 _exit( get_unix_exit_code( status
));
288 /***********************************************************************
291 static void exit_thread( int status
)
293 static void *prev_teb
;
296 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
298 if ((teb
= InterlockedExchangePointer( &prev_teb
, NtCurrentTeb() )))
300 struct ntdll_thread_data
*thread_data
= (struct ntdll_thread_data
*)&teb
->GdiTebBatch
;
302 if (thread_data
->pthread_id
)
304 pthread_join( thread_data
->pthread_id
, NULL
);
305 virtual_free_teb( teb
);
308 signal_exit_thread( status
, pthread_exit_wrapper
);
312 /***********************************************************************
315 void exit_process( int status
)
317 pthread_sigmask( SIG_BLOCK
, &server_block_set
, NULL
);
318 signal_exit_thread( get_unix_exit_code( status
), exit
);
322 /**********************************************************************
325 * Wait until the thread is no longer suspended.
327 void wait_suspend( CONTEXT
*context
)
329 int saved_errno
= errno
;
331 /* wait with 0 timeout, will only return once the thread is no longer suspended */
332 server_select( NULL
, 0, SELECT_INTERRUPTIBLE
, 0, context
, NULL
, NULL
);
337 /**********************************************************************
340 * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
342 NTSTATUS
send_debug_event( EXCEPTION_RECORD
*rec
, CONTEXT
*context
, BOOL first_chance
)
346 obj_handle_t handle
= 0;
347 client_ptr_t params
[EXCEPTION_MAXIMUM_PARAMETERS
];
348 CONTEXT exception_context
= *context
;
349 select_op_t select_op
;
352 if (!NtCurrentTeb()->Peb
->BeingDebugged
) return 0; /* no debugger present */
354 pthread_sigmask( SIG_BLOCK
, &server_block_set
, &old_set
);
356 for (i
= 0; i
< min( rec
->NumberParameters
, EXCEPTION_MAXIMUM_PARAMETERS
); i
++)
357 params
[i
] = rec
->ExceptionInformation
[i
];
359 SERVER_START_REQ( queue_exception_event
)
361 req
->first
= first_chance
;
362 req
->code
= rec
->ExceptionCode
;
363 req
->flags
= rec
->ExceptionFlags
;
364 req
->record
= wine_server_client_ptr( rec
->ExceptionRecord
);
365 req
->address
= wine_server_client_ptr( rec
->ExceptionAddress
);
366 req
->len
= i
* sizeof(params
[0]);
367 wine_server_add_data( req
, params
, req
->len
);
368 if (!(ret
= wine_server_call( req
))) handle
= reply
->handle
;
374 select_op
.wait
.op
= SELECT_WAIT
;
375 select_op
.wait
.handles
[0] = handle
;
376 server_select( &select_op
, offsetof( select_op_t
, wait
.handles
[1] ), SELECT_INTERRUPTIBLE
,
377 TIMEOUT_INFINITE
, &exception_context
, NULL
, NULL
);
379 SERVER_START_REQ( get_exception_status
)
381 req
->handle
= handle
;
382 ret
= wine_server_call( req
);
385 if (ret
>= 0) *context
= exception_context
;
388 pthread_sigmask( SIG_SETMASK
, &old_set
, NULL
);
393 /*******************************************************************
394 * NtRaiseException (NTDLL.@)
396 NTSTATUS WINAPI
NtRaiseException( EXCEPTION_RECORD
*rec
, CONTEXT
*context
, BOOL first_chance
)
398 NTSTATUS status
= send_debug_event( rec
, context
, first_chance
);
400 if (status
== DBG_CONTINUE
|| status
== DBG_EXCEPTION_HANDLED
)
401 NtSetContextThread( GetCurrentThread(), context
);
403 if (first_chance
) call_user_exception_dispatcher( rec
, context
, pKiUserExceptionDispatcher
);
405 if (rec
->ExceptionFlags
& EH_STACK_INVALID
)
406 ERR("Exception frame is not in stack limits => unable to dispatch exception.\n");
407 else if (rec
->ExceptionCode
== STATUS_NONCONTINUABLE_EXCEPTION
)
408 ERR("Process attempted to continue execution after noncontinuable exception.\n");
410 ERR("Unhandled exception code %x flags %x addr %p\n",
411 rec
->ExceptionCode
, rec
->ExceptionFlags
, rec
->ExceptionAddress
);
413 NtTerminateProcess( NtCurrentProcess(), rec
->ExceptionCode
);
414 return STATUS_SUCCESS
;
418 /***********************************************************************
419 * NtOpenThread (NTDLL.@)
421 NTSTATUS WINAPI
NtOpenThread( HANDLE
*handle
, ACCESS_MASK access
,
422 const OBJECT_ATTRIBUTES
*attr
, const CLIENT_ID
*id
)
426 SERVER_START_REQ( open_thread
)
428 req
->tid
= HandleToULong(id
->UniqueThread
);
429 req
->access
= access
;
430 req
->attributes
= attr
? attr
->Attributes
: 0;
431 ret
= wine_server_call( req
);
432 *handle
= wine_server_ptr_handle( reply
->handle
);
439 /******************************************************************************
440 * NtSuspendThread (NTDLL.@)
442 NTSTATUS WINAPI
NtSuspendThread( HANDLE handle
, ULONG
*count
)
446 SERVER_START_REQ( suspend_thread
)
448 req
->handle
= wine_server_obj_handle( handle
);
449 if (!(ret
= wine_server_call( req
)))
451 if (count
) *count
= reply
->count
;
459 /******************************************************************************
460 * NtResumeThread (NTDLL.@)
462 NTSTATUS WINAPI
NtResumeThread( HANDLE handle
, ULONG
*count
)
466 SERVER_START_REQ( resume_thread
)
468 req
->handle
= wine_server_obj_handle( handle
);
469 if (!(ret
= wine_server_call( req
)))
471 if (count
) *count
= reply
->count
;
479 /******************************************************************************
480 * NtAlertResumeThread (NTDLL.@)
482 NTSTATUS WINAPI
NtAlertResumeThread( HANDLE handle
, ULONG
*count
)
484 FIXME( "stub: should alert thread %p\n", handle
);
485 return NtResumeThread( handle
, count
);
489 /******************************************************************************
490 * NtAlertThread (NTDLL.@)
492 NTSTATUS WINAPI
NtAlertThread( HANDLE handle
)
494 FIXME( "stub: %p\n", handle
);
495 return STATUS_NOT_IMPLEMENTED
;
499 /******************************************************************************
500 * NtTerminateThread (NTDLL.@)
502 NTSTATUS WINAPI
NtTerminateThread( HANDLE handle
, LONG exit_code
)
505 BOOL self
= (handle
== GetCurrentThread());
507 if (!self
|| exit_code
)
509 SERVER_START_REQ( terminate_thread
)
511 req
->handle
= wine_server_obj_handle( handle
);
512 req
->exit_code
= exit_code
;
513 ret
= wine_server_call( req
);
514 self
= !ret
&& reply
->self
;
518 if (self
) exit_thread( exit_code
);
523 /******************************************************************************
524 * NtQueueApcThread (NTDLL.@)
526 NTSTATUS WINAPI
NtQueueApcThread( HANDLE handle
, PNTAPCFUNC func
, ULONG_PTR arg1
,
527 ULONG_PTR arg2
, ULONG_PTR arg3
)
531 SERVER_START_REQ( queue_apc
)
533 req
->handle
= wine_server_obj_handle( handle
);
536 req
->call
.type
= APC_USER
;
537 req
->call
.user
.user
.func
= wine_server_client_ptr( func
);
538 req
->call
.user
.user
.args
[0] = arg1
;
539 req
->call
.user
.user
.args
[1] = arg2
;
540 req
->call
.user
.user
.args
[2] = arg3
;
542 else req
->call
.type
= APC_NONE
; /* wake up only */
543 ret
= wine_server_call( req
);
550 /***********************************************************************
553 NTSTATUS
set_thread_context( HANDLE handle
, const context_t
*context
, BOOL
*self
)
557 SERVER_START_REQ( set_thread_context
)
559 req
->handle
= wine_server_obj_handle( handle
);
560 wine_server_add_data( req
, context
, sizeof(*context
) );
561 ret
= wine_server_call( req
);
570 /***********************************************************************
573 NTSTATUS
get_thread_context( HANDLE handle
, context_t
*context
, unsigned int flags
, BOOL
*self
)
577 SERVER_START_REQ( get_thread_context
)
579 req
->handle
= wine_server_obj_handle( handle
);
581 wine_server_set_reply( req
, context
, sizeof(*context
) );
582 ret
= wine_server_call( req
);
584 handle
= wine_server_ptr_handle( reply
->handle
);
588 if (ret
== STATUS_PENDING
)
590 LARGE_INTEGER timeout
;
591 timeout
.QuadPart
= -1000000;
592 if (NtWaitForSingleObject( handle
, FALSE
, &timeout
))
595 return STATUS_ACCESS_DENIED
;
597 SERVER_START_REQ( get_thread_context
)
599 req
->handle
= wine_server_obj_handle( handle
);
601 wine_server_set_reply( req
, context
, sizeof(*context
) );
602 ret
= wine_server_call( req
);
612 /***********************************************************************
613 * wow64_get_server_context_flags
615 static unsigned int wow64_get_server_context_flags( DWORD flags
)
617 unsigned int ret
= 0;
619 flags
&= ~WOW64_CONTEXT_i386
; /* get rid of CPU id */
620 if (flags
& WOW64_CONTEXT_CONTROL
) ret
|= SERVER_CTX_CONTROL
;
621 if (flags
& WOW64_CONTEXT_INTEGER
) ret
|= SERVER_CTX_INTEGER
;
622 if (flags
& WOW64_CONTEXT_SEGMENTS
) ret
|= SERVER_CTX_SEGMENTS
;
623 if (flags
& WOW64_CONTEXT_FLOATING_POINT
) ret
|= SERVER_CTX_FLOATING_POINT
;
624 if (flags
& WOW64_CONTEXT_DEBUG_REGISTERS
) ret
|= SERVER_CTX_DEBUG_REGISTERS
;
625 if (flags
& WOW64_CONTEXT_EXTENDED_REGISTERS
) ret
|= SERVER_CTX_EXTENDED_REGISTERS
;
629 /***********************************************************************
630 * wow64_context_from_server
632 static NTSTATUS
wow64_context_from_server( WOW64_CONTEXT
*to
, const context_t
*from
)
634 if (from
->cpu
!= CPU_x86
) return STATUS_INVALID_PARAMETER
;
636 to
->ContextFlags
= WOW64_CONTEXT_i386
;
637 if (from
->flags
& SERVER_CTX_CONTROL
)
639 to
->ContextFlags
|= WOW64_CONTEXT_CONTROL
;
640 to
->Ebp
= from
->ctl
.i386_regs
.ebp
;
641 to
->Esp
= from
->ctl
.i386_regs
.esp
;
642 to
->Eip
= from
->ctl
.i386_regs
.eip
;
643 to
->SegCs
= from
->ctl
.i386_regs
.cs
;
644 to
->SegSs
= from
->ctl
.i386_regs
.ss
;
645 to
->EFlags
= from
->ctl
.i386_regs
.eflags
;
647 if (from
->flags
& SERVER_CTX_INTEGER
)
649 to
->ContextFlags
|= WOW64_CONTEXT_INTEGER
;
650 to
->Eax
= from
->integer
.i386_regs
.eax
;
651 to
->Ebx
= from
->integer
.i386_regs
.ebx
;
652 to
->Ecx
= from
->integer
.i386_regs
.ecx
;
653 to
->Edx
= from
->integer
.i386_regs
.edx
;
654 to
->Esi
= from
->integer
.i386_regs
.esi
;
655 to
->Edi
= from
->integer
.i386_regs
.edi
;
657 if (from
->flags
& SERVER_CTX_SEGMENTS
)
659 to
->ContextFlags
|= WOW64_CONTEXT_SEGMENTS
;
660 to
->SegDs
= from
->seg
.i386_regs
.ds
;
661 to
->SegEs
= from
->seg
.i386_regs
.es
;
662 to
->SegFs
= from
->seg
.i386_regs
.fs
;
663 to
->SegGs
= from
->seg
.i386_regs
.gs
;
665 if (from
->flags
& SERVER_CTX_FLOATING_POINT
)
667 to
->ContextFlags
|= WOW64_CONTEXT_FLOATING_POINT
;
668 to
->FloatSave
.ControlWord
= from
->fp
.i386_regs
.ctrl
;
669 to
->FloatSave
.StatusWord
= from
->fp
.i386_regs
.status
;
670 to
->FloatSave
.TagWord
= from
->fp
.i386_regs
.tag
;
671 to
->FloatSave
.ErrorOffset
= from
->fp
.i386_regs
.err_off
;
672 to
->FloatSave
.ErrorSelector
= from
->fp
.i386_regs
.err_sel
;
673 to
->FloatSave
.DataOffset
= from
->fp
.i386_regs
.data_off
;
674 to
->FloatSave
.DataSelector
= from
->fp
.i386_regs
.data_sel
;
675 to
->FloatSave
.Cr0NpxState
= from
->fp
.i386_regs
.cr0npx
;
676 memcpy( to
->FloatSave
.RegisterArea
, from
->fp
.i386_regs
.regs
, sizeof(to
->FloatSave
.RegisterArea
) );
678 if (from
->flags
& SERVER_CTX_DEBUG_REGISTERS
)
680 to
->ContextFlags
|= WOW64_CONTEXT_DEBUG_REGISTERS
;
681 to
->Dr0
= from
->debug
.i386_regs
.dr0
;
682 to
->Dr1
= from
->debug
.i386_regs
.dr1
;
683 to
->Dr2
= from
->debug
.i386_regs
.dr2
;
684 to
->Dr3
= from
->debug
.i386_regs
.dr3
;
685 to
->Dr6
= from
->debug
.i386_regs
.dr6
;
686 to
->Dr7
= from
->debug
.i386_regs
.dr7
;
688 if (from
->flags
& SERVER_CTX_EXTENDED_REGISTERS
)
690 to
->ContextFlags
|= WOW64_CONTEXT_EXTENDED_REGISTERS
;
691 memcpy( to
->ExtendedRegisters
, from
->ext
.i386_regs
, sizeof(to
->ExtendedRegisters
) );
693 return STATUS_SUCCESS
;
696 /***********************************************************************
697 * wow64_context_to_server
699 static void wow64_context_to_server( context_t
*to
, const WOW64_CONTEXT
*from
)
701 DWORD flags
= from
->ContextFlags
& ~WOW64_CONTEXT_i386
; /* get rid of CPU id */
703 memset( to
, 0, sizeof(*to
) );
706 if (flags
& WOW64_CONTEXT_CONTROL
)
708 to
->flags
|= SERVER_CTX_CONTROL
;
709 to
->ctl
.i386_regs
.ebp
= from
->Ebp
;
710 to
->ctl
.i386_regs
.esp
= from
->Esp
;
711 to
->ctl
.i386_regs
.eip
= from
->Eip
;
712 to
->ctl
.i386_regs
.cs
= from
->SegCs
;
713 to
->ctl
.i386_regs
.ss
= from
->SegSs
;
714 to
->ctl
.i386_regs
.eflags
= from
->EFlags
;
716 if (flags
& WOW64_CONTEXT_INTEGER
)
718 to
->flags
|= SERVER_CTX_INTEGER
;
719 to
->integer
.i386_regs
.eax
= from
->Eax
;
720 to
->integer
.i386_regs
.ebx
= from
->Ebx
;
721 to
->integer
.i386_regs
.ecx
= from
->Ecx
;
722 to
->integer
.i386_regs
.edx
= from
->Edx
;
723 to
->integer
.i386_regs
.esi
= from
->Esi
;
724 to
->integer
.i386_regs
.edi
= from
->Edi
;
726 if (flags
& WOW64_CONTEXT_SEGMENTS
)
728 to
->flags
|= SERVER_CTX_SEGMENTS
;
729 to
->seg
.i386_regs
.ds
= from
->SegDs
;
730 to
->seg
.i386_regs
.es
= from
->SegEs
;
731 to
->seg
.i386_regs
.fs
= from
->SegFs
;
732 to
->seg
.i386_regs
.gs
= from
->SegGs
;
734 if (flags
& WOW64_CONTEXT_FLOATING_POINT
)
736 to
->flags
|= SERVER_CTX_FLOATING_POINT
;
737 to
->fp
.i386_regs
.ctrl
= from
->FloatSave
.ControlWord
;
738 to
->fp
.i386_regs
.status
= from
->FloatSave
.StatusWord
;
739 to
->fp
.i386_regs
.tag
= from
->FloatSave
.TagWord
;
740 to
->fp
.i386_regs
.err_off
= from
->FloatSave
.ErrorOffset
;
741 to
->fp
.i386_regs
.err_sel
= from
->FloatSave
.ErrorSelector
;
742 to
->fp
.i386_regs
.data_off
= from
->FloatSave
.DataOffset
;
743 to
->fp
.i386_regs
.data_sel
= from
->FloatSave
.DataSelector
;
744 to
->fp
.i386_regs
.cr0npx
= from
->FloatSave
.Cr0NpxState
;
745 memcpy( to
->fp
.i386_regs
.regs
, from
->FloatSave
.RegisterArea
, sizeof(to
->fp
.i386_regs
.regs
) );
747 if (flags
& WOW64_CONTEXT_DEBUG_REGISTERS
)
749 to
->flags
|= SERVER_CTX_DEBUG_REGISTERS
;
750 to
->debug
.i386_regs
.dr0
= from
->Dr0
;
751 to
->debug
.i386_regs
.dr1
= from
->Dr1
;
752 to
->debug
.i386_regs
.dr2
= from
->Dr2
;
753 to
->debug
.i386_regs
.dr3
= from
->Dr3
;
754 to
->debug
.i386_regs
.dr6
= from
->Dr6
;
755 to
->debug
.i386_regs
.dr7
= from
->Dr7
;
757 if (flags
& WOW64_CONTEXT_EXTENDED_REGISTERS
)
759 to
->flags
|= SERVER_CTX_EXTENDED_REGISTERS
;
760 memcpy( to
->ext
.i386_regs
, from
->ExtendedRegisters
, sizeof(to
->ext
.i386_regs
) );
764 #endif /* __x86_64__ */
767 BOOL
get_thread_times(int unix_pid
, int unix_tid
, LARGE_INTEGER
*kernel_time
, LARGE_INTEGER
*user_time
)
769 unsigned long clocks_per_sec
= sysconf( _SC_CLK_TCK
);
770 unsigned long usr
, sys
;
777 sprintf( buf
, "/proc/%u/stat", unix_pid
);
779 sprintf( buf
, "/proc/%u/task/%u/stat", unix_pid
, unix_tid
);
780 if (!(f
= fopen( buf
, "r" )))
782 WARN("Failed to open %s: %s\n", buf
, strerror(errno
));
786 pos
= fgets( buf
, sizeof(buf
), f
);
789 /* the process name is printed unescaped, so we have to skip to the last ')'
790 * to avoid misinterpreting the string */
791 if (pos
) pos
= strrchr( pos
, ')' );
792 if (pos
) pos
= strchr( pos
+ 1, ' ' );
795 /* skip over the following fields: state, ppid, pgid, sid, tty_nr, tty_pgrp,
796 * task->flags, min_flt, cmin_flt, maj_flt, cmaj_flt */
797 for (i
= 0; i
< 11 && pos
; i
++)
799 pos
= strchr( pos
+ 1, ' ' );
803 /* the next two values are user and system time */
804 if (pos
&& (sscanf( pos
, "%lu %lu", &usr
, &sys
) == 2))
806 kernel_time
->QuadPart
= (ULONGLONG
)sys
* 10000000 / clocks_per_sec
;
807 user_time
->QuadPart
= (ULONGLONG
)usr
* 10000000 / clocks_per_sec
;
811 ERR("Failed to parse %s\n", debugstr_a(buf
));
815 BOOL
get_thread_times(int unix_pid
, int unix_tid
, LARGE_INTEGER
*kernel_time
, LARGE_INTEGER
*user_time
)
818 if (!once
++) FIXME("not implemented on this platform\n");
823 /******************************************************************************
824 * NtQueryInformationThread (NTDLL.@)
826 NTSTATUS WINAPI
NtQueryInformationThread( HANDLE handle
, THREADINFOCLASS
class,
827 void *data
, ULONG length
, ULONG
*ret_len
)
831 TRACE("(%p,%d,%p,%x,%p)\n", handle
, class, data
, length
, ret_len
);
835 case ThreadBasicInformation
:
837 THREAD_BASIC_INFORMATION info
;
838 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
840 SERVER_START_REQ( get_thread_info
)
842 req
->handle
= wine_server_obj_handle( handle
);
843 if (!(status
= wine_server_call( req
)))
845 info
.ExitStatus
= reply
->exit_code
;
846 info
.TebBaseAddress
= wine_server_get_ptr( reply
->teb
);
847 info
.ClientId
.UniqueProcess
= ULongToHandle(reply
->pid
);
848 info
.ClientId
.UniqueThread
= ULongToHandle(reply
->tid
);
849 info
.AffinityMask
= reply
->affinity
& affinity_mask
;
850 info
.Priority
= reply
->priority
;
851 info
.BasePriority
= reply
->priority
; /* FIXME */
855 if (status
== STATUS_SUCCESS
)
857 if (data
) memcpy( data
, &info
, min( length
, sizeof(info
) ));
858 if (ret_len
) *ret_len
= min( length
, sizeof(info
) );
863 case ThreadAffinityMask
:
865 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
866 ULONG_PTR affinity
= 0;
868 SERVER_START_REQ( get_thread_info
)
870 req
->handle
= wine_server_obj_handle( handle
);
871 req
->access
= THREAD_QUERY_INFORMATION
;
872 if (!(status
= wine_server_call( req
))) affinity
= reply
->affinity
& affinity_mask
;
875 if (status
== STATUS_SUCCESS
)
877 if (data
) memcpy( data
, &affinity
, min( length
, sizeof(affinity
) ));
878 if (ret_len
) *ret_len
= min( length
, sizeof(affinity
) );
885 KERNEL_USER_TIMES kusrt
;
886 int unix_pid
, unix_tid
;
888 SERVER_START_REQ( get_thread_times
)
890 req
->handle
= wine_server_obj_handle( handle
);
891 status
= wine_server_call( req
);
892 if (status
== STATUS_SUCCESS
)
894 kusrt
.CreateTime
.QuadPart
= reply
->creation_time
;
895 kusrt
.ExitTime
.QuadPart
= reply
->exit_time
;
896 unix_pid
= reply
->unix_pid
;
897 unix_tid
= reply
->unix_tid
;
901 if (status
== STATUS_SUCCESS
)
905 kusrt
.KernelTime
.QuadPart
= kusrt
.UserTime
.QuadPart
= 0;
906 if (unix_pid
!= -1 && unix_tid
!= -1)
907 ret
= get_thread_times( unix_pid
, unix_tid
, &kusrt
.KernelTime
, &kusrt
.UserTime
);
908 if (!ret
&& handle
== GetCurrentThread())
910 /* fall back to process times */
912 long clocks_per_sec
= sysconf(_SC_CLK_TCK
);
915 kusrt
.KernelTime
.QuadPart
= (ULONGLONG
)time_buf
.tms_stime
* 10000000 / clocks_per_sec
;
916 kusrt
.UserTime
.QuadPart
= (ULONGLONG
)time_buf
.tms_utime
* 10000000 / clocks_per_sec
;
918 if (data
) memcpy( data
, &kusrt
, min( length
, sizeof(kusrt
) ));
919 if (ret_len
) *ret_len
= min( length
, sizeof(kusrt
) );
924 case ThreadDescriptorTableEntry
:
925 return get_thread_ldt_entry( handle
, data
, length
, ret_len
);
927 case ThreadAmILastThread
:
929 if (length
!= sizeof(ULONG
)) return STATUS_INFO_LENGTH_MISMATCH
;
930 SERVER_START_REQ( get_thread_info
)
932 req
->handle
= wine_server_obj_handle( handle
);
933 status
= wine_server_call( req
);
934 if (status
== STATUS_SUCCESS
)
936 ULONG last
= reply
->last
;
937 if (data
) memcpy( data
, &last
, sizeof(last
) );
938 if (ret_len
) *ret_len
= sizeof(last
);
945 case ThreadQuerySetWin32StartAddress
:
947 SERVER_START_REQ( get_thread_info
)
949 req
->handle
= wine_server_obj_handle( handle
);
950 req
->access
= THREAD_QUERY_INFORMATION
;
951 status
= wine_server_call( req
);
952 if (status
== STATUS_SUCCESS
)
954 PRTL_THREAD_START_ROUTINE entry
= wine_server_get_ptr( reply
->entry_point
);
955 if (data
) memcpy( data
, &entry
, min( length
, sizeof(entry
) ) );
956 if (ret_len
) *ret_len
= min( length
, sizeof(entry
) );
963 case ThreadGroupInformation
:
965 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
966 GROUP_AFFINITY affinity
;
968 memset( &affinity
, 0, sizeof(affinity
) );
969 affinity
.Group
= 0; /* Wine only supports max 64 processors */
971 SERVER_START_REQ( get_thread_info
)
973 req
->handle
= wine_server_obj_handle( handle
);
974 if (!(status
= wine_server_call( req
))) affinity
.Mask
= reply
->affinity
& affinity_mask
;
977 if (status
== STATUS_SUCCESS
)
979 if (data
) memcpy( data
, &affinity
, min( length
, sizeof(affinity
) ));
980 if (ret_len
) *ret_len
= min( length
, sizeof(affinity
) );
985 case ThreadIsIoPending
:
986 FIXME( "ThreadIsIoPending info class not supported yet\n" );
987 if (length
!= sizeof(BOOL
)) return STATUS_INFO_LENGTH_MISMATCH
;
988 if (!data
) return STATUS_ACCESS_DENIED
;
989 *(BOOL
*)data
= FALSE
;
990 if (ret_len
) *ret_len
= sizeof(BOOL
);
991 return STATUS_SUCCESS
;
993 case ThreadSuspendCount
:
994 if (length
!= sizeof(ULONG
)) return STATUS_INFO_LENGTH_MISMATCH
;
995 if (!data
) return STATUS_ACCESS_VIOLATION
;
997 SERVER_START_REQ( get_thread_info
)
999 req
->handle
= wine_server_obj_handle( handle
);
1000 if (!(status
= wine_server_call( req
))) *(ULONG
*)data
= reply
->suspend_count
;
1005 case ThreadDescription
:
1007 THREAD_DESCRIPTION_INFORMATION
*info
= data
;
1008 data_size_t len
, desc_len
= 0;
1011 len
= length
>= sizeof(*info
) ? length
- sizeof(*info
) : 0;
1012 ptr
= info
? (WCHAR
*)(info
+ 1) : NULL
;
1014 SERVER_START_REQ( get_thread_info
)
1016 req
->handle
= wine_server_obj_handle( handle
);
1017 if (ptr
) wine_server_set_reply( req
, ptr
, len
);
1018 status
= wine_server_call( req
);
1019 desc_len
= reply
->desc_len
;
1023 if (!info
) status
= STATUS_BUFFER_TOO_SMALL
;
1024 else if (status
== STATUS_SUCCESS
)
1026 info
->Description
.Length
= info
->Description
.MaximumLength
= desc_len
;
1027 info
->Description
.Buffer
= ptr
;
1030 if (ret_len
&& (status
== STATUS_SUCCESS
|| status
== STATUS_BUFFER_TOO_SMALL
))
1031 *ret_len
= sizeof(*info
) + desc_len
;
1035 case ThreadWow64Context
:
1039 WOW64_CONTEXT
*context
= data
;
1040 context_t server_context
;
1041 unsigned int server_flags
;
1043 if (length
!= sizeof(*context
)) return STATUS_INFO_LENGTH_MISMATCH
;
1044 server_flags
= wow64_get_server_context_flags( context
->ContextFlags
);
1045 if ((status
= get_thread_context( handle
, &server_context
, server_flags
, &self
))) return status
;
1046 if (self
) return STATUS_INVALID_PARAMETER
;
1047 status
= wow64_context_from_server( context
, &server_context
);
1048 if (ret_len
&& !status
) *ret_len
= sizeof(*context
);
1051 return STATUS_INVALID_INFO_CLASS
;
1055 case ThreadHideFromDebugger
:
1056 if (length
!= sizeof(BOOLEAN
)) return STATUS_INFO_LENGTH_MISMATCH
;
1057 if (!data
) return STATUS_ACCESS_VIOLATION
;
1058 SERVER_START_REQ( get_thread_info
)
1060 req
->handle
= wine_server_obj_handle( handle
);
1061 req
->access
= THREAD_QUERY_INFORMATION
;
1062 if ((status
= wine_server_call( req
))) return status
;
1063 *(BOOLEAN
*)data
= reply
->dbg_hidden
;
1066 if (ret_len
) *ret_len
= sizeof(BOOLEAN
);
1067 return STATUS_SUCCESS
;
1069 case ThreadPriority
:
1070 case ThreadBasePriority
:
1071 case ThreadImpersonationToken
:
1072 case ThreadEnableAlignmentFaultFixup
:
1073 case ThreadEventPair_Reusable
:
1074 case ThreadZeroTlsCell
:
1075 case ThreadPerformanceCount
:
1076 case ThreadIdealProcessor
:
1077 case ThreadPriorityBoost
:
1078 case ThreadSetTlsArrayAddress
:
1080 FIXME( "info class %d not supported yet\n", class );
1081 return STATUS_NOT_IMPLEMENTED
;
1086 /******************************************************************************
1087 * NtSetInformationThread (NTDLL.@)
1089 NTSTATUS WINAPI
NtSetInformationThread( HANDLE handle
, THREADINFOCLASS
class,
1090 const void *data
, ULONG length
)
1094 TRACE("(%p,%d,%p,%x)\n", handle
, class, data
, length
);
1098 case ThreadZeroTlsCell
:
1099 if (handle
== GetCurrentThread())
1101 if (length
!= sizeof(DWORD
)) return STATUS_INVALID_PARAMETER
;
1102 return virtual_clear_tls_index( *(const ULONG
*)data
);
1104 FIXME( "ZeroTlsCell not supported on other threads\n" );
1105 return STATUS_NOT_IMPLEMENTED
;
1107 case ThreadImpersonationToken
:
1109 const HANDLE
*token
= data
;
1111 if (length
!= sizeof(HANDLE
)) return STATUS_INVALID_PARAMETER
;
1112 TRACE("Setting ThreadImpersonationToken handle to %p\n", *token
);
1113 SERVER_START_REQ( set_thread_info
)
1115 req
->handle
= wine_server_obj_handle( handle
);
1116 req
->token
= wine_server_obj_handle( *token
);
1117 req
->mask
= SET_THREAD_INFO_TOKEN
;
1118 status
= wine_server_call( req
);
1124 case ThreadBasePriority
:
1126 const DWORD
*pprio
= data
;
1127 if (length
!= sizeof(DWORD
)) return STATUS_INVALID_PARAMETER
;
1128 SERVER_START_REQ( set_thread_info
)
1130 req
->handle
= wine_server_obj_handle( handle
);
1131 req
->priority
= *pprio
;
1132 req
->mask
= SET_THREAD_INFO_PRIORITY
;
1133 status
= wine_server_call( req
);
1139 case ThreadAffinityMask
:
1141 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
1144 if (length
!= sizeof(ULONG_PTR
)) return STATUS_INVALID_PARAMETER
;
1145 req_aff
= *(const ULONG_PTR
*)data
& affinity_mask
;
1146 if (!req_aff
) return STATUS_INVALID_PARAMETER
;
1148 SERVER_START_REQ( set_thread_info
)
1150 req
->handle
= wine_server_obj_handle( handle
);
1151 req
->affinity
= req_aff
;
1152 req
->mask
= SET_THREAD_INFO_AFFINITY
;
1153 status
= wine_server_call( req
);
1159 case ThreadHideFromDebugger
:
1160 if (length
) return STATUS_INFO_LENGTH_MISMATCH
;
1161 SERVER_START_REQ( set_thread_info
)
1163 req
->handle
= wine_server_obj_handle( handle
);
1164 req
->mask
= SET_THREAD_INFO_DBG_HIDDEN
;
1165 status
= wine_server_call( req
);
1170 case ThreadQuerySetWin32StartAddress
:
1172 const PRTL_THREAD_START_ROUTINE
*entry
= data
;
1173 if (length
!= sizeof(PRTL_THREAD_START_ROUTINE
)) return STATUS_INVALID_PARAMETER
;
1174 SERVER_START_REQ( set_thread_info
)
1176 req
->handle
= wine_server_obj_handle( handle
);
1177 req
->mask
= SET_THREAD_INFO_ENTRYPOINT
;
1178 req
->entry_point
= wine_server_client_ptr( *entry
);
1179 status
= wine_server_call( req
);
1185 case ThreadGroupInformation
:
1187 const ULONG_PTR affinity_mask
= get_system_affinity_mask();
1188 const GROUP_AFFINITY
*req_aff
;
1190 if (length
!= sizeof(*req_aff
)) return STATUS_INVALID_PARAMETER
;
1191 if (!data
) return STATUS_ACCESS_VIOLATION
;
1194 /* On Windows the request fails if the reserved fields are set */
1195 if (req_aff
->Reserved
[0] || req_aff
->Reserved
[1] || req_aff
->Reserved
[2])
1196 return STATUS_INVALID_PARAMETER
;
1198 /* Wine only supports max 64 processors */
1199 if (req_aff
->Group
) return STATUS_INVALID_PARAMETER
;
1200 if (req_aff
->Mask
& ~affinity_mask
) return STATUS_INVALID_PARAMETER
;
1201 if (!req_aff
->Mask
) return STATUS_INVALID_PARAMETER
;
1202 SERVER_START_REQ( set_thread_info
)
1204 req
->handle
= wine_server_obj_handle( handle
);
1205 req
->affinity
= req_aff
->Mask
;
1206 req
->mask
= SET_THREAD_INFO_AFFINITY
;
1207 status
= wine_server_call( req
);
1213 case ThreadDescription
:
1215 const THREAD_DESCRIPTION_INFORMATION
*info
= data
;
1217 if (length
!= sizeof(*info
)) return STATUS_INFO_LENGTH_MISMATCH
;
1218 if (!info
) return STATUS_ACCESS_VIOLATION
;
1219 if (info
->Description
.Length
!= info
->Description
.MaximumLength
) return STATUS_INVALID_PARAMETER
;
1220 if (info
->Description
.Length
&& !info
->Description
.Buffer
) return STATUS_ACCESS_VIOLATION
;
1222 SERVER_START_REQ( set_thread_info
)
1224 req
->handle
= wine_server_obj_handle( handle
);
1225 req
->mask
= SET_THREAD_INFO_DESCRIPTION
;
1226 wine_server_add_data( req
, info
->Description
.Buffer
, info
->Description
.Length
);
1227 status
= wine_server_call( req
);
1233 case ThreadWow64Context
:
1237 const WOW64_CONTEXT
*context
= data
;
1238 context_t server_context
;
1240 if (length
!= sizeof(*context
)) return STATUS_INFO_LENGTH_MISMATCH
;
1241 wow64_context_to_server( &server_context
, context
);
1242 return set_thread_context( handle
, &server_context
, &self
);
1244 return STATUS_INVALID_INFO_CLASS
;
1248 case ThreadBasicInformation
:
1250 case ThreadPriority
:
1251 case ThreadDescriptorTableEntry
:
1252 case ThreadEnableAlignmentFaultFixup
:
1253 case ThreadEventPair_Reusable
:
1254 case ThreadPerformanceCount
:
1255 case ThreadAmILastThread
:
1256 case ThreadIdealProcessor
:
1257 case ThreadPriorityBoost
:
1258 case ThreadSetTlsArrayAddress
:
1259 case ThreadIsIoPending
:
1261 FIXME( "info class %d not supported yet\n", class );
1262 return STATUS_NOT_IMPLEMENTED
;
1267 /******************************************************************************
1268 * NtGetCurrentProcessorNumber (NTDLL.@)
1270 ULONG WINAPI
NtGetCurrentProcessorNumber(void)
1274 #if defined(__linux__) && defined(__NR_getcpu)
1275 int res
= syscall(__NR_getcpu
, &processor
, NULL
, NULL
);
1276 if (res
!= -1) return processor
;
1279 if (NtCurrentTeb()->Peb
->NumberOfProcessors
> 1)
1281 ULONG_PTR thread_mask
, processor_mask
;
1283 if (!NtQueryInformationThread( GetCurrentThread(), ThreadAffinityMask
,
1284 &thread_mask
, sizeof(thread_mask
), NULL
))
1286 for (processor
= 0; processor
< NtCurrentTeb()->Peb
->NumberOfProcessors
; processor
++)
1288 processor_mask
= (1 << processor
);
1289 if (thread_mask
& processor_mask
)
1291 if (thread_mask
!= processor_mask
)
1292 FIXME( "need multicore support (%d processors)\n",
1293 NtCurrentTeb()->Peb
->NumberOfProcessors
);
1299 /* fallback to the first processor */