1 /* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #ifndef MY_XP_THREAD_INCLUDED
24 #define MY_XP_THREAD_INCLUDED
25
26 #include <xplatform/my_xp_cond.h>
27
28 #ifndef ETIME
29 #define ETIME ETIMEDOUT /* For FreeBSD */
30 #endif
31
32 #ifndef ETIMEDOUT
33 #define ETIMEDOUT 145 /* Win32 doesn't have this */
34 #endif
35
36 typedef unsigned int uint32;
37 typedef uint32 native_thread_id;
38
39 #ifdef _WIN32
40
41 typedef volatile LONG native_thread_once_t;
42 typedef DWORD native_thread_t;
43 typedef struct thread_attr
44 {
45 DWORD dwStackSize;
46 } native_thread_attr_t;
47 typedef void *(__cdecl *native_start_routine)(void *);
48 #define MY_THREAD_ONCE_INIT 0
49 #define MY_THREAD_ONCE_INPROGRESS 1
50 #define MY_THREAD_ONCE_DONE 2
51
52 #include <process.h>
53 #include <signal.h>
54
55 struct thread_start_parameter
56 {
57 native_start_routine func;
58 void *arg;
59 };
60
61
win_thread_start(void * p)62 static unsigned int __stdcall win_thread_start(void *p)
63 {
64 struct thread_start_parameter *par= (struct thread_start_parameter *)p;
65 native_start_routine func= par->func;
66 void *arg= par->arg;
67
68 free(p);
69 (*func)(arg);
70 return 0;
71 }
72
73
74 /* All thread specific variables are in the following struct */
75 struct st_native_thread_var
76 {
77 int thr_errno;
78 /*
79 thr_winerr is used for returning the original OS error-code in Windows,
80 my_osmaperr() returns EINVAL for all unknown Windows errors, hence we
81 preserve the original Windows Error code in thr_winerr.
82 */
83 int thr_winerr;
84 native_cond_t suspend;
85 native_thread_id id;
86 int volatile abort;
87 struct st_native_thread_var *next, **prev;
88 void *opt_info;
89 #ifndef DBUG_OFF
90 void *dbug;
91 #endif
92 };
93
94
95 int set_mysys_thread_var(struct st_native_thread_var *mysys_var);
96
97 #ifndef DBUG_OFF
98 /**
99 Returns pointer to DBUG for holding current state.
100 */
101 void **my_thread_var_dbug();
102 #endif
103
104 #define my_errno mysys_thread_var()->thr_errno
105
106 struct errentry
107 {
108 unsigned long oscode; /* OS return value */
109 int sysv_errno; /* System V error code */
110 };
111
112 static struct errentry errtable[]= {
113 { ERROR_INVALID_FUNCTION, EINVAL }, /* 1 */
114 { ERROR_FILE_NOT_FOUND, ENOENT }, /* 2 */
115 { ERROR_PATH_NOT_FOUND, ENOENT }, /* 3 */
116 { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, /* 4 */
117 { ERROR_ACCESS_DENIED, EACCES }, /* 5 */
118 { ERROR_INVALID_HANDLE, EBADF }, /* 6 */
119 { ERROR_ARENA_TRASHED, ENOMEM }, /* 7 */
120 { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, /* 8 */
121 { ERROR_INVALID_BLOCK, ENOMEM }, /* 9 */
122 { ERROR_BAD_ENVIRONMENT, E2BIG }, /* 10 */
123 { ERROR_BAD_FORMAT, ENOEXEC }, /* 11 */
124 { ERROR_INVALID_ACCESS, EINVAL }, /* 12 */
125 { ERROR_INVALID_DATA, EINVAL }, /* 13 */
126 { ERROR_INVALID_DRIVE, ENOENT }, /* 15 */
127 { ERROR_CURRENT_DIRECTORY, EACCES }, /* 16 */
128 { ERROR_NOT_SAME_DEVICE, EXDEV }, /* 17 */
129 { ERROR_NO_MORE_FILES, ENOENT }, /* 18 */
130 { ERROR_LOCK_VIOLATION, EACCES }, /* 33 */
131 { ERROR_BAD_NETPATH, ENOENT }, /* 53 */
132 { ERROR_NETWORK_ACCESS_DENIED, EACCES }, /* 65 */
133 { ERROR_BAD_NET_NAME, ENOENT }, /* 67 */
134 { ERROR_FILE_EXISTS, EEXIST }, /* 80 */
135 { ERROR_CANNOT_MAKE, EACCES }, /* 82 */
136 { ERROR_FAIL_I24, EACCES }, /* 83 */
137 { ERROR_INVALID_PARAMETER, EINVAL }, /* 87 */
138 { ERROR_NO_PROC_SLOTS, EAGAIN }, /* 89 */
139 { ERROR_DRIVE_LOCKED, EACCES }, /* 108 */
140 { ERROR_BROKEN_PIPE, EPIPE }, /* 109 */
141 { ERROR_DISK_FULL, ENOSPC }, /* 112 */
142 { ERROR_INVALID_TARGET_HANDLE, EBADF }, /* 114 */
143 { ERROR_INVALID_NAME, ENOENT }, /* 123 */
144 { ERROR_INVALID_HANDLE, EINVAL }, /* 124 */
145 { ERROR_WAIT_NO_CHILDREN, ECHILD }, /* 128 */
146 { ERROR_CHILD_NOT_COMPLETE, ECHILD }, /* 129 */
147 { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, /* 130 */
148 { ERROR_NEGATIVE_SEEK, EINVAL }, /* 131 */
149 { ERROR_SEEK_ON_DEVICE, EACCES }, /* 132 */
150 { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, /* 145 */
151 { ERROR_NOT_LOCKED, EACCES }, /* 158 */
152 { ERROR_BAD_PATHNAME, ENOENT }, /* 161 */
153 { ERROR_MAX_THRDS_REACHED, EAGAIN }, /* 164 */
154 { ERROR_LOCK_FAILED, EACCES }, /* 167 */
155 { ERROR_ALREADY_EXISTS, EEXIST }, /* 183 */
156 { ERROR_FILENAME_EXCED_RANGE, ENOENT }, /* 206 */
157 { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, /* 215 */
158 { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } /* 1816 */
159 };
160
161 /* size of the table */
162 #define ERRTABLESIZE (sizeof(errtable)/sizeof(errtable[0]))
163
164 /*
165 The following two constants must be the minimum and maximum
166 values in the (contiguous) range of Exec Failure errors.
167 */
168 #define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
169 #define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN
170
171 /*
172 These are the low and high value in the range of errors that are access
173 violations.
174 */
175 #define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
176 #define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED
177
178
get_errno_from_oserr(unsigned long oserrno)179 static int get_errno_from_oserr(unsigned long oserrno)
180 {
181 int i;
182
183 /* check the table for the OS error code */
184 for (i= 0; i < ERRTABLESIZE; ++i)
185 {
186 if (oserrno == errtable[i].oscode)
187 {
188 return errtable[i].sysv_errno;
189 }
190 }
191
192 /*
193 The error code wasn't in the table. We check for a range of
194 EACCES errors or exec failure errors (ENOEXEC). Otherwise
195 EINVAL is returned.
196 */
197
198 if (oserrno >= MIN_EACCES_RANGE && oserrno <= MAX_EACCES_RANGE)
199 return EACCES;
200 else if (oserrno >= MIN_EXEC_ERROR && oserrno <= MAX_EXEC_ERROR)
201 return ENOEXEC;
202 else
203 return EINVAL;
204 }
205
206 #else
207 #include <pthread.h>
208
209 typedef pthread_once_t native_thread_once_t;
210 typedef pthread_t native_thread_t;
211 typedef pthread_attr_t native_thread_attr_t;
212 typedef void *(*native_start_routine)(void *);
213 #define MY_THREAD_ONCE_INIT PTHREAD_ONCE_INIT
214 #endif
215
216 /**
217 @class My_xp_thread
218
219 Abstract class used to wrap mutex for various platforms.
220
221 A typical use case is:
222
223 @code{.cpp}
224
225 My_xp_thread thread= My_xp_thread::get_thread();
226 thread->create(NULL, &function, &args);
227
228 void *result;
229 thread->join(&result);
230
231 @endcode
232 */
233 class My_xp_thread
234 {
235 public:
236 /**
237 Creates thread.
238
239 @param thread attributes
240 @param routine function
241 @param function parameters
242 @return success status
243 */
244
245 virtual int create(const native_thread_attr_t *attr,
246 native_start_routine func, void *arg)= 0;
247
248
249 /**
250 One time initialization.
251
252 @param init routine to invoke
253 @return success status
254 */
255
256 virtual int once(void (*init_routine)(void))= 0;
257
258
259 /**
260 Suspend invoking thread until this thread terminates.
261
262 @param pointer for a placeholder for the terminating thread status
263 @return success status
264 */
265
266 virtual int join(void **value_ptr)= 0;
267
268
269 /**
270 Cancel this thread.
271
272 @return success status
273 */
274
275 virtual int cancel()= 0;
276
277
278 /**
279 Detach this thread, i.e. its resources can be reclaimed when it terminates.
280
281 @return success status
282 */
283
284 virtual int detach()= 0;
285
286
287 /**
288 Retrieves native thread reference
289
290 @return native thread pointer
291 */
292
293 virtual native_thread_t *get_native_thread()= 0;
294
~My_xp_thread()295 virtual ~My_xp_thread() {}
296 };
297
298 #ifdef _WIN32
299 class My_xp_thread_win : public My_xp_thread
300 {
301 private:
302 HANDLE m_handle;
303 void my_osmaperr( unsigned long oserrno);
304 st_native_thread_var *m_thread_var;
305 /*
306 Disabling the copy constructor and assignment operator.
307 */
308 My_xp_thread_win(My_xp_thread_win const&);
309 My_xp_thread_win& operator=(My_xp_thread_win const&);
310 public:
311 explicit My_xp_thread_win();
312 virtual ~My_xp_thread_win();
313 #else
314 class My_xp_thread_pthread : public My_xp_thread
315 {
316 private:
317 /*
318 Disabling the copy constructor and assignment operator.
319 */
320 My_xp_thread_pthread(My_xp_thread_pthread const&);
321 My_xp_thread_pthread& operator=(My_xp_thread_pthread const&);
322 public:
323 explicit My_xp_thread_pthread();
324 virtual ~My_xp_thread_pthread();
325 #endif
326 int create(const native_thread_attr_t *attr, native_start_routine func,
327 void *arg);
328 int once(void (*init_routine)(void));
329 int join(void **value_ptr);
330 int cancel();
331 int detach();
332 native_thread_t *get_native_thread();
333
334 protected:
335 native_thread_t *m_thread;
336 native_thread_once_t *m_thread_once;
337 };
338
339 #ifdef _WIN32
340 class My_xp_thread_impl : public My_xp_thread_win
341 #else
342 class My_xp_thread_impl : public My_xp_thread_pthread
343 #endif
344 {
345 public:
My_xp_thread_impl()346 explicit My_xp_thread_impl() {}
~My_xp_thread_impl()347 ~My_xp_thread_impl() {}
348 };
349
350 class My_xp_thread_util
351 {
352 public:
353 /**
354 Terminate invoking thread.
355
356 @param thread exit value pointer
357 */
358
359 static void exit(void *value_ptr);
360
361
362 /**
363 Initialize thread attributes object.
364
365 @param thread attributes
366 @return success status
367 */
368
369 static int attr_init(native_thread_attr_t *attr);
370
371
372 /**
373 Destroy thread attributes object.
374
375 @param thread attributes
376 @return success status
377 */
378
379 static int attr_destroy(native_thread_attr_t *attr);
380
381
382 /**
383 Retrieve current thread id.
384
385 @return current thread id
386 */
387
388 static native_thread_t self();
389 };
390
391 #endif // MY_XP_THREAD_INCLUDED
392