| /* | |
| * 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 "msvcrt.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); | |
| /********************************************************************/ | |
| typedef struct { | |
| 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 ); | |
| } | |
| 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)); | |
| MSVCRT_free(arg); | |
| local_trampoline.start_address(local_trampoline.arglist); | |
| return 0; | |
| } | |
| /********************************************************************* | |
| * _beginthread (MSVCRT.@) | |
| */ | |
| unsigned long _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; | |
| 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=MSVCRT_malloc(sizeof(*trampoline)); | |
| trampoline->start_address = start_address; | |
| trampoline->arglist = arglist; | |
| /* FIXME */ | |
| return (unsigned long)CreateThread(NULL, stack_size, _beginthread_trampoline, | |
| trampoline, 0, NULL); | |
| } | |
| /********************************************************************* | |
| * _beginthreadex (MSVCRT.@) | |
| */ | |
| unsigned long _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 (unsigned long)CreateThread(security, stack_size, | |
| (LPTHREAD_START_ROUTINE) start_address, | |
| arglist, initflag, (LPDWORD) thrdaddr); | |
| } | |
| /********************************************************************* | |
| * _endthread (MSVCRT.@) | |
| */ | |
| void _endthread(void) | |
| { | |
| TRACE("(void)\n"); | |
| /* FIXME */ | |
| ExitThread(0); | |
| } | |
| /********************************************************************* | |
| * _endthreadex (MSVCRT.@) | |
| */ | |
| void _endthreadex( | |
| unsigned int retval) /* [in] Thread exit code */ | |
| { | |
| TRACE("(%d)\n", retval); | |
| /* FIXME */ | |
| ExitThread(retval); | |
| } |