Imported Upstream version 58.1
[platform/upstream/icu.git] / source / test / intltest / simplethread.cpp
1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /********************************************************************
4  * COPYRIGHT: 
5  * Copyright (c) 1999-2015, International Business Machines Corporation and
6  * others. All Rights Reserved.
7  ********************************************************************/
8
9 #if defined(hpux)
10 # ifndef _INCLUDE_POSIX_SOURCE
11 #  define _INCLUDE_POSIX_SOURCE
12 # endif
13 #endif
14
15 /* Define __EXTENSIONS__ for Solaris and old friends in strict mode. */
16 #ifndef __EXTENSIONS__
17 #define __EXTENSIONS__
18 #endif
19
20 // Defines _XOPEN_SOURCE for access to POSIX functions.
21 // Must be before any other #includes.
22 #include "uposixdefs.h"
23
24 #include "simplethread.h"
25
26 #include "unicode/utypes.h"
27 #include "unicode/ustring.h"
28 #include "umutex.h"
29 #include "cmemory.h"
30 #include "cstring.h"
31 #include "uparse.h"
32 #include "unicode/resbund.h"
33 #include "unicode/udata.h"
34 #include "unicode/uloc.h"
35 #include "unicode/locid.h"
36 #include "putilimp.h"
37 #include "intltest.h"
38
39 #include <stdio.h>
40 #include <string.h>
41 #include <ctype.h>    // tolower, toupper
42
43 #if U_PLATFORM_USES_ONLY_WIN32_API
44     /* Prefer native Windows APIs even if POSIX is implemented (i.e., on Cygwin). */
45 #   undef POSIX
46 #elif U_PLATFORM_IMPLEMENTS_POSIX
47 #   define POSIX
48 #else
49 #   undef POSIX
50 #endif
51
52 /* Needed by z/OS to get usleep */
53 #if U_PLATFORM == U_PF_OS390
54 #define __DOT1 1
55 #ifndef __UU
56 #   define __UU
57 #endif
58 #ifndef _XPG4_2
59 #   define _XPG4_2
60 #endif
61 #include <unistd.h>
62 #endif
63
64 #if defined(POSIX)
65 #define HAVE_IMP
66
67 #include <pthread.h>
68
69 #if U_PLATFORM == U_PF_OS390
70 #include <sys/types.h>
71 #endif
72
73 #if U_PLATFORM != U_PF_OS390
74 #include <signal.h>
75 #endif
76
77 /* Define _XPG4_2 for Solaris and friends. */
78 #ifndef _XPG4_2
79 #define _XPG4_2
80 #endif
81
82 /* Define __USE_XOPEN_EXTENDED for Linux and glibc. */
83 #ifndef __USE_XOPEN_EXTENDED
84 #define __USE_XOPEN_EXTENDED 
85 #endif
86
87 /* Define _INCLUDE_XOPEN_SOURCE_EXTENDED for HP/UX (11?). */
88 #ifndef _INCLUDE_XOPEN_SOURCE_EXTENDED
89 #define _INCLUDE_XOPEN_SOURCE_EXTENDED
90 #endif
91
92 #include <unistd.h>
93
94 #endif
95 /* HPUX */
96 #ifdef sleep
97 #undef sleep
98 #endif
99
100
101 #include "unicode/putil.h"
102
103 /* for mthreadtest*/
104 #include "unicode/numfmt.h"
105 #include "unicode/choicfmt.h"
106 #include "unicode/msgfmt.h"
107 #include "unicode/locid.h"
108 #include "unicode/ucol.h"
109 #include "unicode/calendar.h"
110 #include "ucaconf.h"
111
112 #if U_PLATFORM_USES_ONLY_WIN32_API
113 #define HAVE_IMP
114
115 #   define VC_EXTRALEAN
116 #   define WIN32_LEAN_AND_MEAN
117 #   define NOUSER
118 #   define NOSERVICE
119 #   define NOIME
120 #   define NOMCX
121 #include <windows.h>
122 #include <process.h>
123
124 //-----------------------------------------------------------------------------------
125 //
126 //   class SimpleThread   Windows Implementation
127 //
128 //-----------------------------------------------------------------------------------
129 struct Win32ThreadImplementation
130 {
131     HANDLE         fHandle;
132     unsigned int   fThreadID;
133 };
134
135
136 extern "C" unsigned int __stdcall SimpleThreadProc(void *arg)
137 {
138     ((SimpleThread*)arg)->run();
139     return 0;
140 }
141
142 SimpleThread::SimpleThread()
143 :fImplementation(0)
144 {
145     Win32ThreadImplementation *imp = new Win32ThreadImplementation;
146     imp->fHandle = 0;
147     fImplementation = imp;
148 }
149
150 SimpleThread::~SimpleThread()
151 {
152     // Destructor.  Because we start the thread running with _beginthreadex(),
153     //              we own the Windows HANDLE for the thread and must 
154     //              close it here.
155     Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
156     if (imp != 0) {
157         if (imp->fHandle != 0) {
158             CloseHandle(imp->fHandle);
159             imp->fHandle = 0;
160         }
161     }
162     delete (Win32ThreadImplementation*)fImplementation;
163 }
164
165 int32_t SimpleThread::start()
166 {
167     Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
168     if(imp->fHandle != NULL) {
169         // The thread appears to have already been started.
170         //   This is probably an error on the part of our caller.
171         return -1;
172     }
173
174     imp->fHandle = (HANDLE) _beginthreadex(
175         NULL,                                 // Security    
176         0x20000,                              // Stack Size 
177         SimpleThreadProc,                     // Function to Run
178         (void *)this,                         // Arg List
179         0,                                    // initflag.  Start running, not suspended
180         &imp->fThreadID                       // thraddr
181         );
182
183     if (imp->fHandle == 0) {
184         // An error occured
185         int err = errno;
186         if (err == 0) {
187             err = -1;
188         }
189         return err;
190     }
191     return 0;
192 }
193
194
195 void SimpleThread::join() {
196     Win32ThreadImplementation *imp = (Win32ThreadImplementation*)fImplementation;
197     if (imp->fHandle == 0) {
198         // No handle, thread must not be running.
199         return;
200     }
201     WaitForSingleObject(imp->fHandle, INFINITE);
202 }
203
204 #endif
205
206
207 //-----------------------------------------------------------------------------------
208 //
209 //   class SimpleThread   POSIX implementation
210 //
211 //-----------------------------------------------------------------------------------
212 #if defined(POSIX)
213 #define HAVE_IMP
214
215 struct PosixThreadImplementation
216 {
217     pthread_t        fThread;
218 };
219
220 extern "C" void* SimpleThreadProc(void *arg)
221 {
222     // This is the code that is run in the new separate thread.
223     SimpleThread *This = (SimpleThread *)arg;
224     This->run();
225     return 0;
226 }
227
228 SimpleThread::SimpleThread() 
229 {
230     PosixThreadImplementation *imp = new PosixThreadImplementation;
231     fImplementation = imp;
232 }
233
234 SimpleThread::~SimpleThread()
235 {
236     PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
237     delete imp;
238     fImplementation = (void *)0xdeadbeef;
239 }
240
241 int32_t SimpleThread::start()
242 {
243     int32_t        rc;
244     static pthread_attr_t attr;
245     static UBool attrIsInitialized = FALSE;
246
247     PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
248
249     if (attrIsInitialized == FALSE) {
250         rc = pthread_attr_init(&attr);
251 #if U_PLATFORM == U_PF_OS390
252         {
253             int detachstate = 0;  // jdc30: detach state of zero causes
254                                   //threads created with this attr to be in
255                                   //an undetached state.  An undetached
256                                   //thread will keep its resources after
257                                   //termination.
258             pthread_attr_setdetachstate(&attr, &detachstate);
259         }
260 #else
261         // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
262         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
263 #endif
264         attrIsInitialized = TRUE;
265     }
266     rc = pthread_create(&(imp->fThread), &attr, &SimpleThreadProc, (void*)this);
267     
268     if (rc != 0) {
269         // some kind of error occured, the thread did not start.
270     }
271
272     return rc;
273 }
274
275 void SimpleThread::join() {
276     PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
277     pthread_join(imp->fThread, NULL);
278 }
279
280 #endif
281 // end POSIX
282
283
284 #ifndef HAVE_IMP
285 #error  No implementation for threads! Cannot test.
286 #endif
287
288
289 class ThreadPoolThread: public SimpleThread {
290   public:
291     ThreadPoolThread(ThreadPoolBase *pool, int32_t threadNum) : fPool(pool), fNum(threadNum) {};
292     virtual void run() {fPool->callFn(fNum); }
293     ThreadPoolBase *fPool;
294     int32_t         fNum;
295 };
296
297
298 ThreadPoolBase::ThreadPoolBase(IntlTest *test, int32_t howMany) :
299         fIntlTest(test), fNumThreads(howMany), fThreads(NULL) {
300     fThreads = new SimpleThread *[fNumThreads];
301     if (fThreads == NULL) {
302         fIntlTest->errln("%s:%d memory allocation failure.", __FILE__, __LINE__);
303         return;
304     }
305
306     for (int i=0; i<fNumThreads; i++) {
307         fThreads[i] = new ThreadPoolThread(this, i);
308         if (fThreads[i] == NULL) {
309             fIntlTest->errln("%s:%d memory allocation failure.", __FILE__, __LINE__);
310         }
311     }
312 }
313
314 void ThreadPoolBase::start() {
315     for (int i=0; i<fNumThreads; i++) {
316         if (fThreads && fThreads[i]) {
317             fThreads[i]->start();
318         }
319     }
320 }
321
322 void ThreadPoolBase::join() {
323     for (int i=0; i<fNumThreads; i++) {
324         if (fThreads && fThreads[i]) {
325             fThreads[i]->join();
326         }
327     }
328 }
329
330 ThreadPoolBase::~ThreadPoolBase() {
331     if (fThreads) {
332         for (int i=0; i<fNumThreads; i++) {
333             delete fThreads[i];
334             fThreads[i] = NULL;
335         }
336         delete[] fThreads;
337         fThreads = NULL;
338     }
339 }
340
341
342