summaryrefslogtreecommitdiffstats
path: root/private/crt32/startup/thread.c
blob: 5878eecc78ae9ae3bd33341a6882f19c158a8264 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#ifdef MTHREAD


/***
*thread.c - Being and end a thread
*
*	Copyright (c) 1989-1993, 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-27-93  GJF	Removed support for _RT_STACK, _RT_INTDIV,
*			_RT_INVALDISP and _RT_NONCONT.
*	12-14-93  SKS	Free up per-thread data using a call to _freeptd()
*
*******************************************************************************/

#include <cruntime.h>
#include <oscalls.h>
#include <internal.h>
#include <os2dll.h>
#include <msdos.h>
#include <malloc.h>
#include <process.h>
#include <rterr.h>

/*
 * Startup code for new thread.
 */
static unsigned long WINAPI _threadstart(void *);

/*
 * useful type for initialization and termination declarations
 */
typedef void (_CRTAPI1 *PF)(void);

/*
 * declare pointers to per-thread FP initialization and termination routines
 */
PF _FPmtinit;
PF _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:
*
*******************************************************************************/

unsigned long _CRTAPI1 _beginthread (
	void (_CRTAPI1 * initialcode) (void *),
	unsigned stacksize,
	void * argument
	)
{
	_ptiddata ptd;			/* pointer to per-thread data */
	unsigned long thdl;		/* thread handle */

	/*
	 * Allocate and initialize a per-thread data structure for the to-
	 * be-created thread.
	 */
	if ( (ptd = calloc(1, sizeof(struct _tiddata))) == NULL )
		goto error_return;

	ptd->_initaddr = (void *) initialcode;
	ptd->_initarg = argument;
	ptd->_holdrand = 1L;
	ptd->_pxcptacttab = (void *)_XcptActTab;

	/*
	 * 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 = (unsigned long)
	      CreateThread( NULL,
			    stacksize,
			    _threadstart,
			    (LPVOID)ptd,
			    CREATE_SUSPENDED,
			    (LPDWORD)&(ptd->_tid) ))
	     == 0L )
		goto error_return;

	/*
	 * Start the new thread executing
	 */
	if ( ResumeThread( (HANDLE)thdl ) == (DWORD)(-1L) )
		goto error_return;

	/*
	 * Good return
	 */
	return(thdl);

	/*
	 * Error return
	 */
error_return:
	/***
	 *** MAP ERROR CODE!
	 ***/
	return((unsigned long)-1L);
}


/***
*_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
	)
{
	/*
	 * Stash the pointer to the per-thread data stucture in TLS
	 */
	if ( !TlsSetValue(__tlsindex, ptd) )
		_amsg_exit(_RT_THREAD);

	/*
	 * 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(_CRTAPI1 *)(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 _CRTAPI1 _endthread (
	void
	)
{
	_ptiddata ptd;		 /* pointer to thread's _tiddata struct */

	/*
	 * Call fp termination, if necessary
	 */
	if ( _FPmtterm != NULL )
		(*_FPmtterm)();

	if ( (ptd = _getptd()) == NULL )
		_amsg_exit(_RT_THREAD);

	/*
	 * Close the thread handle (if there was one)
	 */
	if ( ptd->_thandle != (unsigned long)(-1L) )
		(void) CloseHandle( (HANDLE)(ptd->_thandle) );

	/*
	 * Free up the _tiddata structure & its subordinate buffers
	 *	_freeptd() will also clear the value for this thread
	 *	of the TLS variable __tlsindex.
	 */
	_freeptd(ptd);

	/*
	 * Terminate the thread
	 */
	ExitThread(0);

}

#endif  /* MTHREAD */