| /* |
| * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| #include "msvcrt.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); |
| |
| /********************************************************************/ |
| |
| typedef struct { |
| HANDLE thread; |
| MSVCRT__beginthread_start_routine_t start_address; |
| void *arglist; |
| } _beginthread_trampoline_t; |
| |
| /********************************************************************* |
| * msvcrt_get_thread_data |
| * |
| * Return the thread local storage structure. |
| */ |
| thread_data_t *msvcrt_get_thread_data(void) |
| { |
| thread_data_t *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 ); |
| ptr->tid = GetCurrentThreadId(); |
| ptr->handle = INVALID_HANDLE_VALUE; |
| ptr->random_seed = 1; |
| ptr->locinfo = MSVCRT_locale->locinfo; |
| ptr->mbcinfo = MSVCRT_locale->mbcinfo; |
| } |
| SetLastError( err ); |
| return ptr; |
| } |
| |
| /********************************************************************* |
| * _endthread (MSVCRT.@) |
| */ |
| void CDECL _endthread(void) |
| { |
| thread_data_t *tls; |
| |
| TRACE("(void)\n"); |
| |
| tls = TlsGetValue(msvcrt_tls_index); |
| if (tls && tls->handle != INVALID_HANDLE_VALUE) |
| { |
| CloseHandle(tls->handle); |
| tls->handle = INVALID_HANDLE_VALUE; |
| } else |
| WARN("tls=%p tls->handle=%p\n", tls, tls ? tls->handle : INVALID_HANDLE_VALUE); |
| |
| /* FIXME */ |
| ExitThread(0); |
| } |
| |
| /********************************************************************* |
| * _endthreadex (MSVCRT.@) |
| */ |
| void CDECL _endthreadex( |
| unsigned int retval) /* [in] Thread exit code */ |
| { |
| TRACE("(%d)\n", retval); |
| |
| /* FIXME */ |
| ExitThread(retval); |
| } |
| |
| /********************************************************************* |
| * _beginthread_trampoline |
| */ |
| static DWORD CALLBACK _beginthread_trampoline(LPVOID arg) |
| { |
| _beginthread_trampoline_t local_trampoline; |
| thread_data_t *data = msvcrt_get_thread_data(); |
| |
| memcpy(&local_trampoline,arg,sizeof(local_trampoline)); |
| data->handle = local_trampoline.thread; |
| MSVCRT_free(arg); |
| |
| local_trampoline.start_address(local_trampoline.arglist); |
| _endthread(); |
| return 0; |
| } |
| |
| /********************************************************************* |
| * _beginthread (MSVCRT.@) |
| */ |
| MSVCRT_uintptr_t CDECL _beginthread( |
| MSVCRT__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; |
| HANDLE thread; |
| |
| TRACE("(%p, %d, %p)\n", start_address, stack_size, arglist); |
| |
| trampoline = MSVCRT_malloc(sizeof(*trampoline)); |
| if(!trampoline) { |
| *MSVCRT__errno() = MSVCRT_EAGAIN; |
| return -1; |
| } |
| |
| thread = CreateThread(NULL, stack_size, _beginthread_trampoline, |
| trampoline, CREATE_SUSPENDED, NULL); |
| if(!thread) { |
| MSVCRT_free(trampoline); |
| *MSVCRT__errno() = MSVCRT_EAGAIN; |
| return -1; |
| } |
| |
| trampoline->thread = thread; |
| trampoline->start_address = start_address; |
| trampoline->arglist = arglist; |
| |
| if(ResumeThread(thread) == -1) { |
| MSVCRT_free(trampoline); |
| *MSVCRT__errno() = MSVCRT_EAGAIN; |
| return -1; |
| } |
| |
| return (MSVCRT_uintptr_t)thread; |
| } |
| |
| /********************************************************************* |
| * _beginthreadex (MSVCRT.@) |
| */ |
| MSVCRT_uintptr_t CDECL _beginthreadex( |
| void *security, /* [in] Security descriptor for new thread; must be NULL for Windows 9x applications */ |
| unsigned int stack_size, /* [in] Stack size for new thread or 0 */ |
| MSVCRT__beginthreadex_start_routine_t start_address, /* [in] Start address of routine that begins execution of new thread */ |
| void *arglist, /* [in] Argument list to be passed to new thread or NULL */ |
| unsigned int initflag, /* [in] Initial state of new thread (0 for running or CREATE_SUSPEND for suspended) */ |
| unsigned int *thrdaddr) /* [out] Points to a 32-bit variable that receives the thread identifier */ |
| { |
| TRACE("(%p, %d, %p, %p, %d, %p)\n", security, stack_size, start_address, arglist, initflag, thrdaddr); |
| |
| /* FIXME */ |
| return (MSVCRT_uintptr_t)CreateThread(security, stack_size, |
| start_address, arglist, |
| initflag, thrdaddr); |
| } |
| |
| /********************************************************************* |
| * _getptd (MSVCR80.@) |
| */ |
| thread_data_t* CDECL _getptd(void) |
| { |
| FIXME("returns undocumented/not fully filled data\n"); |
| return msvcrt_get_thread_data(); |
| } |