1 /*****************************************************************************
2
3 Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License, version 2.0,
7 as published by the Free Software Foundation.
8
9 This program is also distributed with certain software (including
10 but not limited to OpenSSL) that is licensed under separate terms,
11 as designated in a particular file or component or in included license
12 documentation. The authors of MySQL hereby grant you an additional
13 permission to link the program and your derivative works with the
14 separately licensed software that they have included with MySQL.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License, version 2.0, for more details.
20
21 You should have received a copy of the GNU General Public License along with
22 this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
24
25 *****************************************************************************/
26
27 /**************************************************//**
28 @file os/os0thread.cc
29 The interface to the operating system thread control primitives
30
31 Created 9/8/1995 Heikki Tuuri
32 *******************************************************/
33
34 #include "os0thread.h"
35 #ifdef UNIV_NONINL
36 #include "os0thread.ic"
37 #endif
38
39 #ifdef __WIN__
40 #include <windows.h>
41 #elif UNIV_LINUX
42 #include <sys/time.h>
43 #include <sys/resource.h>
44 #include <unistd.h>
45 #include <sys/syscall.h>
46 #include <sys/types.h>
47 #endif
48
49 #ifndef UNIV_HOTBACKUP
50 #include "srv0srv.h"
51 #include "os0sync.h"
52
53 /***************************************************************//**
54 Compares two thread ids for equality.
55 @return TRUE if equal */
56 UNIV_INTERN
57 ibool
os_thread_eq(os_thread_id_t a,os_thread_id_t b)58 os_thread_eq(
59 /*=========*/
60 os_thread_id_t a, /*!< in: OS thread or thread id */
61 os_thread_id_t b) /*!< in: OS thread or thread id */
62 {
63 #ifdef __WIN__
64 if (a == b) {
65 return(TRUE);
66 }
67
68 return(FALSE);
69 #else
70 if (pthread_equal(a, b)) {
71 return(TRUE);
72 }
73
74 return(FALSE);
75 #endif
76 }
77
78 /****************************************************************//**
79 Converts an OS thread id to a ulint. It is NOT guaranteed that the ulint is
80 unique for the thread though!
81 @return thread identifier as a number */
82 UNIV_INTERN
83 ulint
os_thread_pf(os_thread_id_t a)84 os_thread_pf(
85 /*=========*/
86 os_thread_id_t a) /*!< in: OS thread identifier */
87 {
88 #ifdef UNIV_HPUX10
89 /* In HP-UX-10.20 a pthread_t is a struct of 3 fields: field1, field2,
90 field3. We do not know if field1 determines the thread uniquely. */
91
92 return((ulint)(a.field1));
93 #else
94 return((ulint) a);
95 #endif
96 }
97
98 /*****************************************************************//**
99 Returns the thread identifier of current thread. Currently the thread
100 identifier in Unix is the thread handle itself. Note that in HP-UX
101 pthread_t is a struct of 3 fields.
102 @return current thread identifier */
103 UNIV_INTERN
104 os_thread_id_t
os_thread_get_curr_id(void)105 os_thread_get_curr_id(void)
106 /*=======================*/
107 {
108 #ifdef __WIN__
109 return(GetCurrentThreadId());
110 #else
111 return(pthread_self());
112 #endif
113 }
114
115 /*****************************************************************//**
116 Returns the system-specific thread identifier of current thread. On Linux,
117 returns tid. On other systems currently returns os_thread_get_curr_id().
118
119 @return current thread identifier */
120 UNIV_INTERN
121 os_tid_t
os_thread_get_tid(void)122 os_thread_get_tid(void)
123 /*===================*/
124 {
125 #ifdef UNIV_LINUX
126 return((os_tid_t)syscall(SYS_gettid));
127 #else
128 return(os_thread_get_curr_id());
129 #endif
130 }
131
132
133 /****************************************************************//**
134 Creates a new thread of execution. The execution starts from
135 the function given. The start function takes a void* parameter
136 and returns an ulint.
137 @return handle to the thread */
138 UNIV_INTERN
139 os_thread_t
os_thread_create_func(os_thread_func_t func,void * arg,os_thread_id_t * thread_id)140 os_thread_create_func(
141 /*==================*/
142 os_thread_func_t func, /*!< in: pointer to function
143 from which to start */
144 void* arg, /*!< in: argument to start
145 function */
146 os_thread_id_t* thread_id) /*!< out: id of the created
147 thread, or NULL */
148 {
149 /* the new thread should look recent changes up here so far. */
150 os_wmb;
151
152 #ifdef __WIN__
153 os_thread_t thread;
154 DWORD win_thread_id;
155
156 os_atomic_increment_ulint(&os_thread_count, 1);
157
158 thread = CreateThread(NULL, /* no security attributes */
159 0, /* default size stack */
160 func,
161 arg,
162 0, /* thread runs immediately */
163 &win_thread_id);
164
165 if (thread_id) {
166 *thread_id = win_thread_id;
167 }
168
169 return(thread);
170 #else
171 int ret;
172 os_thread_t pthread;
173 pthread_attr_t attr;
174
175 #ifndef UNIV_HPUX10
176 pthread_attr_init(&attr);
177 #endif
178
179 #ifdef UNIV_AIX
180 /* We must make sure a thread stack is at least 32 kB, otherwise
181 InnoDB might crash; we do not know if the default stack size on
182 AIX is always big enough. An empirical test on AIX-4.3 suggested
183 the size was 96 kB, though. */
184
185 ret = pthread_attr_setstacksize(&attr,
186 (size_t)(PTHREAD_STACK_MIN
187 + 32 * 1024));
188 if (ret) {
189 fprintf(stderr,
190 "InnoDB: Error: pthread_attr_setstacksize"
191 " returned %d\n", ret);
192 exit(1);
193 }
194 #endif
195 ulint new_count = os_atomic_increment_ulint(&os_thread_count, 1);
196 ut_a(new_count <= OS_THREAD_MAX_N);
197
198 #ifdef UNIV_HPUX10
199 ret = pthread_create(&pthread, pthread_attr_default, func, arg);
200 #else
201 ret = pthread_create(&pthread, &attr, func, arg);
202 #endif
203 if (ret) {
204 fprintf(stderr,
205 "InnoDB: Error: pthread_create returned %d\n", ret);
206 exit(1);
207 }
208
209 #ifndef UNIV_HPUX10
210 pthread_attr_destroy(&attr);
211 #endif
212
213 if (thread_id) {
214 *thread_id = pthread;
215 }
216
217 return(pthread);
218 #endif
219 }
220
221 /** Waits until the specified thread completes and joins it.
222 Its return value is ignored.
223 @param[in,out] thread thread to join */
224 UNIV_INTERN
225 void
os_thread_join(os_thread_t thread)226 os_thread_join(
227 os_thread_t thread)
228 {
229 #ifdef __WIN__
230 /* Do nothing. */
231 #else
232 #ifdef UNIV_DEBUG
233 const int ret =
234 #endif /* UNIV_DEBUG */
235 pthread_join(thread, NULL);
236
237 /* Waiting on already-quit threads is allowed. */
238 ut_ad(ret == 0 || ret == ESRCH);
239 #endif /* __WIN__ */
240 }
241
242 /*****************************************************************//**
243 Exits the current thread. */
244 UNIV_INTERN
245 void
os_thread_exit(void * exit_value,bool detach)246 os_thread_exit(
247 /*===========*/
248 void* exit_value, /*!< in: exit value; in Windows this void*
249 is cast as a DWORD */
250 bool detach) /*!< in: if true, the thread will be detached
251 right before exiting. If false, another thread
252 is responsible for joining this thread. */
253 {
254 #ifdef UNIV_DEBUG_THREAD_CREATION
255 fprintf(stderr, "Thread exits, id %lu\n",
256 os_thread_pf(os_thread_get_curr_id()));
257 #endif
258
259 #ifdef UNIV_PFS_THREAD
260 pfs_delete_thread();
261 #endif
262
263 os_atomic_decrement_ulint(&os_thread_count, 1);
264
265 #ifdef __WIN__
266 ExitThread((DWORD) exit_value);
267 #else
268 if (detach) {
269 pthread_detach(pthread_self());
270 }
271 pthread_exit(exit_value);
272 #endif
273 }
274
275 /*****************************************************************//**
276 Advises the os to give up remainder of the thread's time slice. */
277 UNIV_INTERN
278 void
os_thread_yield(void)279 os_thread_yield(void)
280 /*=================*/
281 {
282 #if defined(__WIN__)
283 SwitchToThread();
284 #elif (defined(HAVE_SCHED_YIELD) && defined(HAVE_SCHED_H))
285 sched_yield();
286 #elif defined(HAVE_PTHREAD_YIELD_ZERO_ARG)
287 pthread_yield();
288 #elif defined(HAVE_PTHREAD_YIELD_ONE_ARG)
289 pthread_yield(0);
290 #else
291 os_thread_sleep(0);
292 #endif
293 }
294 #endif /* !UNIV_HOTBACKUP */
295
296 /*****************************************************************//**
297 The thread sleeps at least the time given in microseconds. */
298 UNIV_INTERN
299 void
os_thread_sleep(ulint tm)300 os_thread_sleep(
301 /*============*/
302 ulint tm) /*!< in: time in microseconds */
303 {
304 #ifdef __WIN__
305 Sleep((DWORD) tm / 1000);
306 #else
307 struct timeval t;
308
309 t.tv_sec = tm / 1000000;
310 t.tv_usec = tm % 1000000;
311
312 select(0, NULL, NULL, NULL, &t);
313 #endif
314 }
315
316 /*****************************************************************//**
317 Set relative scheduling priority for a given thread on Linux. Currently a
318 no-op on other systems.
319
320 @return An actual thread priority after the update */
321 UNIV_INTERN
322 ulint
os_thread_set_priority(os_tid_t thread_id,ulint relative_priority)323 os_thread_set_priority(
324 /*===================*/
325 os_tid_t thread_id, /*!< in: thread id */
326 ulint relative_priority) /*!< in: system-specific
327 priority value */
328 {
329 #ifdef UNIV_LINUX
330 lint thread_nice = 19 - relative_priority;
331 if (setpriority(PRIO_PROCESS, thread_id, thread_nice) == -1) {
332 ib_logf(IB_LOG_LEVEL_WARN,
333 "Setting thread %lu nice to %ld failed, "
334 "current nice %d, errno %d",
335 os_thread_pf(thread_id), thread_nice,
336 getpriority(PRIO_PROCESS, thread_id), errno);
337 }
338 return(19 - getpriority(PRIO_PROCESS, thread_id));
339 #else
340 return(relative_priority);
341 #endif
342 }
343