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