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