diff --git a/reactos/lib/crt/crt.xml b/reactos/lib/crt/crt.xml index 2db3f46fe95..1a2f64f21f6 100644 --- a/reactos/lib/crt/crt.xml +++ b/reactos/lib/crt/crt.xml @@ -385,7 +385,6 @@ cppexcept.c heap.c scanf.c - thread.c undname.c diff --git a/reactos/lib/crt/include/internal/tls.h b/reactos/lib/crt/include/internal/tls.h index 4adcc83f236..79ad295618e 100644 --- a/reactos/lib/crt/include/internal/tls.h +++ b/reactos/lib/crt/include/internal/tls.h @@ -17,6 +17,10 @@ typedef struct _ThreadData { + HANDLE hThread; /* handle to the current thread */ + void (__cdecl *start_address)(void*); /* the start address supplied by _beginthread() */ + void* arglist; /* the argument list supplied by _beginthread() */ + int terrno; /* *nix error code */ unsigned long tdoserrno; /* Win32 error code (for I/O only) */ unsigned __int64 tnext; /* used by rand/srand */ @@ -41,7 +45,8 @@ typedef struct _ThreadData int CreateThreadData(void); void DestroyThreadData(void); -void FreeThreadData(PTHREADDATA ptd); +int SetThreadData(PTHREADDATA ThreadData); +void FreeThreadData(PTHREADDATA ThreadData); PTHREADDATA GetThreadData(void); #endif /* __MSVCRT_INTERNAL_TLS_H */ diff --git a/reactos/lib/crt/misc/tls.c b/reactos/lib/crt/misc/tls.c index 9fa6d036ac0..41414f3c585 100644 --- a/reactos/lib/crt/misc/tls.c +++ b/reactos/lib/crt/misc/tls.c @@ -4,7 +4,7 @@ #include -static unsigned long TlsIndex = (unsigned long)-1; +static DWORD TlsIndex = TLS_OUT_OF_INDEXES; static void InitThreadData(PTHREADDATA ThreadData) @@ -19,19 +19,10 @@ static void InitThreadData(PTHREADDATA ThreadData) } -int CreateThreadData(void) +int SetThreadData(PTHREADDATA ThreadData) { - PTHREADDATA ThreadData; - - TlsIndex = TlsAlloc(); - if (TlsIndex == (unsigned long)-1) - return FALSE; - - ThreadData = (PTHREADDATA)calloc(1, sizeof(THREADDATA)); - if (ThreadData == NULL) - return FALSE; - - if(!TlsSetValue(TlsIndex, (LPVOID)ThreadData)) + if(TlsIndex == TLS_OUT_OF_INDEXES || + !TlsSetValue(TlsIndex, ThreadData)) return FALSE; InitThreadData(ThreadData); @@ -40,19 +31,26 @@ int CreateThreadData(void) } +int CreateThreadData(void) +{ + TlsIndex = TlsAlloc(); + return (TlsIndex != TLS_OUT_OF_INDEXES); +} + + void DestroyThreadData(void) { - if (TlsIndex != (unsigned long)-1) + if (TlsIndex != TLS_OUT_OF_INDEXES) { TlsFree(TlsIndex); - TlsIndex = (unsigned long)-1; + TlsIndex = TLS_OUT_OF_INDEXES; } } void FreeThreadData(PTHREADDATA ThreadData) { - if (TlsIndex != (unsigned long)-1) + if (TlsIndex != TLS_OUT_OF_INDEXES) { if (ThreadData == NULL) ThreadData = TlsGetValue(TlsIndex); @@ -84,6 +82,8 @@ PTHREADDATA GetThreadData(void) TlsSetValue(TlsIndex, (LPVOID)ThreadData); InitThreadData(ThreadData); + + ThreadData->hThread = GetCurrentThread(); } else { diff --git a/reactos/lib/crt/process/thread.c b/reactos/lib/crt/process/thread.c index d058d7252e2..2b86729ae70 100644 --- a/reactos/lib/crt/process/thread.c +++ b/reactos/lib/crt/process/thread.c @@ -1,23 +1,102 @@ #include -#if 0 +void _endthread(void); + +static DWORD WINAPI +_beginthread_start(PVOID lpParameter) +{ + PTHREADDATA ThreadData = (PTHREADDATA)lpParameter; + + if (SetThreadData(ThreadData)) + { + /* FIXME - wrap start_address in SEH! */ + ThreadData->start_address(ThreadData->arglist); + + _endthread(); + } + else + { + /* couldn't set the thread data, free it before terminating */ + free(ThreadData); + } + + ExitThread(0); +} + + /* - * @unimplemented + * @implemented + * + * FIXME: the return type should be uintptr_t */ unsigned long _beginthread( void (__cdecl *start_address)(void*), unsigned stack_size, void* arglist) { - __set_errno ( ENOSYS ); - return (unsigned long)-1; + HANDLE hThread; + PTHREADDATA ThreadData; + + if (start_address == NULL) { + __set_errno(EINVAL); + return (unsigned long)-1; + } + + /* allocate the thread data structure already here instead of allocating the + thread data structure in the thread itself. this way we can pass an error + code to the caller in case we don't have sufficient resources */ + ThreadData = malloc(sizeof(THREADDATA)); + if (ThreadData == NULL) + { + __set_errno(EAGAIN); + return (unsigned long)-1; + } + + ThreadData->start_address = start_address; + ThreadData->arglist = arglist; + + hThread = CreateThread(NULL, + stack_size, + _beginthread_start, + ThreadData, + CREATE_SUSPENDED, + NULL); + if (hThread == NULL) + { + free(ThreadData); + __set_errno(EAGAIN); + return (unsigned long)-1; + } + + ThreadData->hThread = hThread; + + if (ResumeThread(hThread) == (DWORD)-1) + { + CloseHandle(hThread); + + /* freeing the ThreadData _could_ cause a crash, but only in case someone + else resumed the thread and it got to free the context before we actually + get here, but that's _very_ unlikely! */ + free(ThreadData); + __set_errno(EAGAIN); + return (unsigned long)-1; + } + + return (unsigned long)hThread; } -#endif + /* - * @unimplemented + * @implemented */ void _endthread(void) { -} + PTHREADDATA ThreadData = GetThreadData(); -/* EOF */ + /* close the thread handle */ + CloseHandle(ThreadData->hThread); + + /* NOTE: the thread data will be freed in the thread detach routine that will + call FreeThreadData */ + + ExitThread(0); +} diff --git a/reactos/lib/crt/wine/thread.c b/reactos/lib/crt/wine/thread.c deleted file mode 100644 index d1574d69faa..00000000000 --- a/reactos/lib/crt/wine/thread.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * msvcrt.dll thread functions - * - * Copyright 2000 Jon Griffiths - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -#include -#include - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); - -void _amsg_exit (int errnum); -/* Index to TLS */ -DWORD MSVCRT_tls_index; - -typedef void (*_beginthread_start_routine_t)(void *); -typedef unsigned int (__stdcall *_beginthreadex_start_routine_t)(void *); - -/********************************************************************/ - -typedef struct { - _beginthread_start_routine_t start_address; - void *arglist; -} _beginthread_trampoline_t; - -/********************************************************************* - * msvcrt_get_thread_data - * - * Return the thread local storage structure. - */ -MSVCRT_thread_data *msvcrt_get_thread_data(void) -{ - MSVCRT_thread_data *ptr; - DWORD err = GetLastError(); /* need to preserve last error */ - - if (!(ptr = TlsGetValue( MSVCRT_tls_index ))) - { - if (!(ptr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*ptr) ))) - _amsg_exit( _RT_THREAD ); - if (!TlsSetValue( MSVCRT_tls_index, ptr )) - _amsg_exit( _RT_THREAD ); - if (!TlsSetValue( MSVCRT_tls_index, ptr )) - _amsg_exit( _RT_THREAD ); - } - SetLastError( err ); - return ptr; -} - -/********************************************************************* - * _beginthread_trampoline - */ -static DWORD CALLBACK _beginthread_trampoline(LPVOID arg) -{ - _beginthread_trampoline_t local_trampoline; - - /* Maybe it's just being paranoid, but freeing arg right - * away seems safer. - */ - memcpy(&local_trampoline,arg,sizeof(local_trampoline)); - free(arg); - - local_trampoline.start_address(local_trampoline.arglist); - return 0; -} - -/********************************************************************* - * _beginthread (MSVCRT.@) - */ -unsigned long _beginthread( - _beginthread_start_routine_t start_address, /* [in] Start address of routine that begins execution of new thread */ - unsigned int stack_size, /* [in] Stack size for new thread or 0 */ - void *arglist) /* [in] Argument list to be passed to new thread or NULL */ -{ - _beginthread_trampoline_t* trampoline; - - TRACE("(%p, %d, %p)\n", start_address, stack_size, arglist); - - /* Allocate the trampoline here so that it is still valid when the thread - * starts... typically after this function has returned. - * _beginthread_trampoline is responsible for freeing the trampoline - */ - trampoline=malloc(sizeof(*trampoline)); - trampoline->start_address = start_address; - trampoline->arglist = arglist; - - /* FIXME */ - return (unsigned long)CreateThread(NULL, stack_size, _beginthread_trampoline, - trampoline, 0, NULL); -}