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