source: trunk/testapp/threads/threads.c@ 21614

Last change on this file since 21614 was 21614, checked in by dmik, 14 years ago

testapp/threads: Updated to properly trigger the hanging behavior (#28).

  • Property svn:eol-style set to native
File size: 6.2 KB
Line 
1/*
2 * Taken from here http://msdn.microsoft.com/en-us/library/ms682516%28v=VS.85%29.aspx
3 * and modified for the needs of the testcase
4 */
5
6//#define USE_TRY
7
8#if !defined(_MSC_VER) && 1
9#define INCL_DOS
10#include <os2wrap2.h>
11#endif
12
13#include <windows.h>
14#include <tchar.h>
15#include <excpt.h>
16
17#define MAX_THREADS 10
18#define BUF_SIZE 255
19
20#ifdef _MSC_VER
21#include <strsafe.h>
22#else
23#include <stdarg.h>
24void StringCchPrintf(LPTSTR pszDest, size_t cchDest,
25 LPCTSTR pszFormat, ...);
26void StringCchLength(LPCTSTR psz, size_t cchMax, size_t *pcch);
27#endif
28
29DWORD WINAPI MyThreadFunction( LPVOID lpParam );
30void ErrorHandler(LPTSTR lpszFunction);
31
32// Sample custom data structure for threads to use.
33// This is passed by void pointer so it can be any data type
34// that can be passed using a single void pointer (LPVOID).
35typedef struct MyData {
36 int val1;
37 int val2;
38} MYDATA, *PMYDATA;
39
40#ifndef _MSC_VER
41
42// register the EXE to cause the OS/2 exception handler setup around
43// the entry point
44
45#include <odinlx.h>
46
47#undef _tmain
48int _tmain();
49
50int APIENTRY WinMain(HINSTANCE hInstance,
51 HINSTANCE hPrevInstance,
52 LPTSTR lpCmdLine,
53 int nCmdShow)
54{
55 return _tmain();
56}
57
58int main(int argc, char **argv)
59{
60 EnableSEH();
61 RegisterLxExe((WINMAIN)WinMain, NULL);
62 return _tmain();
63}
64
65void StringCchPrintf(LPTSTR pszDest, size_t cchDest,
66 LPCTSTR pszFormat, ...)
67{
68 va_list ap;
69
70 va_start(ap, pszFormat);
71 vsnprintf(pszDest, cchDest, pszFormat, ap);
72 va_end(ap);
73}
74
75void StringCchLength(LPCTSTR psz, size_t cchMax, size_t *pcch)
76{
77 *pcch = strnlen(psz, cchMax);
78}
79
80#endif // !_MSC_VER
81
82int _tmain()
83{
84 PMYDATA pDataArray[MAX_THREADS];
85 DWORD dwThreadIdArray[MAX_THREADS];
86 HANDLE hThreadArray[MAX_THREADS];
87
88 // Create MAX_THREADS worker threads.
89
90 int i;
91 for( i=0; i<MAX_THREADS; i++ )
92 {
93 // Allocate memory for thread data.
94
95 pDataArray[i] = (PMYDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
96 sizeof(MYDATA));
97
98 if( pDataArray[i] == NULL )
99 {
100 // If the array allocation fails, the system is out of memory
101 // so there is no point in trying to print an error message.
102 // Just terminate execution.
103 ExitProcess(2);
104 }
105
106 // Generate unique data for each thread to work with.
107
108 pDataArray[i]->val1 = i;
109 pDataArray[i]->val2 = i+100;
110
111 // Create the thread to begin execution on its own.
112
113 hThreadArray[i] = CreateThread(
114 NULL, // default security attributes
115 0, // use default stack size
116 MyThreadFunction, // thread function name
117 pDataArray[i], // argument to thread function
118 0, // use default creation flags
119 &dwThreadIdArray[i]); // returns the thread identifier
120
121
122 // Check the return value for success.
123 // If CreateThread fails, terminate execution.
124 // This will automatically clean up threads and memory.
125
126 if (hThreadArray[i] == NULL)
127 {
128 ErrorHandler(TEXT("CreateThread"));
129 ExitProcess(3);
130 }
131 } // End of main thread creation loop.
132
133 _tprintf(TEXT("Started %d threads. Waiting for them to terminate...\n"),
134 MAX_THREADS);
135
136 // Wait until some threads have terminated.
137
138 WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, 2000);
139
140 _tprintf(TEXT("Finished waiting.\n"));
141
142 // Close all thread handles and free memory allocations.
143
144 for(i=0; i<MAX_THREADS; i++)
145 {
146 CloseHandle(hThreadArray[i]);
147 if(pDataArray[i] != NULL)
148 {
149 HeapFree(GetProcessHeap(), 0, pDataArray[i]);
150 pDataArray[i] = NULL; // Ensure address is not reused.
151 }
152 }
153
154#if !defined(_MSC_VER) && 1
155 DosExit(1, 0);
156#endif
157
158 return 0;
159}
160
161#ifdef USE_TRY
162int exc_filter(DWORD code, PEXCEPTION_POINTERS pPtrs)
163{
164 PEXCEPTION_RECORD pRec = pPtrs->ExceptionRecord;
165
166#ifndef _MSC_VER
167 os2_PPIB pPib;
168 os2_PTIB pTib;
169 DosGetInfoBlocks(&pTib, &pPib);
170 printf("TID: %d\n", pTib->tib_ptib2->tib2_ultid);
171#endif
172
173 _tprintf(TEXT("Filter: code %08lx\n"), code);
174 _tprintf(TEXT("ExceptionCode %p\n"), pRec->ExceptionCode);
175 _tprintf(TEXT("ExceptionAddress %p\n"), pRec->ExceptionAddress);
176 _tprintf(TEXT("NumberParameters %d\n"), pRec->NumberParameters);
177
178 return EXCEPTION_CONTINUE_SEARCH;
179}
180#endif
181
182DWORD WINAPI MyThreadFunction( LPVOID lpParam )
183{
184 PMYDATA pDataArray;
185
186 TCHAR msgBuf[BUF_SIZE];
187 size_t cchStringSize;
188 DWORD dwChars;
189
190#ifdef USE_TRY
191 __try
192 {
193#endif
194 // Cast the parameter to the correct data type.
195 // The pointer is known to be valid because
196 // it was checked for NULL before the thread was created.
197
198 pDataArray = (PMYDATA)lpParam;
199
200 // Print the parameter values using thread-safe functions.
201
202 Sleep(1000 * pDataArray->val1 / 2);
203
204#if 0
205 StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d\n"),
206 pDataArray->val1, pDataArray->val2);
207 _tprintf("%s", msgBuf);
208#endif
209
210#ifdef USE_TRY
211 }
212 __except(exc_filter(exception_code(), exception_info()))
213 {
214 }
215#endif
216
217 return 0;
218}
219
220void ErrorHandler(LPTSTR lpszFunction)
221{
222 // Retrieve the system error message for the last-error code.
223
224 LPVOID lpMsgBuf;
225 LPVOID lpDisplayBuf;
226 DWORD dw = GetLastError();
227
228 FormatMessage(
229 FORMAT_MESSAGE_ALLOCATE_BUFFER |
230 FORMAT_MESSAGE_FROM_SYSTEM |
231 FORMAT_MESSAGE_IGNORE_INSERTS,
232 NULL,
233 dw,
234 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
235 (LPTSTR) &lpMsgBuf,
236 0, NULL );
237
238 // Display the error message.
239
240 lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
241 (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) lpszFunction) + 40) * sizeof(TCHAR));
242 StringCchPrintf((LPTSTR)lpDisplayBuf,
243 LocalSize(lpDisplayBuf) / sizeof(TCHAR),
244 TEXT("%s failed with error %d: %s"),
245 lpszFunction, dw, lpMsgBuf);
246 MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK);
247
248 // Free error-handling buffer allocations.
249
250 LocalFree(lpMsgBuf);
251 LocalFree(lpDisplayBuf);
252}
253
Note: See TracBrowser for help on using the repository browser.