• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)
SimpleThread()106     SimpleThread::SimpleThread()
107     {}
108 
~SimpleThread()109     SimpleThread::~SimpleThread()
110     {}
111 
112     int32_t
start()113     SimpleThread::start()
114     { return -1; }
115 
116     void
run()117     SimpleThread::run()
118     {}
119 
120     void
sleep(int32_t millis)121     SimpleThread::sleep(int32_t millis)
122     {}
123 
124     UBool
isRunning()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 
SimpleThreadProc(void * arg)165 extern "C" unsigned int __stdcall SimpleThreadProc(void *arg)
166 {
167     ((SimpleThread*)arg)->run();
168     return 0;
169 }
170 
SimpleThread()171 SimpleThread::SimpleThread()
172 :fImplementation(0)
173 {
174     Win32ThreadImplementation *imp = new Win32ThreadImplementation;
175     imp->fHandle = 0;
176     fImplementation = imp;
177 }
178 
~SimpleThread()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 
start()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 
isRunning()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 
sleep(int32_t millis)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 
SimpleThread()274 SimpleThread::SimpleThread()
275 {}
276 
~SimpleThread()277 SimpleThread::~SimpleThread()
278 {}
279 
280 int32_t
start()281 SimpleThread::start()
282 { return 0; }
283 
284 void
run()285 SimpleThread::run()
286 {}
287 
288 void
sleep(int32_t millis)289 SimpleThread::sleep(int32_t millis)
290 {}
291 
292 UBool
isRunning()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 
SimpleThreadProc(void * arg)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 
SimpleThread()347 SimpleThread::SimpleThread()
348 {
349     PosixThreadImplementation *imp = new PosixThreadImplementation;
350     imp->fRunning   = FALSE;
351     imp->fRan       = FALSE;
352     fImplementation = imp;
353 }
354 
~SimpleThread()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 
start()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
isRunning()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 
sleep(int32_t millis)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:
getError()465     UBool  getError() { return (fErrors > 0); }
getError(UnicodeString & fillinError)466     UBool  getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); }
~ThreadWithStatus()467     virtual ~ThreadWithStatus(){}
468 protected:
ThreadWithStatus()469     ThreadWithStatus() :  fErrors(0) {}
error(const UnicodeString & error)470     void error(const UnicodeString &error) {
471         fErrors++; fErrorString = error;
472         SimpleThread::errorFunc();
473     }
error()474     void error() { error("An error occured."); }
475 private:
476     int32_t fErrors;
477     UnicodeString fErrorString;
478 };
479 
480 #endif // ICU_USE_THREADS
481