Index: icu46/source/test/intltest/simplethread.cpp |
=================================================================== |
--- icu46/source/test/intltest/simplethread.cpp (revision 0) |
+++ icu46/source/test/intltest/simplethread.cpp (revision 0) |
@@ -0,0 +1,472 @@ |
+/******************************************************************** |
+ * COPYRIGHT: |
+ * Copyright (c) 1999-2009, International Business Machines Corporation and |
+ * others. All Rights Reserved. |
+ ********************************************************************/ |
+ |
+#if defined(hpux) |
+# ifndef _INCLUDE_POSIX_SOURCE |
+# define _INCLUDE_POSIX_SOURCE |
+# endif |
+#endif |
+ |
+#include "simplethread.h" |
+ |
+#include "unicode/utypes.h" |
+#include "unicode/ustring.h" |
+#include "umutex.h" |
+#include "cmemory.h" |
+#include "cstring.h" |
+#include "uparse.h" |
+#include "unicode/resbund.h" |
+#include "unicode/udata.h" |
+#include "unicode/uloc.h" |
+#include "unicode/locid.h" |
+#include "putilimp.h" |
+ |
+#include <stdio.h> |
+#include <string.h> |
+#include <ctype.h> // tolower, toupper |
+ |
+#if !defined(U_WINDOWS) && !defined(XP_MAC) && !defined(U_RHAPSODY) |
+#define POSIX 1 |
+#endif |
+ |
+/* Needed by z/OS to get usleep */ |
+#if defined(OS390) |
+#define __DOT1 1 |
+#define __UU |
+#define _XOPEN_SOURCE_EXTENDED 1 |
+#ifndef _XPG4_2 |
+#define _XPG4_2 |
+#endif |
+#include <unistd.h> |
+/*#include "platform_xopen_source_extended.h"*/ |
+#endif |
+ |
+#if defined(POSIX) || defined(U_SOLARIS) || defined(U_AIX) || defined(U_HPUX) |
+#define HAVE_IMP |
+ |
+#if (ICU_USE_THREADS == 1) |
+#include <pthread.h> |
+#endif |
+ |
+#if defined(__hpux) && defined(HPUX_CMA) |
+# if defined(read) // read being defined as cma_read causes trouble with iostream::read |
+# undef read |
+# endif |
+#endif |
+ |
+/* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */ |
+#ifndef __EXTENSIONS__ |
+#define __EXTENSIONS__ |
+#endif |
+ |
+#if defined(OS390) |
+#include <sys/types.h> |
+#endif |
+ |
+#if !defined(OS390) |
+#include <signal.h> |
+#endif |
+ |
+/* Define _XPG4_2 for Solaris and friends. */ |
+#ifndef _XPG4_2 |
+#define _XPG4_2 |
+#endif |
+ |
+/* Define __USE_XOPEN_EXTENDED for Linux and glibc. */ |
+#ifndef __USE_XOPEN_EXTENDED |
+#define __USE_XOPEN_EXTENDED |
+#endif |
+ |
+/* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */ |
+#ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED |
+#define _INCLUDE_XOPEN_SOURCE_EXTENDED |
+#endif |
+ |
+#include <unistd.h> |
+ |
+#endif |
+/* HPUX */ |
+#ifdef sleep |
+#undef sleep |
+#endif |
+ |
+ |
+#if (ICU_USE_THREADS==0) |
+ SimpleThread::SimpleThread() |
+ {} |
+ |
+ SimpleThread::~SimpleThread() |
+ {} |
+ |
+ int32_t |
+ SimpleThread::start() |
+ { return -1; } |
+ |
+ void |
+ SimpleThread::run() |
+ {} |
+ |
+ void |
+ SimpleThread::sleep(int32_t millis) |
+ {} |
+ |
+ UBool |
+ SimpleThread::isRunning() { |
+ return FALSE; |
+ } |
+#else |
+ |
+#include "unicode/putil.h" |
+ |
+/* for mthreadtest*/ |
+#include "unicode/numfmt.h" |
+#include "unicode/choicfmt.h" |
+#include "unicode/msgfmt.h" |
+#include "unicode/locid.h" |
+#include "unicode/ucol.h" |
+#include "unicode/calendar.h" |
+#include "ucaconf.h" |
+ |
+#ifdef U_WINDOWS |
+#define HAVE_IMP |
+ |
+# define VC_EXTRALEAN |
+# define WIN32_LEAN_AND_MEAN |
+# define NOUSER |
+# define NOSERVICE |
+# define NOIME |
+# define NOMCX |
+#include <windows.h> |
+#include <process.h> |
+ |
+//----------------------------------------------------------------------------------- |
+// |
+// class SimpleThread Windows Implementation |
+// |
+//----------------------------------------------------------------------------------- |
+struct Win32ThreadImplementation |
+{ |
+ HANDLE fHandle; |
+ unsigned int fThreadID; |
+}; |
+ |
+ |
+extern "C" unsigned int __stdcall SimpleThreadProc(void *arg) |
+{ |
+ ((SimpleThread*)arg)->run(); |
+ return 0; |
+} |
+ |
+SimpleThread::SimpleThread() |
+:fImplementation(0) |
+{ |
+ Win32ThreadImplementation *imp = new Win32ThreadImplementation; |
+ imp->fHandle = 0; |
+ fImplementation = imp; |
+} |
+ |
+SimpleThread::~SimpleThread() |
+{ |
+ // Destructor. Because we start the thread running with _beginthreadex(), |
+ // we own the Windows HANDLE for the thread and must |
+ // close it here. |
+ Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation; |
+ if (imp != 0) { |
+ if (imp->fHandle != 0) { |
+ CloseHandle(imp->fHandle); |
+ imp->fHandle = 0; |
+ } |
+ } |
+ delete (Win32ThreadImplementation*)fImplementation; |
+} |
+ |
+int32_t SimpleThread::start() |
+{ |
+ Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation; |
+ if(imp->fHandle != NULL) { |
+ // The thread appears to have already been started. |
+ // This is probably an error on the part of our caller. |
+ return -1; |
+ } |
+ |
+ imp->fHandle = (HANDLE) _beginthreadex( |
+ NULL, // Security |
+ 0x20000, // Stack Size |
+ SimpleThreadProc, // Function to Run |
+ (void *)this, // Arg List |
+ 0, // initflag. Start running, not suspended |
+ &imp->fThreadID // thraddr |
+ ); |
+ |
+ if (imp->fHandle == 0) { |
+ // An error occured |
+ int err = errno; |
+ if (err == 0) { |
+ err = -1; |
+ } |
+ return err; |
+ } |
+ return 0; |
+} |
+ |
+ |
+UBool SimpleThread::isRunning() { |
+ // |
+ // Test whether the thread associated with the SimpleThread object is |
+ // still actually running. |
+ // |
+ // NOTE: on Win64 on Itanium processors, a crashes |
+ // occur if the main thread of a process exits concurrently with some |
+ // other thread(s) exiting. To avoid the possibility, we wait until the |
+ // OS indicates that all threads have terminated, rather than waiting |
+ // only until the end of the user's Run function has been reached. |
+ // |
+ // I don't know whether the crashes represent a Windows bug, or whether |
+ // main() programs are supposed to have to wait for their threads. |
+ // |
+ Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation; |
+ |
+ bool success; |
+ DWORD threadExitCode; |
+ |
+ if (imp->fHandle == 0) { |
+ // No handle, thread must not be running. |
+ return FALSE; |
+ } |
+ success = GetExitCodeThread(imp->fHandle, &threadExitCode) != 0; |
+ if (! success) { |
+ // Can't get status, thread must not be running. |
+ return FALSE; |
+ } |
+ return (threadExitCode == STILL_ACTIVE); |
+} |
+ |
+ |
+void SimpleThread::sleep(int32_t millis) |
+{ |
+ ::Sleep(millis); |
+} |
+ |
+//----------------------------------------------------------------------------------- |
+// |
+// class SimpleThread NULL Implementation |
+// |
+//----------------------------------------------------------------------------------- |
+#elif defined XP_MAC |
+ |
+// since the Mac has no preemptive threading (at least on MacOS 8), only |
+// cooperative threading, threads are a no-op. We have no yield() calls |
+// anywhere in the ICU, so we are guaranteed to be thread-safe. |
+ |
+#define HAVE_IMP |
+ |
+SimpleThread::SimpleThread() |
+{} |
+ |
+SimpleThread::~SimpleThread() |
+{} |
+ |
+int32_t |
+SimpleThread::start() |
+{ return 0; } |
+ |
+void |
+SimpleThread::run() |
+{} |
+ |
+void |
+SimpleThread::sleep(int32_t millis) |
+{} |
+ |
+UBool |
+SimpleThread::isRunning() { |
+ return FALSE; |
+} |
+ |
+#endif |
+ |
+ |
+//----------------------------------------------------------------------------------- |
+// |
+// class SimpleThread POSIX implementation |
+// |
+// A note on the POSIX vs the Windows implementations of this class.. |
+// On Windows, the main thread must verify that other threads have finished |
+// before exiting, or crashes occasionally occur. (Seen on Itanium Win64 only) |
+// The function SimpleThread::isRunning() is used for this purpose. |
+// |
+// On POSIX, there is NO reliable non-blocking mechanism to determine |
+// whether a thread has exited. pthread_kill(thread, 0) almost works, |
+// but the system can recycle thread ids immediately, so seeing that a |
+// thread exists with this call could mean that the original thread has |
+// finished and a new one started with the same ID. Useless. |
+// |
+// So we need to do the check with user code, by setting a flag just before |
+// the thread function returns. A technique that is guaranteed to fail |
+// on Windows, because it indicates that the thread is done before all |
+// system level cleanup has happened. |
+// |
+//----------------------------------------------------------------------------------- |
+#if defined(POSIX)||defined(U_SOLARIS)||defined(U_AIX)||defined(U_HPUX) |
+#define HAVE_IMP |
+ |
+struct PosixThreadImplementation |
+{ |
+ pthread_t fThread; |
+ UBool fRunning; |
+ UBool fRan; // True if the thread was successfully started |
+}; |
+ |
+extern "C" void* SimpleThreadProc(void *arg) |
+{ |
+ // This is the code that is run in the new separate thread. |
+ SimpleThread *This = (SimpleThread *)arg; |
+ This->run(); // Run the user code. |
+ |
+ // The user function has returned. Set the flag indicating that this thread |
+ // is done. Need a mutex for memory barrier purposes only, so that other thread |
+ // will reliably see that the flag has changed. |
+ PosixThreadImplementation *imp = (PosixThreadImplementation*)This->fImplementation; |
+ umtx_lock(NULL); |
+ imp->fRunning = FALSE; |
+ umtx_unlock(NULL); |
+ return 0; |
+} |
+ |
+SimpleThread::SimpleThread() |
+{ |
+ PosixThreadImplementation *imp = new PosixThreadImplementation; |
+ imp->fRunning = FALSE; |
+ imp->fRan = FALSE; |
+ fImplementation = imp; |
+} |
+ |
+SimpleThread::~SimpleThread() |
+{ |
+ PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation; |
+ if (imp->fRan) { |
+ pthread_join(imp->fThread, NULL); |
+ } |
+ delete imp; |
+ fImplementation = (void *)0xdeadbeef; |
+} |
+ |
+int32_t SimpleThread::start() |
+{ |
+ int32_t rc; |
+ static pthread_attr_t attr; |
+ static UBool attrIsInitialized = FALSE; |
+ |
+ PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation; |
+ imp->fRunning = TRUE; |
+ imp->fRan = TRUE; |
+ |
+#ifdef HPUX_CMA |
+ if (attrIsInitialized == FALSE) { |
+ rc = pthread_attr_create(&attr); |
+ attrIsInitialized = TRUE; |
+ } |
+ rc = pthread_create(&(imp->fThread),attr,&SimpleThreadProc,(void*)this); |
+#else |
+ if (attrIsInitialized == FALSE) { |
+ rc = pthread_attr_init(&attr); |
+#if defined(OS390) |
+ { |
+ int detachstate = 0; // jdc30: detach state of zero causes |
+ //threads created with this attr to be in |
+ //an undetached state. An undetached |
+ //thread will keep its resources after |
+ //termination. |
+ pthread_attr_setdetachstate(&attr, &detachstate); |
+ } |
+#else |
+ // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); |
+#endif |
+ attrIsInitialized = TRUE; |
+ } |
+ rc = pthread_create(&(imp->fThread),&attr,&SimpleThreadProc,(void*)this); |
+#endif |
+ |
+ if (rc != 0) { |
+ // some kind of error occured, the thread did not start. |
+ imp->fRan = FALSE; |
+ imp->fRunning = FALSE; |
+ } |
+ |
+ return rc; |
+} |
+ |
+ |
+UBool |
+SimpleThread::isRunning() { |
+ // Note: Mutex functions are used here not for synchronization, |
+ // but to force memory barriors to exist, to ensure that one thread |
+ // can see changes made by another when running on processors |
+ // with memory models having weak coherency. |
+ PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation; |
+ umtx_lock(NULL); |
+ UBool retVal = imp->fRunning; |
+ umtx_unlock(NULL); |
+ return retVal; |
+} |
+ |
+ |
+void SimpleThread::sleep(int32_t millis) |
+{ |
+#ifdef U_SOLARIS |
+ sigignore(SIGALRM); |
+#endif |
+ |
+#ifdef HPUX_CMA |
+ cma_sleep(millis/100); |
+#elif defined(U_HPUX) || defined(OS390) |
+ millis *= 1000; |
+ while(millis >= 1000000) { |
+ usleep(999999); |
+ millis -= 1000000; |
+ } |
+ if(millis > 0) { |
+ usleep(millis); |
+ } |
+#else |
+ usleep(millis * 1000); |
+#endif |
+} |
+ |
+#endif |
+// end POSIX |
+ |
+ |
+#ifndef HAVE_IMP |
+#error No implementation for threads! Cannot test. |
+0 = 216; //die |
+#endif |
+ |
+//------------------------------------------------------------------------------------------- |
+// |
+// class ThreadWithStatus - a thread that we can check the status and error condition of |
+// |
+//------------------------------------------------------------------------------------------- |
+class ThreadWithStatus : public SimpleThread |
+{ |
+public: |
+ UBool getError() { return (fErrors > 0); } |
+ UBool getError(UnicodeString& fillinError) { fillinError = fErrorString; return (fErrors > 0); } |
+ virtual ~ThreadWithStatus(){} |
+protected: |
+ ThreadWithStatus() : fErrors(0) {} |
+ void error(const UnicodeString &error) { |
+ fErrors++; fErrorString = error; |
+ SimpleThread::errorFunc(); |
+ } |
+ void error() { error("An error occured."); } |
+private: |
+ int32_t fErrors; |
+ UnicodeString fErrorString; |
+}; |
+ |
+#endif // ICU_USE_THREADS |
Property changes on: icu46/source/test/intltest/simplethread.cpp |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |