Home | History | Annotate | Download | only in intltest
      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
    481