source: trunk/testapp/threads/threads.c

Last change on this file 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
RevLine 
[21518]1/*
2 * Taken from here http://msdn.microsoft.com/en-us/library/ms682516%28v=VS.85%29.aspx
[21614]3 * and modified for the needs of the testcase
[21518]4 */
5
[21614]6//#define USE_TRY
7
8#if !defined(_MSC_VER) && 1
9#define INCL_DOS
10#include <os2wrap2.h>
11#endif
12
[21518]13#include <windows.h>
14#include <tchar.h>
[21614]15#include <excpt.h>
[21518]16
17#define MAX_THREADS 10
18#define BUF_SIZE 255
19
20#ifdef _MSC_VER
21#include <strsafe.h>
22#else
[21916]23#include <stdio.h>
[21518]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
[21614]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{
[21999]61#ifdef ODIN_FORCE_WIN32_TIB
62 ForceWin32TIB();
63#endif
[21614]64 RegisterLxExe((WINMAIN)WinMain, NULL);
65 return _tmain();
66}
67
[21518]68void StringCchPrintf(LPTSTR pszDest, size_t cchDest,
69 LPCTSTR pszFormat, ...)
70{
71 va_list ap;
[21614]72
[21518]73 va_start(ap, pszFormat);
74 vsnprintf(pszDest, cchDest, pszFormat, ap);
[21614]75 va_end(ap);
[21518]76}
77
78void StringCchLength(LPCTSTR psz, size_t cchMax, size_t *pcch)
79{
80 *pcch = strnlen(psz, cchMax);
81}
82
[21614]83#endif // !_MSC_VER
[21518]84
85int _tmain()
86{
87 PMYDATA pDataArray[MAX_THREADS];
88 DWORD dwThreadIdArray[MAX_THREADS];
[21614]89 HANDLE hThreadArray[MAX_THREADS];
[21518]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
[21614]116 hThreadArray[i] = CreateThread(
[21518]117 NULL, // default security attributes
[21614]118 0, // use default stack size
[21518]119 MyThreadFunction, // thread function name
[21614]120 pDataArray[i], // argument to thread function
121 0, // use default creation flags
122 &dwThreadIdArray[i]); // returns the thread identifier
[21518]123
124
125 // Check the return value for success.
[21614]126 // If CreateThread fails, terminate execution.
127 // This will automatically clean up threads and memory.
[21518]128
[21614]129 if (hThreadArray[i] == NULL)
[21518]130 {
131 ErrorHandler(TEXT("CreateThread"));
132 ExitProcess(3);
133 }
134 } // End of main thread creation loop.
135
[21614]136 _tprintf(TEXT("Started %d threads. Waiting for them to terminate...\n"),
137 MAX_THREADS);
[21518]138
[21614]139 // Wait until some threads have terminated.
[21518]140
[21614]141 WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, 2000);
142
143 _tprintf(TEXT("Finished waiting.\n"));
144
[21518]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
[21614]157#if !defined(_MSC_VER) && 1
158 DosExit(1, 0);
159#endif
160
[21518]161 return 0;
162}
163
[21614]164#ifdef USE_TRY
165int exc_filter(DWORD code, PEXCEPTION_POINTERS pPtrs)
166{
167 PEXCEPTION_RECORD pRec = pPtrs->ExceptionRecord;
[21518]168
[21614]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{
[21518]187 PMYDATA pDataArray;
188
189 TCHAR msgBuf[BUF_SIZE];
190 size_t cchStringSize;
191 DWORD dwChars;
192
[21614]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.
[21518]200
[21614]201 pDataArray = (PMYDATA)lpParam;
[21518]202
[21614]203 // Print the parameter values using thread-safe functions.
[21518]204
[21614]205 Sleep(1000 * pDataArray->val1 / 2);
[21518]206
[21614]207#if 0
208 StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d\n"),
209 pDataArray->val1, pDataArray->val2);
210 _tprintf("%s", msgBuf);
211#endif
[21608]212
[21614]213#ifdef USE_TRY
214 }
215 __except(exc_filter(exception_code(), exception_info()))
[21608]216 {
217 }
218#endif
219
[21614]220 return 0;
221}
[21518]222
[21614]223void ErrorHandler(LPTSTR lpszFunction)
224{
[21518]225 // Retrieve the system error message for the last-error code.
226
227 LPVOID lpMsgBuf;
228 LPVOID lpDisplayBuf;
[21614]229 DWORD dw = GetLastError();
[21518]230
231 FormatMessage(
[21614]232 FORMAT_MESSAGE_ALLOCATE_BUFFER |
[21518]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
[21614]243 lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
244 (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) lpszFunction) + 40) * sizeof(TCHAR));
245 StringCchPrintf((LPTSTR)lpDisplayBuf,
[21916]246 LocalSize((HLOCAL)lpDisplayBuf) / sizeof(TCHAR),
[21614]247 TEXT("%s failed with error %d: %s"),
248 lpszFunction, dw, lpMsgBuf);
249 MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK);
[21518]250
251 // Free error-handling buffer allocations.
252
[21916]253 LocalFree((HLOCAL)lpMsgBuf);
254 LocalFree((HLOCAL)lpDisplayBuf);
[21518]255}
256
Note: See TracBrowser for help on using the repository browser.