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