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