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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
24 #include <sys/types.h>
25 #ifdef HAVE_SYS_MMAN_H
28 #ifdef HAVE_SYS_TIMES_H
29 #include <sys/times.h>
32 #define NONAMELESSUNION
34 #define WIN32_NO_STATUS
37 #include "wine/library.h"
38 #include "wine/server.h"
39 #include "wine/pthread.h"
40 #include "wine/debug.h"
41 #include "ntdll_misc.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(thread);
45 /* info passed to a starting thread */
48 struct wine_pthread_thread_info pthread_info;
49 PRTL_THREAD_START_ROUTINE entry_point;
54 static PEB_LDR_DATA ldr;
55 static RTL_USER_PROCESS_PARAMETERS params; /* default parameters if no parent */
56 static WCHAR current_dir[MAX_NT_PATH_LENGTH];
57 static RTL_BITMAP tls_bitmap;
58 static RTL_BITMAP tls_expansion_bitmap;
59 static LIST_ENTRY tls_links;
60 static size_t sigstack_total_size;
62 struct wine_pthread_functions pthread_functions = { NULL };
64 /***********************************************************************
67 static inline NTSTATUS init_teb( TEB *teb )
69 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
71 teb->Tib.ExceptionList = (void *)~0UL;
72 teb->Tib.StackBase = (void *)~0UL;
73 teb->Tib.Self = &teb->Tib;
75 teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
76 teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
78 if (!(thread_data->teb_sel = wine_ldt_alloc_fs())) return STATUS_TOO_MANY_THREADS;
79 thread_data->request_fd = -1;
80 thread_data->reply_fd = -1;
81 thread_data->wait_fd[0] = -1;
82 thread_data->wait_fd[1] = -1;
84 return STATUS_SUCCESS;
88 /***********************************************************************
91 static inline void free_teb( TEB *teb )
95 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
97 NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE );
98 wine_ldt_free_fs( thread_data->teb_sel );
99 munmap( teb, sigstack_total_size );
103 /***********************************************************************
106 * Setup the initial thread.
108 * NOTES: The first allocated TEB on NT is at 0x7ffde000.
110 void thread_init(void)
115 struct ntdll_thread_data *thread_data;
116 struct wine_pthread_thread_info thread_info;
117 static struct debug_info debug_info; /* debug info for initial thread */
119 peb.NumberOfProcessors = 1;
120 peb.ProcessParameters = ¶ms;
121 peb.TlsBitmap = &tls_bitmap;
122 peb.TlsExpansionBitmap = &tls_expansion_bitmap;
124 params.CurrentDirectory.DosPath.Buffer = current_dir;
125 params.CurrentDirectory.DosPath.MaximumLength = sizeof(current_dir);
126 params.wShowWindow = 1; /* SW_SHOWNORMAL */
127 RtlInitializeBitMap( &tls_bitmap, peb.TlsBitmapBits, sizeof(peb.TlsBitmapBits) * 8 );
128 RtlInitializeBitMap( &tls_expansion_bitmap, peb.TlsExpansionBitmapBits,
129 sizeof(peb.TlsExpansionBitmapBits) * 8 );
130 InitializeListHead( &ldr.InLoadOrderModuleList );
131 InitializeListHead( &ldr.InMemoryOrderModuleList );
132 InitializeListHead( &ldr.InInitializationOrderModuleList );
133 InitializeListHead( &tls_links );
135 sigstack_total_size = get_signal_stack_total_size();
136 thread_info.teb_size = sigstack_total_size;
137 VIRTUAL_alloc_teb( &addr, thread_info.teb_size, TRUE );
140 thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
141 thread_data->debug_info = &debug_info;
142 InsertHeadList( &tls_links, &teb->TlsLinks );
144 thread_info.stack_base = NULL;
145 thread_info.stack_size = 0;
146 thread_info.teb_base = teb;
147 thread_info.teb_sel = thread_data->teb_sel;
148 wine_pthread_get_functions( &pthread_functions, sizeof(pthread_functions) );
149 pthread_functions.init_current_teb( &thread_info );
150 pthread_functions.init_thread( &thread_info );
152 debug_info.str_pos = debug_info.strings;
153 debug_info.out_pos = debug_info.output;
156 /* setup the server connection */
157 server_init_process();
158 info_size = server_init_thread( thread_info.pid, thread_info.tid, NULL );
160 /* create the process heap */
161 if (!(peb.ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL )))
163 MESSAGE( "wine: failed to create the process heap\n" );
167 /* allocate user parameters */
170 RTL_USER_PROCESS_PARAMETERS *params = NULL;
172 if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)¶ms, 0, &info_size,
173 MEM_COMMIT, PAGE_READWRITE ) == STATUS_SUCCESS)
175 params->AllocationSize = info_size;
176 NtCurrentTeb()->Peb->ProcessParameters = params;
181 /* This is wine specific: we have no parent (we're started from unix)
182 * so, create a simple console with bare handles to unix stdio
184 wine_server_fd_to_handle( 0, GENERIC_READ|SYNCHRONIZE, TRUE, ¶ms.hStdInput );
185 wine_server_fd_to_handle( 1, GENERIC_WRITE|SYNCHRONIZE, TRUE, ¶ms.hStdOutput );
186 wine_server_fd_to_handle( 2, GENERIC_WRITE|SYNCHRONIZE, TRUE, ¶ms.hStdError );
191 /***********************************************************************
194 * Startup routine for a newly created thread.
196 static void start_thread( struct wine_pthread_thread_info *info )
198 TEB *teb = info->teb_base;
199 struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
200 struct startup_info *startup_info = (struct startup_info *)info;
201 PRTL_THREAD_START_ROUTINE func = startup_info->entry_point;
202 void *arg = startup_info->entry_arg;
203 struct debug_info debug_info;
206 debug_info.str_pos = debug_info.strings;
207 debug_info.out_pos = debug_info.output;
208 thread_data->debug_info = &debug_info;
210 pthread_functions.init_current_teb( info );
212 server_init_thread( info->pid, info->tid, func );
213 pthread_functions.init_thread( info );
215 /* allocate a memory view for the stack */
216 size = info->stack_size;
217 teb->DeallocationStack = info->stack_base;
218 NtAllocateVirtualMemory( NtCurrentProcess(), &teb->DeallocationStack, 0,
219 &size, MEM_SYSTEM, PAGE_READWRITE );
220 /* limit is lower than base since the stack grows down */
221 teb->Tib.StackBase = (char *)info->stack_base + info->stack_size;
222 teb->Tib.StackLimit = info->stack_base;
224 /* setup the guard page */
226 NtProtectVirtualMemory( NtCurrentProcess(), &teb->DeallocationStack, &size,
227 PAGE_READWRITE | PAGE_GUARD, NULL );
228 RtlFreeHeap( GetProcessHeap(), 0, info );
231 InsertHeadList( &tls_links, &teb->TlsLinks );
238 /***********************************************************************
239 * RtlCreateUserThread (NTDLL.@)
241 NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *descr,
242 BOOLEAN suspended, PVOID stack_addr,
243 SIZE_T stack_reserve, SIZE_T stack_commit,
244 PRTL_THREAD_START_ROUTINE start, void *param,
245 HANDLE *handle_ptr, CLIENT_ID *id )
247 struct ntdll_thread_data *thread_data = NULL;
248 struct startup_info *info = NULL;
256 if( ! is_current_process( process ) )
258 ERR("Unsupported on other process\n");
259 return STATUS_ACCESS_DENIED;
262 if (pipe( request_pipe ) == -1) return STATUS_TOO_MANY_OPENED_FILES;
263 fcntl( request_pipe[1], F_SETFD, 1 ); /* set close on exec flag */
264 wine_server_send_fd( request_pipe[0] );
266 SERVER_START_REQ( new_thread )
268 req->suspend = suspended;
269 req->inherit = 0; /* FIXME */
270 req->request_fd = request_pipe[0];
271 if (!(status = wine_server_call( req )))
273 handle = reply->handle;
276 close( request_pipe[0] );
280 if (status) goto error;
282 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*info) )))
284 status = STATUS_NO_MEMORY;
288 info->pthread_info.teb_size = sigstack_total_size;
289 if ((status = VIRTUAL_alloc_teb( &addr, info->pthread_info.teb_size, FALSE ))) goto error;
291 if ((status = init_teb( teb ))) goto error;
293 teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId();
294 teb->ClientId.UniqueThread = (HANDLE)tid;
296 thread_data = (struct ntdll_thread_data *)teb->SystemReserved2;
297 thread_data->request_fd = request_pipe[1];
299 info->pthread_info.teb_base = teb;
300 info->pthread_info.teb_sel = thread_data->teb_sel;
302 if (!stack_reserve || !stack_commit)
304 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
305 if (!stack_reserve) stack_reserve = nt->OptionalHeader.SizeOfStackReserve;
306 if (!stack_commit) stack_commit = nt->OptionalHeader.SizeOfStackCommit;
308 if (stack_reserve < stack_commit) stack_reserve = stack_commit;
309 stack_reserve = (stack_reserve + 0xffff) & ~0xffff; /* round to 64K boundary */
310 if (stack_reserve < 1024 * 1024) stack_reserve = 1024 * 1024; /* Xlib needs a large stack */
312 info->pthread_info.stack_base = NULL;
313 info->pthread_info.stack_size = stack_reserve;
314 info->pthread_info.entry = start_thread;
315 info->entry_point = start;
316 info->entry_arg = param;
318 if (pthread_functions.create_thread( &info->pthread_info ) == -1)
320 status = STATUS_NO_MEMORY;
324 if (id) id->UniqueThread = (HANDLE)tid;
325 if (handle_ptr) *handle_ptr = handle;
326 else NtClose( handle );
328 return STATUS_SUCCESS;
331 if (thread_data) wine_ldt_free_fs( thread_data->teb_sel );
335 NtFreeVirtualMemory( NtCurrentProcess(), &addr, &size, MEM_RELEASE );
337 if (info) RtlFreeHeap( GetProcessHeap(), 0, info );
338 if (handle) NtClose( handle );
339 close( request_pipe[1] );
344 /***********************************************************************
345 * RtlExitUserThread (NTDLL.@)
347 void WINAPI RtlExitUserThread( ULONG status )
350 server_exit_thread( status );
354 /***********************************************************************
355 * NtOpenThread (NTDLL.@)
356 * ZwOpenThread (NTDLL.@)
358 NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
359 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
363 SERVER_START_REQ( open_thread )
365 req->tid = (thread_id_t)id->UniqueThread;
366 req->access = access;
367 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
368 ret = wine_server_call( req );
369 *handle = reply->handle;
376 /******************************************************************************
377 * NtSuspendThread (NTDLL.@)
378 * ZwSuspendThread (NTDLL.@)
380 NTSTATUS WINAPI NtSuspendThread( HANDLE handle, PULONG count )
384 SERVER_START_REQ( suspend_thread )
386 req->handle = handle;
387 if (!(ret = wine_server_call( req ))) *count = reply->count;
394 /******************************************************************************
395 * NtResumeThread (NTDLL.@)
396 * ZwResumeThread (NTDLL.@)
398 NTSTATUS WINAPI NtResumeThread( HANDLE handle, PULONG count )
402 SERVER_START_REQ( resume_thread )
404 req->handle = handle;
405 if (!(ret = wine_server_call( req ))) *count = reply->count;
412 /******************************************************************************
413 * NtAlertResumeThread (NTDLL.@)
414 * ZwAlertResumeThread (NTDLL.@)
416 NTSTATUS WINAPI NtAlertResumeThread( HANDLE handle, PULONG count )
418 FIXME( "stub: should alert thread %p\n", handle );
419 return NtResumeThread( handle, count );
423 /******************************************************************************
424 * NtAlertThread (NTDLL.@)
425 * ZwAlertThread (NTDLL.@)
427 NTSTATUS WINAPI NtAlertThread( HANDLE handle )
429 FIXME( "stub: %p\n", handle );
430 return STATUS_NOT_IMPLEMENTED;
434 /******************************************************************************
435 * NtTerminateThread (NTDLL.@)
436 * ZwTerminateThread (NTDLL.@)
438 NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
443 SERVER_START_REQ( terminate_thread )
445 req->handle = handle;
446 req->exit_code = exit_code;
447 ret = wine_server_call( req );
448 self = !ret && reply->self;
455 if (last) exit( exit_code );
456 else server_abort_thread( exit_code );
462 /******************************************************************************
463 * NtQueueApcThread (NTDLL.@)
465 NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
466 ULONG_PTR arg2, ULONG_PTR arg3 )
469 SERVER_START_REQ( queue_apc )
471 req->handle = handle;
474 req->arg1 = (void *)arg1;
475 req->arg2 = (void *)arg2;
476 req->arg3 = (void *)arg3;
477 ret = wine_server_call( req );
484 /***********************************************************************
485 * NtSetContextThread (NTDLL.@)
486 * ZwSetContextThread (NTDLL.@)
488 NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
493 SERVER_START_REQ( set_thread_context )
495 req->handle = handle;
496 req->flags = context->ContextFlags;
498 wine_server_add_data( req, context, sizeof(*context) );
499 ret = wine_server_call( req );
503 if (ret == STATUS_PENDING)
505 if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
507 for (i = 0; i < 100; i++)
509 SERVER_START_REQ( set_thread_context )
511 req->handle = handle;
512 req->flags = context->ContextFlags;
514 wine_server_add_data( req, context, sizeof(*context) );
515 ret = wine_server_call( req );
518 if (ret != STATUS_PENDING) break;
521 NtResumeThread( handle, &dummy );
525 if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
530 /* copy a context structure according to the flags */
531 static inline void copy_context( CONTEXT *to, const CONTEXT *from, DWORD flags )
534 flags &= ~CONTEXT_i386; /* get rid of CPU id */
535 if (flags & CONTEXT_INTEGER)
544 if (flags & CONTEXT_CONTROL)
549 to->SegCs = from->SegCs;
550 to->SegSs = from->SegSs;
551 to->EFlags = from->EFlags;
553 if (flags & CONTEXT_SEGMENTS)
555 to->SegDs = from->SegDs;
556 to->SegEs = from->SegEs;
557 to->SegFs = from->SegFs;
558 to->SegGs = from->SegGs;
560 if (flags & CONTEXT_DEBUG_REGISTERS)
569 if (flags & CONTEXT_FLOATING_POINT)
571 to->FloatSave = from->FloatSave;
573 #elif defined(__x86_64__)
574 flags &= ~CONTEXT_AMD64; /* get rid of CPU id */
575 if (flags & CONTEXT_CONTROL)
580 to->SegCs = from->SegCs;
581 to->SegSs = from->SegSs;
582 to->EFlags = from->EFlags;
583 to->MxCsr = from->MxCsr;
585 if (flags & CONTEXT_INTEGER)
602 if (flags & CONTEXT_SEGMENTS)
604 to->SegDs = from->SegDs;
605 to->SegEs = from->SegEs;
606 to->SegFs = from->SegFs;
607 to->SegGs = from->SegGs;
609 if (flags & CONTEXT_FLOATING_POINT)
611 to->u.FltSave = from->u.FltSave;
613 if (flags & CONTEXT_DEBUG_REGISTERS)
622 #elif defined(__sparc__)
623 flags &= ~CONTEXT_SPARC; /* get rid of CPU id */
624 if (flags & CONTEXT_CONTROL)
633 if (flags & CONTEXT_INTEGER)
668 if (flags & CONTEXT_FLOATING_POINT)
672 #elif defined(__powerpc__)
674 if (flags & CONTEXT_CONTROL)
680 if (flags & CONTEXT_INTEGER)
682 to->Gpr0 = from->Gpr0;
683 to->Gpr1 = from->Gpr1;
684 to->Gpr2 = from->Gpr2;
685 to->Gpr3 = from->Gpr3;
686 to->Gpr4 = from->Gpr4;
687 to->Gpr5 = from->Gpr5;
688 to->Gpr6 = from->Gpr6;
689 to->Gpr7 = from->Gpr7;
690 to->Gpr8 = from->Gpr8;
691 to->Gpr9 = from->Gpr9;
692 to->Gpr10 = from->Gpr10;
693 to->Gpr11 = from->Gpr11;
694 to->Gpr12 = from->Gpr12;
695 to->Gpr13 = from->Gpr13;
696 to->Gpr14 = from->Gpr14;
697 to->Gpr15 = from->Gpr15;
698 to->Gpr16 = from->Gpr16;
699 to->Gpr17 = from->Gpr17;
700 to->Gpr18 = from->Gpr18;
701 to->Gpr19 = from->Gpr19;
702 to->Gpr20 = from->Gpr20;
703 to->Gpr21 = from->Gpr21;
704 to->Gpr22 = from->Gpr22;
705 to->Gpr23 = from->Gpr23;
706 to->Gpr24 = from->Gpr24;
707 to->Gpr25 = from->Gpr25;
708 to->Gpr26 = from->Gpr26;
709 to->Gpr27 = from->Gpr27;
710 to->Gpr28 = from->Gpr28;
711 to->Gpr29 = from->Gpr29;
712 to->Gpr30 = from->Gpr30;
713 to->Gpr31 = from->Gpr31;
717 if (flags & CONTEXT_FLOATING_POINT)
719 to->Fpr0 = from->Fpr0;
720 to->Fpr1 = from->Fpr1;
721 to->Fpr2 = from->Fpr2;
722 to->Fpr3 = from->Fpr3;
723 to->Fpr4 = from->Fpr4;
724 to->Fpr5 = from->Fpr5;
725 to->Fpr6 = from->Fpr6;
726 to->Fpr7 = from->Fpr7;
727 to->Fpr8 = from->Fpr8;
728 to->Fpr9 = from->Fpr9;
729 to->Fpr10 = from->Fpr10;
730 to->Fpr11 = from->Fpr11;
731 to->Fpr12 = from->Fpr12;
732 to->Fpr13 = from->Fpr13;
733 to->Fpr14 = from->Fpr14;
734 to->Fpr15 = from->Fpr15;
735 to->Fpr16 = from->Fpr16;
736 to->Fpr17 = from->Fpr17;
737 to->Fpr18 = from->Fpr18;
738 to->Fpr19 = from->Fpr19;
739 to->Fpr20 = from->Fpr20;
740 to->Fpr21 = from->Fpr21;
741 to->Fpr22 = from->Fpr22;
742 to->Fpr23 = from->Fpr23;
743 to->Fpr24 = from->Fpr24;
744 to->Fpr25 = from->Fpr25;
745 to->Fpr26 = from->Fpr26;
746 to->Fpr27 = from->Fpr27;
747 to->Fpr28 = from->Fpr28;
748 to->Fpr29 = from->Fpr29;
749 to->Fpr30 = from->Fpr30;
750 to->Fpr31 = from->Fpr31;
751 to->Fpscr = from->Fpscr;
754 #error You must implement context copying for your CPU
759 /***********************************************************************
760 * NtGetContextThread (NTDLL.@)
761 * ZwGetContextThread (NTDLL.@)
763 NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
769 SERVER_START_REQ( get_thread_context )
771 req->handle = handle;
772 req->flags = context->ContextFlags;
774 wine_server_set_reply( req, &ctx, sizeof(ctx) );
775 ret = wine_server_call( req );
779 if (ret == STATUS_PENDING)
781 if (NtSuspendThread( handle, &dummy ) == STATUS_SUCCESS)
783 for (i = 0; i < 100; i++)
785 SERVER_START_REQ( get_thread_context )
787 req->handle = handle;
788 req->flags = context->ContextFlags;
790 wine_server_set_reply( req, &ctx, sizeof(ctx) );
791 ret = wine_server_call( req );
794 if (ret != STATUS_PENDING) break;
797 NtResumeThread( handle, &dummy );
801 if (ret == STATUS_SUCCESS) copy_context( context, &ctx, context->ContextFlags );
802 else if (ret == STATUS_PENDING) ret = STATUS_ACCESS_DENIED;
807 /******************************************************************************
808 * NtQueryInformationThread (NTDLL.@)
809 * ZwQueryInformationThread (NTDLL.@)
811 NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
812 void *data, ULONG length, ULONG *ret_len )
818 case ThreadBasicInformation:
820 THREAD_BASIC_INFORMATION info;
822 SERVER_START_REQ( get_thread_info )
824 req->handle = handle;
826 if (!(status = wine_server_call( req )))
828 info.ExitStatus = reply->exit_code;
829 info.TebBaseAddress = reply->teb;
830 info.ClientId.UniqueProcess = (HANDLE)reply->pid;
831 info.ClientId.UniqueThread = (HANDLE)reply->tid;
832 info.AffinityMask = reply->affinity;
833 info.Priority = reply->priority;
834 info.BasePriority = reply->priority; /* FIXME */
838 if (status == STATUS_SUCCESS)
840 if (data) memcpy( data, &info, min( length, sizeof(info) ));
841 if (ret_len) *ret_len = min( length, sizeof(info) );
847 KERNEL_USER_TIMES kusrt;
848 /* We need to do a server call to get the creation time or exit time */
849 /* This works on any thread */
850 SERVER_START_REQ( get_thread_info )
852 req->handle = handle;
854 status = wine_server_call( req );
855 if (status == STATUS_SUCCESS)
857 RtlSecondsSince1970ToTime( reply->creation_time, &kusrt.CreateTime );
858 RtlSecondsSince1970ToTime( reply->exit_time, &kusrt.ExitTime );
862 if (status == STATUS_SUCCESS)
864 /* We call times(2) for kernel time or user time */
865 /* We can only (portably) do this for the current thread */
866 if (handle == GetCurrentThread())
869 long clocks_per_sec = sysconf(_SC_CLK_TCK);
872 kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
873 kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
877 kusrt.KernelTime.QuadPart = 0;
878 kusrt.UserTime.QuadPart = 0;
879 FIXME("Cannot get kerneltime or usertime of other threads\n");
881 if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
882 if (ret_len) *ret_len = min( length, sizeof(kusrt) );
887 case ThreadBasePriority:
888 case ThreadAffinityMask:
889 case ThreadImpersonationToken:
890 case ThreadDescriptorTableEntry:
891 case ThreadEnableAlignmentFaultFixup:
892 case ThreadEventPair_Reusable:
893 case ThreadQuerySetWin32StartAddress:
894 case ThreadZeroTlsCell:
895 case ThreadPerformanceCount:
896 case ThreadAmILastThread:
897 case ThreadIdealProcessor:
898 case ThreadPriorityBoost:
899 case ThreadSetTlsArrayAddress:
900 case ThreadIsIoPending:
902 FIXME( "info class %d not supported yet\n", class );
903 return STATUS_NOT_IMPLEMENTED;
908 /******************************************************************************
909 * NtSetInformationThread (NTDLL.@)
910 * ZwSetInformationThread (NTDLL.@)
912 NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
913 LPCVOID data, ULONG length )
918 case ThreadZeroTlsCell:
919 if (handle == GetCurrentThread())
924 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
925 index = *(const DWORD *)data;
926 if (index < TLS_MINIMUM_AVAILABLE)
929 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
931 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
932 teb->TlsSlots[index] = 0;
938 index -= TLS_MINIMUM_AVAILABLE;
939 if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
940 return STATUS_INVALID_PARAMETER;
942 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
944 TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
945 if (teb->TlsExpansionSlots) teb->TlsExpansionSlots[index] = 0;
949 return STATUS_SUCCESS;
951 FIXME( "ZeroTlsCell not supported on other threads\n" );
952 return STATUS_NOT_IMPLEMENTED;
954 case ThreadImpersonationToken:
956 const HANDLE *phToken = data;
957 if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
958 TRACE("Setting ThreadImpersonationToken handle to %p\n", *phToken );
959 SERVER_START_REQ( set_thread_info )
961 req->handle = handle;
962 req->token = *phToken;
963 req->mask = SET_THREAD_INFO_TOKEN;
964 status = wine_server_call( req );
969 case ThreadBasePriority:
971 const DWORD *pprio = data;
972 if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
973 SERVER_START_REQ( set_thread_info )
975 req->handle = handle;
976 req->priority = *pprio;
977 req->mask = SET_THREAD_INFO_PRIORITY;
978 status = wine_server_call( req );
983 case ThreadBasicInformation:
986 case ThreadAffinityMask:
987 case ThreadDescriptorTableEntry:
988 case ThreadEnableAlignmentFaultFixup:
989 case ThreadEventPair_Reusable:
990 case ThreadQuerySetWin32StartAddress:
991 case ThreadPerformanceCount:
992 case ThreadAmILastThread:
993 case ThreadIdealProcessor:
994 case ThreadPriorityBoost:
995 case ThreadSetTlsArrayAddress:
996 case ThreadIsIoPending:
998 FIXME( "info class %d not supported yet\n", class );
999 return STATUS_NOT_IMPLEMENTED;
1004 /**********************************************************************
1005 * NtCurrentTeb (NTDLL.@)
1007 #if defined(__i386__) && defined(__GNUC__)
1009 __ASM_GLOBAL_FUNC( NtCurrentTeb, ".byte 0x64\n\tmovl 0x18,%eax\n\tret" );
1011 #elif defined(__i386__) && defined(_MSC_VER)
1013 /* Nothing needs to be done. MS C "magically" exports the inline version from winnt.h */
1017 /**********************************************************************/
1019 TEB * WINAPI NtCurrentTeb(void)
1021 return pthread_functions.get_current_teb();
1024 #endif /* __i386__ */