|
|
/***
*thread.c - Begin and end a thread * * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved. * *Purpose: * This source contains the _beginthread() and _endthread() * routines which are used to start and terminate a thread. * *Revision History: * 05-09-90 JCR Translated from ASM to C * 07-25-90 SBM Removed '32' from API names * 10-08-90 GJF New-style function declarators. * 10-09-90 GJF Thread ids are of type unsigned long. * 10-19-90 GJF Added code to set _stkhqq properly in stub(). * 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h> * 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals. * 06-03-91 GJF Win32 version [_WIN32_]. * 07-18-91 GJF Fixed many silly errors [_WIN32_]. * 08-19-91 GJF Allow for newly created thread terminating before * _beginthread returns * 09-30-91 GJF Add per-thread initialization and termination calls * for floating point. * 01-18-92 GJF Revised try - except statement. * 02-25-92 GJF Initialize _holdrand field to 1. * 09-30-92 SRW Add WINAPI keyword to _threadstart routine * 10-30-92 GJF Error ret for CreateThread is 0 (NULL), not -1. * 02-13-93 GJF Revised to use TLS API. Also, purged Cruiser support. * 03-26-93 GJF Fixed horribly embarrassing bug: ptd->pxcptacttab * must be initialized to _XcptActTab! * 04-01-93 CFW Change try-except to __try-__except * 04-06-93 SKS Replace _CRTAPI* with __cdecl * 04-27-93 GJF Removed support for _RT_STACK, _RT_INTDIV, * _RT_INVALDISP and _RT_NONCONT. * 10-26-93 GJF Replaced PF with _PVFV (defined in internal.h). * 12-13-93 SKS Free up per-thread data using a call to _freeptd() * 01-06-94 GJF Free up _tiddata struct upon failure in _beginthread. * Also, set errno on failure. * 01-10-95 CFW Debug CRT allocs. * 04-18-95 SKS Add 5 MIPS per-thread variables. * 05-02-95 SKS Call _initptd for initialization of per-thread data. * 02-03-98 GJF Changes for Win64: use uintptr_t type for anything with * a HANDLE value. * 02-02-00 GB Modified threadstart() to prevent leaking of ptd * allocated during call to getptd while ATTACHing THREAD * in dlls. * 08-04-00 PML Set EINVAL error if thread start address null in * _beginthread (VS7#118688). * 10-16-01 GB Added fiber support * 12-11-01 BWT _getptd doesn't return NULL. Change to _getptd_noexit * and don't terminate the process if it can't be allocated * in endthreadex - just exit the thread. * 12-11-01 BWT Also, in threadstart - don't exit the process if FlsSetValue * fails - exit the thread instead - this isn't a fatal condition. * *******************************************************************************/
#ifdef _MT
#include <cruntime.h>
#include <oscalls.h>
#include <internal.h>
#include <mtdll.h>
#include <msdos.h>
#include <malloc.h>
#include <process.h>
#include <stddef.h>
#include <rterr.h>
#include <dbgint.h>
#include <errno.h>
/*
* Startup code for new thread. */ static unsigned long WINAPI _threadstart(void *);
/*
* declare pointers to per-thread FP initialization and termination routines */ _PVFV _FPmtinit; _PVFV _FPmtterm;
/***
*_beginthread() - Create a child thread * *Purpose: * Create a child thread. * *Entry: * initialcode = pointer to thread's startup code address * stacksize = size of stack * argument = argument to be passed to new thread * *Exit: * success = handle for new thread if successful * * failure = (unsigned long) -1L in case of error, errno and _doserrno * are set * *Exceptions: * *******************************************************************************/
uintptr_t __cdecl _beginthread ( void (__cdecl * initialcode) (void *), unsigned stacksize, void * argument ) { _ptiddata ptd; /* pointer to per-thread data */ uintptr_t thdl; /* thread handle */ unsigned long errcode = 0L; /* Return from GetLastError() */
if ( initialcode == NULL ) { errno = EINVAL; return( (uintptr_t)(-1) ); }
/*
* Allocate and initialize a per-thread data structure for the to- * be-created thread. */ if ( (ptd = _calloc_crt(1, sizeof(struct _tiddata))) == NULL ) goto error_return;
/*
* Initialize the per-thread data */
_initptd(ptd);
ptd->_initaddr = (void *) initialcode; ptd->_initarg = argument;
/*
* Create the new thread. Bring it up in a suspended state so that * the _thandle and _tid fields are filled in before execution * starts. */ if ( (ptd->_thandle = thdl = (uintptr_t) CreateThread( NULL, stacksize, _threadstart, (LPVOID)ptd, CREATE_SUSPENDED, (LPDWORD)&(ptd->_tid) )) == (uintptr_t)0 ) { errcode = GetLastError(); goto error_return; }
/*
* Start the new thread executing */ if ( ResumeThread( (HANDLE)thdl ) == (DWORD)(-1) ) { errcode = GetLastError(); goto error_return; }
/*
* Good return */ return(thdl);
/*
* Error return */ error_return: /*
* Either ptd is NULL, or it points to the no-longer-necessary block * calloc-ed for the _tiddata struct which should now be freed up. */ _free_crt(ptd);
/*
* Map the error, if necessary. */ if ( errcode != 0L ) _dosmaperr(errcode);
return( (uintptr_t)(-1) ); }
/***
*_threadstart() - New thread begins here * *Purpose: * The new thread begins execution here. This routine, in turn, * passes control to the user's code. * *Entry: * void *ptd = pointer to _tiddata structure for this thread * *Exit: * Never returns - terminates thread! * *Exceptions: * *******************************************************************************/
static unsigned long WINAPI _threadstart ( void * ptd ) { _ptiddata _ptd; /* pointer to per-thread data */ /*
* Check if ptd is initialised during THREAD_ATTACH call to dll mains */ if ( (_ptd = FLS_GETVALUE(__tlsindex)) == NULL) { /*
* Stash the pointer to the per-thread data stucture in TLS */ if ( !FLS_SETVALUE(__tlsindex, ptd) ) ExitThread(GetLastError()); } else { _ptd->_initaddr = ((_ptiddata) ptd)->_initaddr; _ptd->_initarg = ((_ptiddata) ptd)->_initarg; _ptd->_thandle = ((_ptiddata) ptd)->_thandle; _free_crt(ptd); ptd = _ptd; }
/*
* Call fp initialization, if necessary */ if ( _FPmtinit != NULL ) (*_FPmtinit)();
/*
* Guard call to user code with a _try - _except statement to * implement runtime errors and signal support */ __try { ( (void(__cdecl *)(void *))(((_ptiddata)ptd)->_initaddr) ) ( ((_ptiddata)ptd)->_initarg );
_endthread(); } __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) ) { /*
* Should never reach here */ _exit( GetExceptionCode() );
} /* end of _try - _except */
/*
* Never executed! */ return(0L); }
/***
*_endthread() - Terminate the calling thread * *Purpose: * *Entry: * void * *Exit: * Never returns! * *Exceptions: * *******************************************************************************/
void __cdecl _endthread ( void ) { _ptiddata ptd; /* pointer to thread's _tiddata struct */
/*
* Call fp termination, if necessary */ if ( _FPmtterm != NULL ) (*_FPmtterm)();
ptd = _getptd_noexit(); if (ptd) { /*
* Close the thread handle (if there was one) */ if ( ptd->_thandle != (uintptr_t)(-1) ) (void) CloseHandle( (HANDLE)(ptd->_thandle) ); /*
* Free up the _tiddata structure & its subordinate buffers * _freeptd() will also clear the value for this thread * of the FLS variable __tlsindex. */ _freeptd(ptd); }
/*
* Terminate the thread */ ExitThread(0);
}
#endif /* _MT */
|