]> git.saurik.com Git - apple/icu.git/blob - icuSources/test/intltest/simplethread.cpp
ICU-491.11.3.tar.gz
[apple/icu.git] / icuSources / test / intltest / simplethread.cpp
1 /********************************************************************
2 * COPYRIGHT:
3 * Copyright (c) 1999-2011, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 ********************************************************************/
6
7 #if defined(hpux)
8 # ifndef _INCLUDE_POSIX_SOURCE
9 # define _INCLUDE_POSIX_SOURCE
10 # endif
11 #endif
12
13 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
14 #ifndef __EXTENSIONS__
15 #define __EXTENSIONS__
16 #endif
17
18 // Defines _XOPEN_SOURCE for access to POSIX functions.
19 // Must be before any other #includes.
20 #include "uposixdefs.h"
21
22 #include "simplethread.h"
23
24 #include "unicode/utypes.h"
25 #include "unicode/ustring.h"
26 #include "umutex.h"
27 #include "cmemory.h"
28 #include "cstring.h"
29 #include "uparse.h"
30 #include "unicode/resbund.h"
31 #include "unicode/udata.h"
32 #include "unicode/uloc.h"
33 #include "unicode/locid.h"
34 #include "putilimp.h"
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <ctype.h> // tolower, toupper
39
40 #if U_PLATFORM_USES_ONLY_WIN32_API
41 /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */
42 # undef POSIX
43 #elif U_PLATFORM_IMPLEMENTS_POSIX
44 # define POSIX
45 #else
46 # undef POSIX
47 #endif
48
49 /* Needed by z/OS to get usleep */
50 #if U_PLATFORM == U_PF_OS390
51 #define __DOT1 1
52 #define __UU
53 #ifndef _XPG4_2
54 #define _XPG4_2
55 #endif
56 #include <unistd.h>
57 #endif
58
59 #if defined(POSIX)
60 #define HAVE_IMP
61
62 #if (ICU_USE_THREADS == 1)
63 #include <pthread.h>
64 #endif
65
66 #if defined(__hpux) && defined(HPUX_CMA)
67 # if defined(read) // read being defined as cma_read causes trouble with iostream::read
68 # undef read
69 # endif
70 #endif
71
72 #if U_PLATFORM == U_PF_OS390
73 #include <sys/types.h>
74 #endif
75
76 #if U_PLATFORM != U_PF_OS390
77 #include <signal.h>
78 #endif
79
80 /* Define _XPG4_2 for Solaris and friends. */
81 #ifndef _XPG4_2
82 #define _XPG4_2
83 #endif
84
85 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
86 #ifndef __USE_XOPEN_EXTENDED
87 #define __USE_XOPEN_EXTENDED
88 #endif
89
90 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
91 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
92 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
93 #endif
94
95 #include <unistd.h>
96
97 #endif
98 /* HPUX */
99 #ifdef sleep
100 #undef sleep
101 #endif
102
103
104 #if (ICU_USE_THREADS==0)
105 SimpleThread::SimpleThread()
106 {}
107
108 SimpleThread::~SimpleThread()
109 {}
110
111 int32_t
112 SimpleThread::start()
113 { return -1; }
114
115 void
116 SimpleThread::run()
117 {}
118
119 void
120 SimpleThread::sleep(int32_t millis)
121 {}
122
123 UBool
124 SimpleThread::isRunning() {
125 return FALSE;
126 }
127 #else
128
129 #include "unicode/putil.h"
130
131 /* for mthreadtest*/
132 #include "unicode/numfmt.h"
133 #include "unicode/choicfmt.h"
134 #include "unicode/msgfmt.h"
135 #include "unicode/locid.h"
136 #include "unicode/ucol.h"
137 #include "unicode/calendar.h"
138 #include "ucaconf.h"
139
140 #if U_PLATFORM_USES_ONLY_WIN32_API
141 #define HAVE_IMP
142
143 # define VC_EXTRALEAN
144 # define WIN32_LEAN_AND_MEAN
145 # define NOUSER
146 # define NOSERVICE
147 # define NOIME
148 # define NOMCX
149 #include <windows.h>
150 #include <process.h>
151
152 //-----------------------------------------------------------------------------------
153 //
154 // class SimpleThread Windows Implementation
155 //
156 //-----------------------------------------------------------------------------------
157 struct Win32ThreadImplementation
158 {
159 HANDLE fHandle;
160 unsigned int fThreadID;
161 };
162
163
164 extern "C" unsigned int __stdcall SimpleThreadProc(void *arg)
165 {
166 ((SimpleThread*)arg)->run();
167 return 0;
168 }
169
170 SimpleThread::SimpleThread()
171 :fImplementation(0)
172 {
173 Win32ThreadImplementation *imp = new Win32ThreadImplementation;
174 imp->fHandle = 0;
175 fImplementation = imp;
176 }
177
178 SimpleThread::~SimpleThread()
179 {
180 // Destructor. Because we start the thread running with _beginthreadex(),
181 // we own the Windows HANDLE for the thread and must
182 // close it here.
183 Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
184 if (imp != 0) {
185 if (imp->fHandle != 0) {
186 CloseHandle(imp->fHandle);
187 imp->fHandle = 0;
188 }
189 }
190 delete (Win32ThreadImplementation*)fImplementation;
191 }
192
193 int32_t SimpleThread::start()
194 {
195 Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
196 if(imp->fHandle != NULL) {
197 // The thread appears to have already been started.
198 // This is probably an error on the part of our caller.
199 return -1;
200 }
201
202 imp->fHandle = (HANDLE) _beginthreadex(
203 NULL, // Security
204 0x20000, // Stack Size
205 SimpleThreadProc, // Function to Run
206 (void *)this, // Arg List
207 0, // initflag. Start running, not suspended
208 &imp->fThreadID // thraddr
209 );
210
211 if (imp->fHandle == 0) {
212 // An error occured
213 int err = errno;
214 if (err == 0) {
215 err = -1;
216 }
217 return err;
218 }
219 return 0;
220 }
221
222
223 UBool SimpleThread::isRunning() {
224 //
225 // Test whether the thread associated with the SimpleThread object is
226 // still actually running.
227 //
228 // NOTE: on Win64 on Itanium processors, a crashes
229 // occur if the main thread of a process exits concurrently with some
230 // other thread(s) exiting. To avoid the possibility, we wait until the
231 // OS indicates that all threads have terminated, rather than waiting
232 // only until the end of the user's Run function has been reached.
233 //
234 // I don't know whether the crashes represent a Windows bug, or whether
235 // main() programs are supposed to have to wait for their threads.
236 //
237 Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
238
239 bool success;
240 DWORD threadExitCode;
241
242 if (imp->fHandle == 0) {
243 // No handle, thread must not be running.
244 return FALSE;
245 }
246 success = GetExitCodeThread(imp->fHandle, &threadExitCode) != 0;
247 if (! success) {
248 // Can't get status, thread must not be running.
249 return FALSE;
250 }
251 return (threadExitCode == STILL_ACTIVE);
252 }
253
254
255 void SimpleThread::sleep(int32_t millis)
256 {
257 ::Sleep(millis);
258 }
259
260 //-----------------------------------------------------------------------------------
261 //
262 // class SimpleThread NULL Implementation
263 //
264 //-----------------------------------------------------------------------------------
265 #elif U_PLATFORM == U_PF_CLASSIC_MACOS
266
267 // since the Mac has no preemptive threading (at least on MacOS 8), only
268 // cooperative threading, threads are a no-op. We have no yield() calls
269 // anywhere in the ICU, so we are guaranteed to be thread-safe.
270
271 #define HAVE_IMP
272
273 SimpleThread::SimpleThread()
274 {}
275
276 SimpleThread::~SimpleThread()
277 {}
278
279 int32_t
280 SimpleThread::start()
281 { return 0; }
282
283 void
284 SimpleThread::run()
285 {}
286
287 void
288 SimpleThread::sleep(int32_t millis)
289 {}
290
291 UBool
292 SimpleThread::isRunning() {
293 return FALSE;
294 }
295
296 #endif
297
298
299 //-----------------------------------------------------------------------------------
300 //
301 // class SimpleThread POSIX implementation
302 //
303 // A note on the POSIX vs the Windows implementations of this class..
304 // On Windows, the main thread must verify that other threads have finished
305 // before exiting, or crashes occasionally occur. (Seen on Itanium Win64 only)
306 // The function SimpleThread::isRunning() is used for this purpose.
307 //
308 // On POSIX, there is NO reliable non-blocking mechanism to determine
309 // whether a thread has exited. pthread_kill(thread, 0) almost works,
310 // but the system can recycle thread ids immediately, so seeing that a
311 // thread exists with this call could mean that the original thread has
312 // finished and a new one started with the same ID. Useless.
313 //
314 // So we need to do the check with user code, by setting a flag just before
315 // the thread function returns. A technique that is guaranteed to fail
316 // on Windows, because it indicates that the thread is done before all
317 // system level cleanup has happened.
318 //
319 //-----------------------------------------------------------------------------------
320 #if defined(POSIX)
321 #define HAVE_IMP
322
323 struct PosixThreadImplementation
324 {
325 pthread_t fThread;
326 UBool fRunning;
327 UBool fRan; // True if the thread was successfully started
328 };
329
330 extern "C" void* SimpleThreadProc(void *arg)
331 {
332 // This is the code that is run in the new separate thread.
333 SimpleThread *This = (SimpleThread *)arg;
334 This->run(); // Run the user code.
335
336 // The user function has returned. Set the flag indicating that this thread
337 // is done. Need a mutex for memory barrier purposes only, so that other thread
338 // will reliably see that the flag has changed.
339 PosixThreadImplementation *imp = (PosixThreadImplementation*)This->fImplementation;
340 umtx_lock(NULL);
341 imp->fRunning = FALSE;
342 umtx_unlock(NULL);
343 return 0;
344 }
345
346 SimpleThread::SimpleThread()
347 {
348 PosixThreadImplementation *imp = new PosixThreadImplementation;
349 imp->fRunning = FALSE;
350 imp->fRan = FALSE;
351 fImplementation = imp;
352 }
353
354 SimpleThread::~SimpleThread()
355 {
356 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
357 if (imp->fRan) {
358 pthread_join(imp->fThread, NULL);
359 }
360 delete imp;
361 fImplementation = (void *)0xdeadbeef;
362 }
363
364 int32_t SimpleThread::start()
365 {
366 int32_t rc;
367 static pthread_attr_t attr;
368 static UBool attrIsInitialized = FALSE;
369
370 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
371 imp->fRunning = TRUE;
372 imp->fRan = TRUE;
373
374 #ifdef HPUX_CMA
375 if (attrIsInitialized == FALSE) {
376 rc = pthread_attr_create(&attr);
377 attrIsInitialized = TRUE;
378 }
379 rc = pthread_create(&(imp->fThread),attr,&SimpleThreadProc,(void*)this);
380 #else
381 if (attrIsInitialized == FALSE) {
382 rc = pthread_attr_init(&attr);
383 #if U_PLATFORM == U_PF_OS390
384 {
385 int detachstate = 0; // jdc30: detach state of zero causes
386 //threads created with this attr to be in
387 //an undetached state. An undetached
388 //thread will keep its resources after
389 //termination.
390 pthread_attr_setdetachstate(&attr, &detachstate);
391 }
392 #else
393 // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
394 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
395 #endif
396 attrIsInitialized = TRUE;
397 }
398 rc = pthread_create(&(imp->fThread),&attr,&SimpleThreadProc,(void*)this);
399 #endif
400
401 if (rc != 0) {
402 // some kind of error occured, the thread did not start.
403 imp->fRan = FALSE;
404 imp->fRunning = FALSE;
405 }
406
407 return rc;
408 }
409
410
411 UBool
412 SimpleThread::isRunning() {
413 // Note: Mutex functions are used here not for synchronization,
414 // but to force memory barriors to exist, to ensure that one thread
415 // can see changes made by another when running on processors
416 // with memory models having weak coherency.
417 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
418 umtx_lock(NULL);
419 UBool retVal = imp->fRunning;
420 umtx_unlock(NULL);
421 return retVal;
422 }
423
424
425 void SimpleThread::sleep(int32_t millis)
426 {
427 #if U_PLATFORM == U_PF_SOLARIS
428 sigignore(SIGALRM);
429 #endif
430
431 #ifdef HPUX_CMA
432 cma_sleep(millis/100);
433 #elif U_PLATFORM == U_PF_HPUX || U_PLATFORM == U_PF_OS390
434 millis *= 1000;
435 while(millis >= 1000000) {
436 usleep(999999);
437 millis -= 1000000;
438 }
439 if(millis > 0) {
440 usleep(millis);
441 }
442 #else
443 usleep(millis * 1000);
444 #endif
445 }
446
447 #endif
448 // end POSIX
449
450
451 #ifndef HAVE_IMP
452 #error No implementation for threads! Cannot test.
453 0 = 216; //die
454 #endif
455
456 //-------------------------------------------------------------------------------------------
457 //
458 // class ThreadWithStatus - a thread that we can check the status and error condition of
459 //
460 //-------------------------------------------------------------------------------------------
461 class ThreadWithStatus : public SimpleThread
462 {
463 public:
464 UBool getError() { return (fErrors > 0); }
465 UBool getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); }
466 virtual ~ThreadWithStatus(){}
467 protected:
468 ThreadWithStatus() : fErrors(0) {}
469 void error(const UnicodeString &error) {
470 fErrors++; fErrorString = error;
471 SimpleThread::errorFunc();
472 }
473 void error() { error("An error occured."); }
474 private:
475 int32_t fErrors;
476 UnicodeString fErrorString;
477 };
478
479 #endif // ICU_USE_THREADS