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