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//----------------------------------------------------------------------------------- 158struct Win32ThreadImplementation 159{ 160 HANDLE fHandle; 161 unsigned int fThreadID; 162}; 163 164 165extern "C" unsigned int __stdcall SimpleThreadProc(void *arg) 166{ 167 ((SimpleThread*)arg)->run(); 168 return 0; 169} 170 171SimpleThread::SimpleThread() 172:fImplementation(0) 173{ 174 Win32ThreadImplementation *imp = new Win32ThreadImplementation; 175 imp->fHandle = 0; 176 fImplementation = imp; 177} 178 179SimpleThread::~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 194int32_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 224UBool 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 256void 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 274SimpleThread::SimpleThread() 275{} 276 277SimpleThread::~SimpleThread() 278{} 279 280int32_t 281SimpleThread::start() 282{ return 0; } 283 284void 285SimpleThread::run() 286{} 287 288void 289SimpleThread::sleep(int32_t millis) 290{} 291 292UBool 293SimpleThread::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 324struct PosixThreadImplementation 325{ 326 pthread_t fThread; 327 UBool fRunning; 328 UBool fRan; // True if the thread was successfully started 329}; 330 331extern "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 347SimpleThread::SimpleThread() 348{ 349 PosixThreadImplementation *imp = new PosixThreadImplementation; 350 imp->fRunning = FALSE; 351 imp->fRan = FALSE; 352 fImplementation = imp; 353} 354 355SimpleThread::~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 365int32_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 412UBool 413SimpleThread::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 426void 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. 4540 = 216; //die 455#endif 456 457//------------------------------------------------------------------------------------------- 458// 459// class ThreadWithStatus - a thread that we can check the status and error condition of 460// 461//------------------------------------------------------------------------------------------- 462class ThreadWithStatus : public SimpleThread 463{ 464public: 465 UBool getError() { return (fErrors > 0); } 466 UBool getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); } 467 virtual ~ThreadWithStatus(){} 468protected: 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."); } 475private: 476 int32_t fErrors; 477 UnicodeString fErrorString; 478}; 479 480#endif // ICU_USE_THREADS 481