1 // © 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
SimpleThreadProc(void * arg)136 extern "C" unsigned int __stdcall SimpleThreadProc(void *arg)
137 {
138 ((SimpleThread*)arg)->run();
139 return 0;
140 }
141
SimpleThread()142 SimpleThread::SimpleThread()
143 :fImplementation(0)
144 {
145 Win32ThreadImplementation *imp = new Win32ThreadImplementation;
146 imp->fHandle = 0;
147 fImplementation = imp;
148 }
149
~SimpleThread()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
start()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
join()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
SimpleThreadProc(void * arg)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
SimpleThread()228 SimpleThread::SimpleThread()
229 {
230 PosixThreadImplementation *imp = new PosixThreadImplementation;
231 fImplementation = imp;
232 }
233
~SimpleThread()234 SimpleThread::~SimpleThread()
235 {
236 PosixThreadImplementation *imp = (PosixThreadImplementation*)fImplementation;
237 delete imp;
238 fImplementation = (void *)0xdeadbeef;
239 }
240
start()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
join()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:
ThreadPoolThread(ThreadPoolBase * pool,int32_t threadNum)291 ThreadPoolThread(ThreadPoolBase *pool, int32_t threadNum) : fPool(pool), fNum(threadNum) {};
run()292 virtual void run() {fPool->callFn(fNum); }
293 ThreadPoolBase *fPool;
294 int32_t fNum;
295 };
296
297
ThreadPoolBase(IntlTest * test,int32_t howMany)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
start()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
join()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
~ThreadPoolBase()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
343