Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

331 lines
10 KiB

  1. /***
  2. *threadex.c - Extended versions of Begin (Create) and End (Exit) a Thread
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * This source contains the _beginthreadex() and _endthreadex()
  8. * routines which are used to start and terminate a thread. These
  9. * routines are more like the Win32 APIs CreateThread() and ExitThread()
  10. * than the original functions _beginthread() & _endthread() were.
  11. *
  12. *Revision History:
  13. * 02-16-94 SKS Original version, based on thread.c which contains
  14. * _beginthread() and _endthread().
  15. * 02-17-94 SKS Changed error return from -1 to 0, fix some comments.
  16. * 06-10-94 SKS Pass the thrdaddr value directly to CreateThread().
  17. * Do *NOT* store the thread handle into the per-thread
  18. * data block of the child thread. (It is not needed.)
  19. * The thread data structure may have been freed by the
  20. * child thread before the parent thread returns from the
  21. * call to CreateThread(). Watch that synchronization!
  22. * 01-10-95 CFW Debug CRT allocs.
  23. * 04-18-95 SKS Add 5 MIPS per-thread variables.
  24. * 05-02-95 SKS Call _initptd for initialization of per-thread data.
  25. * 02-03-98 GJF Changes for Win64: use uintptr_t type for anything with
  26. * a HANDLE value.
  27. * 02-02-00 GB Modified threadstartex() to prevent leaking of ptd
  28. * allocated during call to getptd while ATTACHing THREAD
  29. * in dlls.
  30. * 05-31-00 PML Don't pass NULL thrdaddr into CreateThread, since a
  31. * non-NULL lpThreadId is required on Win9x.
  32. * 08-04-00 PML Set EINVAL error if thread start address null in
  33. * _beginthreadex (VS7#118688).
  34. * 10-16-01 GB Added fiber support
  35. * 12-11-01 BWT _getptd doesn't return NULL. Change to _getptd_noexit
  36. * and don't terminate the process if it can't be allocated
  37. * in endthreadex - just exit the thread.
  38. *
  39. *******************************************************************************/
  40. #ifdef _MT
  41. #include <cruntime.h>
  42. #include <oscalls.h>
  43. #include <internal.h>
  44. #include <mtdll.h>
  45. #include <msdos.h>
  46. #include <malloc.h>
  47. #include <process.h>
  48. #include <stddef.h>
  49. #include <rterr.h>
  50. #include <dbgint.h>
  51. #include <errno.h>
  52. /*
  53. * Startup code for new thread.
  54. */
  55. static unsigned long WINAPI _threadstartex(void *);
  56. /*
  57. * declare pointers to per-thread FP initialization and termination routines
  58. */
  59. _PVFV _FPmtinit;
  60. _PVFV _FPmtterm;
  61. /***
  62. *_beginthreadex() - Create a child thread
  63. *
  64. *Purpose:
  65. * Create a child thread.
  66. *
  67. *Entry:
  68. * *** Same parameters as the Win32 API CreateThread() ***
  69. * security = security descriptor for the new thread
  70. * stacksize = size of stack
  71. * initialcode = pointer to thread's startup code address
  72. * must be a __stdcall function returning an unsigned.
  73. * argument = argument to be passed to new thread
  74. * createflag = flag to create thread in a suspended state
  75. * thrdaddr = points to an int to receive the ID of the new thread
  76. *
  77. *Exit:
  78. * *** Same as the Win32 API CreateThread() ***
  79. *
  80. * success = handle for new thread if successful
  81. *
  82. * failure = 0 in case of error, errno and _doserrno are set
  83. *
  84. *Exceptions:
  85. *
  86. *Notes:
  87. * This routine is more like the Win32 API CreateThread() than it
  88. * is like the C run-time routine _beginthread(). Ditto for
  89. * _endthreadex() and the Win32 API ExitThread() versus _endthread().
  90. *
  91. * Differences between _beginthread/_endthread and the "ex" versions:
  92. *
  93. * 1) _beginthreadex takes the 3 extra parameters to CreateThread
  94. * which are lacking in _beginthread():
  95. * A) security descriptor for the new thread
  96. * B) initial thread state (running/asleep)
  97. * C) pointer to return ID of newly created thread
  98. *
  99. * 2) The routine passed to _beginthread() must be __cdecl and has
  100. * no return code, but the routine passed to _beginthreadex()
  101. * must be __stdcall and returns a thread exit code. _endthread
  102. * likewise takes no parameter and calls ExitThread() with a
  103. * parameter of zero, but _endthreadex() takes a parameter as
  104. * thread exit code.
  105. *
  106. * 3) _endthread implicitly closes the handle to the thread, but
  107. * _endthreadex does not!
  108. *
  109. * 4) _beginthread returns -1 for failure, _beginthreadex returns
  110. * 0 for failure (just like CreateThread).
  111. *
  112. *******************************************************************************/
  113. uintptr_t __cdecl _beginthreadex (
  114. void *security,
  115. unsigned stacksize,
  116. unsigned (__stdcall * initialcode) (void *),
  117. void * argument,
  118. unsigned createflag,
  119. unsigned *thrdaddr
  120. )
  121. {
  122. _ptiddata ptd; /* pointer to per-thread data */
  123. uintptr_t thdl; /* thread handle */
  124. unsigned long errcode = 0L; /* Return from GetLastError() */
  125. unsigned dummyid; /* dummy returned thread ID */
  126. if ( initialcode == NULL ) {
  127. errno = EINVAL;
  128. return( (uintptr_t)0 );
  129. }
  130. /*
  131. * Allocate and initialize a per-thread data structure for the to-
  132. * be-created thread.
  133. */
  134. if ( (ptd = _calloc_crt(1, sizeof(struct _tiddata))) == NULL )
  135. goto error_return;
  136. /*
  137. * Initialize the per-thread data
  138. */
  139. _initptd(ptd);
  140. ptd->_initaddr = (void *) initialcode;
  141. ptd->_initarg = argument;
  142. ptd->_thandle = (uintptr_t)(-1);
  143. /*
  144. * Make sure non-NULL thrdaddr is passed to CreateThread
  145. */
  146. if ( thrdaddr == NULL )
  147. thrdaddr = &dummyid;
  148. /*
  149. * Create the new thread using the parameters supplied by the caller.
  150. */
  151. if ( (thdl = (uintptr_t)
  152. CreateThread( security,
  153. stacksize,
  154. _threadstartex,
  155. (LPVOID)ptd,
  156. createflag,
  157. thrdaddr))
  158. == (uintptr_t)0 )
  159. {
  160. errcode = GetLastError();
  161. goto error_return;
  162. }
  163. /*
  164. * Good return
  165. */
  166. return(thdl);
  167. /*
  168. * Error return
  169. */
  170. error_return:
  171. /*
  172. * Either ptd is NULL, or it points to the no-longer-necessary block
  173. * calloc-ed for the _tiddata struct which should now be freed up.
  174. */
  175. _free_crt(ptd);
  176. /*
  177. * Map the error, if necessary.
  178. *
  179. * Note: this routine returns 0 for failure, just like the Win32
  180. * API CreateThread, but _beginthread() returns -1 for failure.
  181. */
  182. if ( errcode != 0L )
  183. _dosmaperr(errcode);
  184. return( (uintptr_t)0 );
  185. }
  186. /***
  187. *_threadstartex() - New thread begins here
  188. *
  189. *Purpose:
  190. * The new thread begins execution here. This routine, in turn,
  191. * passes control to the user's code.
  192. *
  193. *Entry:
  194. * void *ptd = pointer to _tiddata structure for this thread
  195. *
  196. *Exit:
  197. * Never returns - terminates thread!
  198. *
  199. *Exceptions:
  200. *
  201. *******************************************************************************/
  202. static unsigned long WINAPI _threadstartex (
  203. void * ptd
  204. )
  205. {
  206. _ptiddata _ptd; /* pointer to per-thread data */
  207. /*
  208. * Check if ptd is initialised during THREAD_ATTACH call to dll mains
  209. */
  210. if ( ( _ptd = FLS_GETVALUE(__tlsindex)) == NULL)
  211. {
  212. /*
  213. * Stash the pointer to the per-thread data stucture in TLS
  214. */
  215. if ( !FLS_SETVALUE(__tlsindex, ptd) )
  216. _amsg_exit(_RT_THREAD);
  217. /*
  218. * Set the thread ID field -- parent thread cannot set it after
  219. * CreateThread() returns since the child thread might have run
  220. * to completion and already freed its per-thread data block!
  221. */
  222. ((_ptiddata) ptd)->_tid = GetCurrentThreadId();
  223. }
  224. else
  225. {
  226. _ptd->_initaddr = ((_ptiddata) ptd)->_initaddr;
  227. _ptd->_initarg = ((_ptiddata) ptd)->_initarg;
  228. _free_crt(ptd);
  229. ptd = _ptd;
  230. }
  231. /*
  232. * Call fp initialization, if necessary
  233. */
  234. if ( _FPmtinit != NULL )
  235. (*_FPmtinit)();
  236. /*
  237. * Guard call to user code with a _try - _except statement to
  238. * implement runtime errors and signal support
  239. */
  240. __try {
  241. _endthreadex (
  242. ( (unsigned (WINAPI *)(void *))(((_ptiddata)ptd)->_initaddr) )
  243. ( ((_ptiddata)ptd)->_initarg ) ) ;
  244. }
  245. __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
  246. {
  247. /*
  248. * Should never reach here
  249. */
  250. _exit( GetExceptionCode() );
  251. } /* end of _try - _except */
  252. /*
  253. * Never executed!
  254. */
  255. return(0L);
  256. }
  257. /***
  258. *_endthreadex() - Terminate the calling thread
  259. *
  260. *Purpose:
  261. *
  262. *Entry:
  263. * Thread exit code
  264. *
  265. *Exit:
  266. * Never returns!
  267. *
  268. *Exceptions:
  269. *
  270. *******************************************************************************/
  271. void __cdecl _endthreadex (
  272. unsigned retcode
  273. )
  274. {
  275. _ptiddata ptd; /* pointer to thread's _tiddata struct */
  276. /*
  277. * Call fp termination, if necessary
  278. */
  279. if ( _FPmtterm != NULL )
  280. (*_FPmtterm)();
  281. ptd = _getptd_noexit();
  282. if (ptd) {
  283. /*
  284. * Free up the _tiddata structure & its subordinate buffers
  285. * _freeptd() will also clear the value for this thread
  286. * of the FLS variable __tlsindex.
  287. */
  288. _freeptd(ptd);
  289. }
  290. /*
  291. * Terminate the thread
  292. */
  293. ExitThread(retcode);
  294. }
  295. #endif /* _MT */