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

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

testapp: threads: Modified to be able to easily reproduce the hang on SMP (by e.g. hitting Ctrl-Break before the normal program termination).

  • Property svn:eol-style set to native
File size: 5.4 KB
Line 
1/*
2 * Taken from here http://msdn.microsoft.com/en-us/library/ms682516%28v=VS.85%29.aspx
3 * and slightly modified to compile with Odin
4 */
5
6#include <windows.h>
7#include <tchar.h>
8
9#define MAX_THREADS 10
10#define BUF_SIZE 255
11
12#ifdef _MSC_VER
13#include <strsafe.h>
14#else
15#include <stdarg.h>
16void StringCchPrintf(LPTSTR pszDest, size_t cchDest,
17 LPCTSTR pszFormat, ...);
18void StringCchLength(LPCTSTR psz, size_t cchMax, size_t *pcch);
19#endif
20
21DWORD WINAPI MyThreadFunction( LPVOID lpParam );
22void ErrorHandler(LPTSTR lpszFunction);
23
24// Sample custom data structure for threads to use.
25// This is passed by void pointer so it can be any data type
26// that can be passed using a single void pointer (LPVOID).
27typedef struct MyData {
28 int val1;
29 int val2;
30} MYDATA, *PMYDATA;
31
32#ifndef _MSC_VER
33
34void StringCchPrintf(LPTSTR pszDest, size_t cchDest,
35 LPCTSTR pszFormat, ...)
36{
37 va_list ap;
38
39 va_start(ap, pszFormat);
40 vsnprintf(pszDest, cchDest, pszFormat, ap);
41 va_end(ap);
42}
43
44void StringCchLength(LPCTSTR psz, size_t cchMax, size_t *pcch)
45{
46 *pcch = strnlen(psz, cchMax);
47}
48
49#endif
50
51int _tmain()
52{
53 PMYDATA pDataArray[MAX_THREADS];
54 DWORD dwThreadIdArray[MAX_THREADS];
55 HANDLE hThreadArray[MAX_THREADS];
56
57 // Create MAX_THREADS worker threads.
58
59 int i;
60 for( i=0; i<MAX_THREADS; i++ )
61 {
62 // Allocate memory for thread data.
63
64 pDataArray[i] = (PMYDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
65 sizeof(MYDATA));
66
67 if( pDataArray[i] == NULL )
68 {
69 // If the array allocation fails, the system is out of memory
70 // so there is no point in trying to print an error message.
71 // Just terminate execution.
72 ExitProcess(2);
73 }
74
75 // Generate unique data for each thread to work with.
76
77 pDataArray[i]->val1 = i;
78 pDataArray[i]->val2 = i+100;
79
80 // Create the thread to begin execution on its own.
81
82 hThreadArray[i] = CreateThread(
83 NULL, // default security attributes
84 0, // use default stack size
85 MyThreadFunction, // thread function name
86 pDataArray[i], // argument to thread function
87 0, // use default creation flags
88 &dwThreadIdArray[i]); // returns the thread identifier
89
90
91 // Check the return value for success.
92 // If CreateThread fails, terminate execution.
93 // This will automatically clean up threads and memory.
94
95 if (hThreadArray[i] == NULL)
96 {
97 ErrorHandler(TEXT("CreateThread"));
98 ExitProcess(3);
99 }
100 } // End of main thread creation loop.
101
102#ifndef _MSC_VER
103 printf("Started %d threads. Waiting for them to terminate...\n", MAX_THREADS);
104#endif
105
106 // Wait until all threads have terminated.
107
108 WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);
109
110#ifndef _MSC_VER
111 printf("All threads terminated.\n");
112#endif
113
114 // Close all thread handles and free memory allocations.
115
116 for(i=0; i<MAX_THREADS; i++)
117 {
118 CloseHandle(hThreadArray[i]);
119 if(pDataArray[i] != NULL)
120 {
121 HeapFree(GetProcessHeap(), 0, pDataArray[i]);
122 pDataArray[i] = NULL; // Ensure address is not reused.
123 }
124 }
125
126 return 0;
127}
128
129
130DWORD WINAPI MyThreadFunction( LPVOID lpParam )
131{
132 HANDLE hStdout;
133 PMYDATA pDataArray;
134
135 TCHAR msgBuf[BUF_SIZE];
136 size_t cchStringSize;
137 DWORD dwChars;
138
139 // Make sure there is a console to receive output results.
140
141 hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
142 if( hStdout == INVALID_HANDLE_VALUE )
143 return 1;
144
145 // Cast the parameter to the correct data type.
146 // The pointer is known to be valid because
147 // it was checked for NULL before the thread was created.
148
149 pDataArray = (PMYDATA)lpParam;
150
151 // Print the parameter values using thread-safe functions.
152
153 Sleep(1000 * pDataArray->val1 / 2);
154
155 StringCchPrintf(msgBuf, BUF_SIZE, TEXT("Parameters = %d, %d\n"),
156 pDataArray->val1, pDataArray->val2);
157 StringCchLength(msgBuf, BUF_SIZE, &cchStringSize);
158#ifdef _MSC_VER
159 WriteConsole(hStdout, msgBuf, (DWORD)cchStringSize, &dwChars, NULL);
160#else
161 // WriteConsole seems to be a stub in Odin yet
162 printf("%s", msgBuf);
163#endif
164
165#if 0
166 // crash the application
167 if (pDataArray->val1 == 6)
168 {
169 *((int*)0) = 0;
170 }
171#endif
172
173 return 0;
174}
175
176
177
178void ErrorHandler(LPTSTR lpszFunction)
179{
180 // Retrieve the system error message for the last-error code.
181
182 LPVOID lpMsgBuf;
183 LPVOID lpDisplayBuf;
184 DWORD dw = GetLastError();
185
186 FormatMessage(
187 FORMAT_MESSAGE_ALLOCATE_BUFFER |
188 FORMAT_MESSAGE_FROM_SYSTEM |
189 FORMAT_MESSAGE_IGNORE_INSERTS,
190 NULL,
191 dw,
192 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
193 (LPTSTR) &lpMsgBuf,
194 0, NULL );
195
196 // Display the error message.
197
198 lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
199 (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) lpszFunction) + 40) * sizeof(TCHAR));
200 StringCchPrintf((LPTSTR)lpDisplayBuf,
201 LocalSize(lpDisplayBuf) / sizeof(TCHAR),
202 TEXT("%s failed with error %d: %s"),
203 lpszFunction, dw, lpMsgBuf);
204 MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK);
205
206 // Free error-handling buffer allocations.
207
208 LocalFree(lpMsgBuf);
209 LocalFree(lpDisplayBuf);
210}
211
Note: See TracBrowser for help on using the repository browser.