1 /*****************************************************************************
2
3 Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
4
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16
17 *****************************************************************************/
18
19 /**************************************************//**
20 @file os/os0thread.c
21 The interface to the operating system thread control primitives
22
23 Created 9/8/1995 Heikki Tuuri
24 *******************************************************/
25
26 #include "os0thread.h"
27 #ifdef UNIV_NONINL
28 #include "os0thread.ic"
29 #endif
30
31 #ifdef __WIN__
32 #include <windows.h>
33 #endif
34
35 #ifndef UNIV_HOTBACKUP
36 #include "srv0srv.h"
37 #include "os0sync.h"
38
39 /***************************************************************//**
40 Compares two thread ids for equality.
41 @return TRUE if equal */
42 UNIV_INTERN
43 ibool
os_thread_eq(os_thread_id_t a,os_thread_id_t b)44 os_thread_eq(
45 /*=========*/
46 os_thread_id_t a, /*!< in: OS thread or thread id */
47 os_thread_id_t b) /*!< in: OS thread or thread id */
48 {
49 #ifdef __WIN__
50 if (a == b) {
51 return(TRUE);
52 }
53
54 return(FALSE);
55 #else
56 if (pthread_equal(a, b)) {
57 return(TRUE);
58 }
59
60 return(FALSE);
61 #endif
62 }
63
64 /****************************************************************//**
65 Converts an OS thread id to a ulint. It is NOT guaranteed that the ulint is
66 unique for the thread though!
67 @return thread identifier as a number */
68 UNIV_INTERN
69 ulint
os_thread_pf(os_thread_id_t a)70 os_thread_pf(
71 /*=========*/
72 os_thread_id_t a) /*!< in: OS thread identifier */
73 {
74 #ifdef UNIV_HPUX10
75 /* In HP-UX-10.20 a pthread_t is a struct of 3 fields: field1, field2,
76 field3. We do not know if field1 determines the thread uniquely. */
77
78 return((ulint)(a.field1));
79 #else
80 return((ulint)a);
81 #endif
82 }
83
84 /*****************************************************************//**
85 Returns the thread identifier of current thread. Currently the thread
86 identifier in Unix is the thread handle itself. Note that in HP-UX
87 pthread_t is a struct of 3 fields.
88 @return current thread identifier */
89 UNIV_INTERN
90 os_thread_id_t
os_thread_get_curr_id(void)91 os_thread_get_curr_id(void)
92 /*=======================*/
93 {
94 #ifdef __WIN__
95 return(GetCurrentThreadId());
96 #else
97 return(pthread_self());
98 #endif
99 }
100
101 /****************************************************************//**
102 Creates a new thread of execution. The execution starts from
103 the function given. The start function takes a void* parameter
104 and returns an ulint.
105 @return handle to the thread */
106 UNIV_INTERN
107 os_thread_t
os_thread_create(os_posix_f_t start_f,void * arg,os_thread_id_t * thread_id)108 os_thread_create(
109 /*=============*/
110 #ifndef __WIN__
111 os_posix_f_t start_f,
112 #else
113 ulint (*start_f)(void*), /*!< in: pointer to function
114 from which to start */
115 #endif
116 void* arg, /*!< in: argument to start
117 function */
118 os_thread_id_t* thread_id) /*!< out: id of the created
119 thread, or NULL */
120 {
121 #ifdef __WIN__
122 os_thread_t thread;
123 DWORD win_thread_id;
124
125 os_mutex_enter(os_sync_mutex);
126 os_thread_count++;
127 os_mutex_exit(os_sync_mutex);
128
129 thread = CreateThread(NULL, /* no security attributes */
130 0, /* default size stack */
131 (LPTHREAD_START_ROUTINE)start_f,
132 arg,
133 0, /* thread runs immediately */
134 &win_thread_id);
135
136 if (thread_id) {
137 *thread_id = win_thread_id;
138 }
139
140 return(thread);
141 #else
142 int ret;
143 os_thread_t pthread;
144 pthread_attr_t attr;
145
146 #ifndef UNIV_HPUX10
147 pthread_attr_init(&attr);
148 #endif
149
150 #ifdef UNIV_AIX
151 /* We must make sure a thread stack is at least 32 kB, otherwise
152 InnoDB might crash; we do not know if the default stack size on
153 AIX is always big enough. An empirical test on AIX-4.3 suggested
154 the size was 96 kB, though. */
155
156 ret = pthread_attr_setstacksize(&attr,
157 (size_t)(PTHREAD_STACK_MIN
158 + 32 * 1024));
159 if (ret) {
160 fprintf(stderr,
161 "InnoDB: Error: pthread_attr_setstacksize"
162 " returned %d\n", ret);
163 exit(1);
164 }
165 #endif
166 os_mutex_enter(os_sync_mutex);
167 os_thread_count++;
168 os_mutex_exit(os_sync_mutex);
169
170 #ifdef UNIV_HPUX10
171 ret = pthread_create(&pthread, pthread_attr_default, start_f, arg);
172 #else
173 ret = pthread_create(&pthread, &attr, start_f, arg);
174 #endif
175 if (ret) {
176 fprintf(stderr,
177 "InnoDB: Error: pthread_create returned %d\n", ret);
178 exit(1);
179 }
180
181 #ifndef UNIV_HPUX10
182 pthread_attr_destroy(&attr);
183 #endif
184 if (thread_id) {
185 *thread_id = pthread;
186 }
187
188 return(pthread);
189 #endif
190 }
191
192 /*****************************************************************//**
193 Exits the current thread. */
194 UNIV_INTERN
195 void
os_thread_exit(void * exit_value)196 os_thread_exit(
197 /*===========*/
198 void* exit_value) /*!< in: exit value; in Windows this void*
199 is cast as a DWORD */
200 {
201 #ifdef UNIV_DEBUG_THREAD_CREATION
202 fprintf(stderr, "Thread exits, id %lu\n",
203 os_thread_pf(os_thread_get_curr_id()));
204 #endif
205
206 #ifdef UNIV_PFS_THREAD
207 pfs_delete_thread();
208 #endif
209
210 os_mutex_enter(os_sync_mutex);
211 os_thread_count--;
212 os_mutex_exit(os_sync_mutex);
213
214 #ifdef __WIN__
215 ExitThread((DWORD)exit_value);
216 #else
217 pthread_detach(pthread_self());
218 pthread_exit(exit_value);
219 #endif
220 }
221
222 /*****************************************************************//**
223 Advises the os to give up remainder of the thread's time slice. */
224 UNIV_INTERN
225 void
os_thread_yield(void)226 os_thread_yield(void)
227 /*=================*/
228 {
229 #if defined(__WIN__)
230 SwitchToThread();
231 #elif (defined(HAVE_SCHED_YIELD) && defined(HAVE_SCHED_H))
232 sched_yield();
233 #elif defined(HAVE_PTHREAD_YIELD_ZERO_ARG)
234 pthread_yield();
235 #elif defined(HAVE_PTHREAD_YIELD_ONE_ARG)
236 pthread_yield(0);
237 #else
238 os_thread_sleep(0);
239 #endif
240 }
241 #endif /* !UNIV_HOTBACKUP */
242
243 /*****************************************************************//**
244 The thread sleeps at least the time given in microseconds. */
245 UNIV_INTERN
246 void
os_thread_sleep(ulint tm)247 os_thread_sleep(
248 /*============*/
249 ulint tm) /*!< in: time in microseconds */
250 {
251 #ifdef __WIN__
252 Sleep((DWORD) tm / 1000);
253 #else
254 struct timeval t;
255
256 t.tv_sec = tm / 1000000;
257 t.tv_usec = tm % 1000000;
258
259 select(0, NULL, NULL, NULL, &t);
260 #endif
261 }
262