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

Last change on this file since 21999 was 21999, checked in by dmik, 13 years ago

kernel32: Make SEH work in OS/2 context.

See #82 for details.

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