home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / threadex.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  8KB  |  275 lines

  1. /***
  2. *threadex.c - Extended versions of Begin (Create) and End (Exit) a Thread
  3. *
  4. *       Copyright (c) 1989-1997, 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. *******************************************************************************/
  13.  
  14. #ifdef _MT
  15.  
  16. #include <cruntime.h>
  17. #include <oscalls.h>
  18. #include <internal.h>
  19. #include <mtdll.h>
  20. #include <msdos.h>
  21. #include <malloc.h>
  22. #include <process.h>
  23. #include <rterr.h>
  24. #include <dbgint.h>
  25.  
  26. /*
  27.  * Startup code for new thread.
  28.  */
  29. static unsigned long WINAPI _threadstartex(void *);
  30.  
  31. /*
  32.  * declare pointers to per-thread FP initialization and termination routines
  33.  */
  34. _PVFV _FPmtinit;
  35. _PVFV _FPmtterm;
  36.  
  37.  
  38. /***
  39. *_beginthreadex() - Create a child thread
  40. *
  41. *Purpose:
  42. *       Create a child thread.
  43. *
  44. *Entry:
  45. *       *** Same parameters as the Win32 API CreateThread() ***
  46. *       security = security descriptor for the new thread
  47. *       stacksize = size of stack
  48. *       initialcode = pointer to thread's startup code address
  49. *               must be a __stdcall function returning an unsigned.
  50. *       argument = argument to be passed to new thread
  51. *       createflag = flag to create thread in a suspended state
  52. *       thrdaddr = points to an int to receive the ID of the new thread
  53. *
  54. *Exit:
  55. *       *** Same as the Win32 API CreateThread() ***
  56. *
  57. *       success = handle for new thread if successful
  58. *
  59. *       failure = 0 in case of error, errno and _doserrno are set
  60. *
  61. *Exceptions:
  62. *
  63. *Notes:
  64. *       This routine is more like the Win32 API CreateThread() than it
  65. *       is like the C run-time routine _beginthread().  Ditto for
  66. *       _endthreadex() and the Win32 API ExitThread() versus _endthread().
  67. *
  68. *       Differences between _beginthread/_endthread and the "ex" versions:
  69. *
  70. *         1)  _beginthreadex takes the 3 extra parameters to CreateThread
  71. *             which are lacking in _beginthread():
  72. *               A) security descriptor for the new thread
  73. *               B) initial thread state (running/asleep)
  74. *               C) pointer to return ID of newly created thread
  75. *
  76. *         2)  The routine passed to _beginthread() must be __cdecl and has
  77. *             no return code, but the routine passed to _beginthreadex()
  78. *             must be __stdcall and returns a thread exit code.  _endthread
  79. *             likewise takes no parameter and calls ExitThread() with a
  80. *             parameter of zero, but _endthreadex() takes a parameter as
  81. *             thread exit code.
  82. *
  83. *         3)  _endthread implicitly closes the handle to the thread, but
  84. *             _endthreadex does not!
  85. *
  86. *         4)  _beginthread returns -1 for failure, _beginthreadex returns
  87. *             0 for failure (just like CreateThread).
  88. *
  89. *******************************************************************************/
  90.  
  91. unsigned long __cdecl _beginthreadex (
  92.         void *security,
  93.         unsigned stacksize,
  94.         unsigned (__stdcall * initialcode) (void *),
  95.         void * argument,
  96.         unsigned createflag,
  97.         unsigned *thrdaddr
  98.         )
  99. {
  100.         _ptiddata ptd;                  /* pointer to per-thread data */
  101.         unsigned long thdl;             /* thread handle */
  102.         unsigned long errcode = 0L;     /* Return from GetLastError() */
  103.  
  104.         /*
  105.          * Allocate and initialize a per-thread data structure for the to-
  106.          * be-created thread.
  107.          */
  108.         if ( (ptd = _calloc_crt(1, sizeof(struct _tiddata))) == NULL )
  109.                 goto error_return;
  110.  
  111.         /*
  112.          * Initialize the per-thread data
  113.          */
  114.  
  115.         _initptd(ptd);
  116.  
  117.         ptd->_initaddr = (void *) initialcode;
  118.         ptd->_initarg = argument;
  119.         ptd->_thandle = (unsigned long)(-1L);
  120.  
  121.         /*
  122.          * Create the new thread using the parameters supplied by the caller.
  123.          */
  124.         if ( (thdl = (unsigned long)
  125.               CreateThread( security,
  126.                             stacksize,
  127.                             _threadstartex,
  128.                             (LPVOID)ptd,
  129.                             createflag,
  130.                             thrdaddr))
  131.              == 0L )
  132.         {
  133.                 errcode = GetLastError();
  134.                 goto error_return;
  135.         }
  136.  
  137.         /*
  138.          * Good return
  139.          */
  140.         return(thdl);
  141.  
  142.         /*
  143.          * Error return
  144.          */
  145. error_return:
  146.         /*
  147.          * Either ptd is NULL, or it points to the no-longer-necessary block
  148.          * calloc-ed for the _tiddata struct which should now be freed up.
  149.          */
  150.         _free_crt(ptd);
  151.  
  152.         /*
  153.          * Map the error, if necessary.
  154.          *
  155.          * Note: this routine returns 0 for failure, just like the Win32
  156.          * API CreateThread, but _beginthread() returns -1 for failure.
  157.          */
  158.         if ( errcode != 0L )
  159.                 _dosmaperr(errcode);
  160.  
  161.         return((unsigned long)0L);
  162. }
  163.  
  164.  
  165. /***
  166. *_threadstartex() - New thread begins here
  167. *
  168. *Purpose:
  169. *       The new thread begins execution here.  This routine, in turn,
  170. *       passes control to the user's code.
  171. *
  172. *Entry:
  173. *       void *ptd       = pointer to _tiddata structure for this thread
  174. *
  175. *Exit:
  176. *       Never returns - terminates thread!
  177. *
  178. *Exceptions:
  179. *
  180. *******************************************************************************/
  181.  
  182. static unsigned long WINAPI _threadstartex (
  183.         void * ptd
  184.         )
  185. {
  186.         /*
  187.          * Stash the pointer to the per-thread data stucture in TLS
  188.          */
  189.         if ( !TlsSetValue(__tlsindex, ptd) )
  190.                 _amsg_exit(_RT_THREAD);
  191.  
  192.         /*
  193.          * Set the thread ID field -- parent thread cannot set it after
  194.          * CreateThread() returns since the child thread might have run
  195.          * to completion and already freed its per-thread data block!
  196.          */
  197.         ((_ptiddata) ptd)->_tid = GetCurrentThreadId();
  198.  
  199.         /*
  200.          * Call fp initialization, if necessary
  201.          */
  202.         if ( _FPmtinit != NULL )
  203.                 (*_FPmtinit)();
  204.  
  205.         /*
  206.          * Guard call to user code with a _try - _except statement to
  207.          * implement runtime errors and signal support
  208.          */
  209.         __try {
  210.                 _endthreadex (
  211.                     ( (unsigned (WINAPI *)(void *))(((_ptiddata)ptd)->_initaddr) )
  212.                     ( ((_ptiddata)ptd)->_initarg ) ) ;
  213.         }
  214.         __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
  215.         {
  216.                 /*
  217.                  * Should never reach here
  218.                  */
  219.                 _exit( GetExceptionCode() );
  220.  
  221.         } /* end of _try - _except */
  222.  
  223.         /*
  224.          * Never executed!
  225.          */
  226.         return(0L);
  227. }
  228.  
  229.  
  230. /***
  231. *_endthreadex() - Terminate the calling thread
  232. *
  233. *Purpose:
  234. *
  235. *Entry:
  236. *       Thread exit code
  237. *
  238. *Exit:
  239. *       Never returns!
  240. *
  241. *Exceptions:
  242. *
  243. *******************************************************************************/
  244.  
  245. void __cdecl _endthreadex (
  246.         unsigned retcode
  247.         )
  248. {
  249.         _ptiddata ptd;           /* pointer to thread's _tiddata struct */
  250.  
  251.         /*
  252.          * Call fp termination, if necessary
  253.          */
  254.         if ( _FPmtterm != NULL )
  255.                 (*_FPmtterm)();
  256.  
  257.         if ( (ptd = _getptd()) == NULL )
  258.                 _amsg_exit(_RT_THREAD);
  259.  
  260.         /*
  261.          * Free up the _tiddata structure & its subordinate buffers
  262.          *      _freeptd() will also clear the value for this thread
  263.          *      of the TLS variable __tlsindex.
  264.          */
  265.         _freeptd(ptd);
  266.  
  267.         /*
  268.          * Terminate the thread
  269.          */
  270.         ExitThread(retcode);
  271.  
  272. }
  273.  
  274. #endif  /* _MT */
  275.