1 | // posix-threads.cc - interface between libjava and POSIX threads.
|
---|
2 |
|
---|
3 | /* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation
|
---|
4 |
|
---|
5 | This file is part of libgcj.
|
---|
6 |
|
---|
7 | This software is copyrighted work licensed under the terms of the
|
---|
8 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
---|
9 | details. */
|
---|
10 |
|
---|
11 | // TO DO:
|
---|
12 | // * Document signal handling limitations
|
---|
13 |
|
---|
14 | #include <config.h>
|
---|
15 |
|
---|
16 | // If we're using the Boehm GC, then we need to override some of the
|
---|
17 | // thread primitives. This is fairly gross.
|
---|
18 | #ifdef HAVE_BOEHM_GC
|
---|
19 | #include <gc.h>
|
---|
20 | #endif /* HAVE_BOEHM_GC */
|
---|
21 |
|
---|
22 | #include <stdlib.h>
|
---|
23 | #include <time.h>
|
---|
24 | #include <signal.h>
|
---|
25 | #include <errno.h>
|
---|
26 | #include <limits.h>
|
---|
27 |
|
---|
28 | #include <gcj/cni.h>
|
---|
29 | #include <jvm.h>
|
---|
30 | #include <java/lang/Thread.h>
|
---|
31 | #include <java/lang/System.h>
|
---|
32 | #include <java/lang/Long.h>
|
---|
33 | #include <java/lang/OutOfMemoryError.h>
|
---|
34 |
|
---|
35 | // This is used to implement thread startup.
|
---|
36 | struct starter
|
---|
37 | {
|
---|
38 | _Jv_ThreadStartFunc *method;
|
---|
39 | _Jv_Thread_t *data;
|
---|
40 | };
|
---|
41 |
|
---|
42 | // This is the key used to map from the POSIX thread value back to the
|
---|
43 | // Java object representing the thread. The key is global to all
|
---|
44 | // threads, so it is ok to make it a global here.
|
---|
45 | pthread_key_t _Jv_ThreadKey;
|
---|
46 |
|
---|
47 | // This is the key used to map from the POSIX thread value back to the
|
---|
48 | // _Jv_Thread_t* representing the thread.
|
---|
49 | pthread_key_t _Jv_ThreadDataKey;
|
---|
50 |
|
---|
51 | // We keep a count of all non-daemon threads which are running. When
|
---|
52 | // this reaches zero, _Jv_ThreadWait returns.
|
---|
53 | static pthread_mutex_t daemon_mutex;
|
---|
54 | static pthread_cond_t daemon_cond;
|
---|
55 | static int non_daemon_count;
|
---|
56 |
|
---|
57 | // The signal to use when interrupting a thread.
|
---|
58 | #if defined(LINUX_THREADS) || defined(FREEBSD_THREADS)
|
---|
59 | // LinuxThreads (prior to glibc 2.1) usurps both SIGUSR1 and SIGUSR2.
|
---|
60 | // GC on FreeBSD uses both SIGUSR1 and SIGUSR2.
|
---|
61 | # define INTR SIGHUP
|
---|
62 | #else /* LINUX_THREADS */
|
---|
63 | # define INTR SIGUSR2
|
---|
64 | #endif /* LINUX_THREADS */
|
---|
65 |
|
---|
66 | //
|
---|
67 | // These are the flags that can appear in _Jv_Thread_t.
|
---|
68 | //
|
---|
69 |
|
---|
70 | // Thread started.
|
---|
71 | #define FLAG_START 0x01
|
---|
72 | // Thread is daemon.
|
---|
73 | #define FLAG_DAEMON 0x02
|
---|
74 |
|
---|
75 | |
---|
76 |
|
---|
77 |
|
---|
78 | // Wait for the condition variable "CV" to be notified.
|
---|
79 | // Return values:
|
---|
80 | // 0: the condition was notified, or the timeout expired.
|
---|
81 | // _JV_NOT_OWNER: the thread does not own the mutex "MU".
|
---|
82 | // _JV_INTERRUPTED: the thread was interrupted. Its interrupted flag is set.
|
---|
83 | int
|
---|
84 | _Jv_CondWait (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu,
|
---|
85 | jlong millis, jint nanos)
|
---|
86 | {
|
---|
87 | pthread_t self = pthread_self();
|
---|
88 | if (mu->owner != self)
|
---|
89 | return _JV_NOT_OWNER;
|
---|
90 |
|
---|
91 | struct timespec ts;
|
---|
92 | jlong m, startTime;
|
---|
93 |
|
---|
94 | if (millis > 0 || nanos > 0)
|
---|
95 | {
|
---|
96 | startTime = java::lang::System::currentTimeMillis();
|
---|
97 | m = millis + startTime;
|
---|
98 | ts.tv_sec = m / 1000;
|
---|
99 | ts.tv_nsec = ((m % 1000) * 1000000) + nanos;
|
---|
100 | }
|
---|
101 |
|
---|
102 | _Jv_Thread_t *current = _Jv_ThreadCurrentData ();
|
---|
103 | java::lang::Thread *current_obj = _Jv_ThreadCurrent ();
|
---|
104 |
|
---|
105 | pthread_mutex_lock (¤t->wait_mutex);
|
---|
106 |
|
---|
107 | // Now that we hold the wait mutex, check if this thread has been
|
---|
108 | // interrupted already.
|
---|
109 | if (current_obj->interrupt_flag)
|
---|
110 | {
|
---|
111 | pthread_mutex_unlock (¤t->wait_mutex);
|
---|
112 | return _JV_INTERRUPTED;
|
---|
113 | }
|
---|
114 |
|
---|
115 | // Add this thread to the cv's wait set.
|
---|
116 | current->next = NULL;
|
---|
117 |
|
---|
118 | if (cv->first == NULL)
|
---|
119 | cv->first = current;
|
---|
120 | else
|
---|
121 | for (_Jv_Thread_t *t = cv->first;; t = t->next)
|
---|
122 | {
|
---|
123 | if (t->next == NULL)
|
---|
124 | {
|
---|
125 | t->next = current;
|
---|
126 | break;
|
---|
127 | }
|
---|
128 | }
|
---|
129 |
|
---|
130 | // Record the current lock depth, so it can be restored when we re-aquire it.
|
---|
131 | int count = mu->count;
|
---|
132 |
|
---|
133 | // Release the monitor mutex.
|
---|
134 | mu->count = 0;
|
---|
135 | mu->owner = 0;
|
---|
136 | pthread_mutex_unlock (&mu->mutex);
|
---|
137 |
|
---|
138 | int r = 0;
|
---|
139 | bool done_sleeping = false;
|
---|
140 |
|
---|
141 | while (! done_sleeping)
|
---|
142 | {
|
---|
143 | if (millis == 0 && nanos == 0)
|
---|
144 | r = pthread_cond_wait (¤t->wait_cond, ¤t->wait_mutex);
|
---|
145 | else
|
---|
146 | r = pthread_cond_timedwait (¤t->wait_cond, ¤t->wait_mutex,
|
---|
147 | &ts);
|
---|
148 |
|
---|
149 | // In older glibc's (prior to 2.1.3), the cond_wait functions may
|
---|
150 | // spuriously wake up on a signal. Catch that here.
|
---|
151 | if (r != EINTR)
|
---|
152 | done_sleeping = true;
|
---|
153 | }
|
---|
154 |
|
---|
155 | // Check for an interrupt *before* releasing the wait mutex.
|
---|
156 | jboolean interrupted = current_obj->interrupt_flag;
|
---|
157 |
|
---|
158 | pthread_mutex_unlock (¤t->wait_mutex);
|
---|
159 |
|
---|
160 | // Reaquire the monitor mutex, and restore the lock count.
|
---|
161 | pthread_mutex_lock (&mu->mutex);
|
---|
162 | mu->owner = self;
|
---|
163 | mu->count = count;
|
---|
164 |
|
---|
165 | // If we were interrupted, or if a timeout occurred, remove ourself from
|
---|
166 | // the cv wait list now. (If we were notified normally, notify() will have
|
---|
167 | // already taken care of this)
|
---|
168 | if (r == ETIMEDOUT || interrupted)
|
---|
169 | {
|
---|
170 | _Jv_Thread_t *prev = NULL;
|
---|
171 | for (_Jv_Thread_t *t = cv->first; t != NULL; t = t->next)
|
---|
172 | {
|
---|
173 | if (t == current)
|
---|
174 | {
|
---|
175 | if (prev != NULL)
|
---|
176 | prev->next = t->next;
|
---|
177 | else
|
---|
178 | cv->first = t->next;
|
---|
179 | t->next = NULL;
|
---|
180 | break;
|
---|
181 | }
|
---|
182 | prev = t;
|
---|
183 | }
|
---|
184 | if (interrupted)
|
---|
185 | return _JV_INTERRUPTED;
|
---|
186 | }
|
---|
187 |
|
---|
188 | return 0;
|
---|
189 | }
|
---|
190 |
|
---|
191 | int
|
---|
192 | _Jv_CondNotify (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu)
|
---|
193 | {
|
---|
194 | if (_Jv_PthreadCheckMonitor (mu))
|
---|
195 | return _JV_NOT_OWNER;
|
---|
196 |
|
---|
197 | _Jv_Thread_t *target;
|
---|
198 | _Jv_Thread_t *prev = NULL;
|
---|
199 |
|
---|
200 | for (target = cv->first; target != NULL; target = target->next)
|
---|
201 | {
|
---|
202 | pthread_mutex_lock (&target->wait_mutex);
|
---|
203 |
|
---|
204 | if (target->thread_obj->interrupt_flag)
|
---|
205 | {
|
---|
206 | // Don't notify a thread that has already been interrupted.
|
---|
207 | pthread_mutex_unlock (&target->wait_mutex);
|
---|
208 | prev = target;
|
---|
209 | continue;
|
---|
210 | }
|
---|
211 |
|
---|
212 | pthread_cond_signal (&target->wait_cond);
|
---|
213 | pthread_mutex_unlock (&target->wait_mutex);
|
---|
214 |
|
---|
215 | // Two concurrent notify() calls must not be delivered to the same
|
---|
216 | // thread, so remove the target thread from the cv wait list now.
|
---|
217 | if (prev == NULL)
|
---|
218 | cv->first = target->next;
|
---|
219 | else
|
---|
220 | prev->next = target->next;
|
---|
221 |
|
---|
222 | target->next = NULL;
|
---|
223 |
|
---|
224 | break;
|
---|
225 | }
|
---|
226 |
|
---|
227 | return 0;
|
---|
228 | }
|
---|
229 |
|
---|
230 | int
|
---|
231 | _Jv_CondNotifyAll (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu)
|
---|
232 | {
|
---|
233 | if (_Jv_PthreadCheckMonitor (mu))
|
---|
234 | return _JV_NOT_OWNER;
|
---|
235 |
|
---|
236 | _Jv_Thread_t *target;
|
---|
237 | _Jv_Thread_t *prev = NULL;
|
---|
238 |
|
---|
239 | for (target = cv->first; target != NULL; target = target->next)
|
---|
240 | {
|
---|
241 | pthread_mutex_lock (&target->wait_mutex);
|
---|
242 | pthread_cond_signal (&target->wait_cond);
|
---|
243 | pthread_mutex_unlock (&target->wait_mutex);
|
---|
244 |
|
---|
245 | if (prev != NULL)
|
---|
246 | prev->next = NULL;
|
---|
247 | prev = target;
|
---|
248 | }
|
---|
249 | if (prev != NULL)
|
---|
250 | prev->next = NULL;
|
---|
251 |
|
---|
252 | cv->first = NULL;
|
---|
253 |
|
---|
254 | return 0;
|
---|
255 | }
|
---|
256 |
|
---|
257 | void
|
---|
258 | _Jv_ThreadInterrupt (_Jv_Thread_t *data)
|
---|
259 | {
|
---|
260 | pthread_mutex_lock (&data->wait_mutex);
|
---|
261 |
|
---|
262 | // Set the thread's interrupted flag *after* aquiring its wait_mutex. This
|
---|
263 | // ensures that there are no races with the interrupt flag being set after
|
---|
264 | // the waiting thread checks it and before pthread_cond_wait is entered.
|
---|
265 | data->thread_obj->interrupt_flag = true;
|
---|
266 |
|
---|
267 | // Interrupt blocking system calls using a signal.
|
---|
268 | pthread_kill (data->thread, INTR);
|
---|
269 |
|
---|
270 | pthread_cond_signal (&data->wait_cond);
|
---|
271 |
|
---|
272 | pthread_mutex_unlock (&data->wait_mutex);
|
---|
273 | }
|
---|
274 |
|
---|
275 | static void
|
---|
276 | handle_intr (int)
|
---|
277 | {
|
---|
278 | // Do nothing.
|
---|
279 | }
|
---|
280 |
|
---|
281 | void
|
---|
282 | _Jv_InitThreads (void)
|
---|
283 | {
|
---|
284 | pthread_key_create (&_Jv_ThreadKey, NULL);
|
---|
285 | pthread_key_create (&_Jv_ThreadDataKey, NULL);
|
---|
286 | pthread_mutex_init (&daemon_mutex, NULL);
|
---|
287 | pthread_cond_init (&daemon_cond, 0);
|
---|
288 | non_daemon_count = 0;
|
---|
289 |
|
---|
290 | // Arrange for the interrupt signal to interrupt system calls.
|
---|
291 | struct sigaction act;
|
---|
292 | act.sa_handler = handle_intr;
|
---|
293 | sigemptyset (&act.sa_mask);
|
---|
294 | act.sa_flags = 0;
|
---|
295 | sigaction (INTR, &act, NULL);
|
---|
296 | }
|
---|
297 |
|
---|
298 | _Jv_Thread_t *
|
---|
299 | _Jv_ThreadInitData (java::lang::Thread *obj)
|
---|
300 | {
|
---|
301 | _Jv_Thread_t *data = (_Jv_Thread_t *) _Jv_Malloc (sizeof (_Jv_Thread_t));
|
---|
302 | data->flags = 0;
|
---|
303 | data->thread_obj = obj;
|
---|
304 |
|
---|
305 | pthread_mutex_init (&data->wait_mutex, NULL);
|
---|
306 | pthread_cond_init (&data->wait_cond, NULL);
|
---|
307 |
|
---|
308 | return data;
|
---|
309 | }
|
---|
310 |
|
---|
311 | void
|
---|
312 | _Jv_ThreadDestroyData (_Jv_Thread_t *data)
|
---|
313 | {
|
---|
314 | pthread_mutex_destroy (&data->wait_mutex);
|
---|
315 | pthread_cond_destroy (&data->wait_cond);
|
---|
316 | _Jv_Free ((void *)data);
|
---|
317 | }
|
---|
318 |
|
---|
319 | void
|
---|
320 | _Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio)
|
---|
321 | {
|
---|
322 | if (data->flags & FLAG_START)
|
---|
323 | {
|
---|
324 | struct sched_param param;
|
---|
325 |
|
---|
326 | param.sched_priority = prio;
|
---|
327 | pthread_setschedparam (data->thread, SCHED_RR, ¶m);
|
---|
328 | }
|
---|
329 | }
|
---|
330 |
|
---|
331 | void
|
---|
332 | _Jv_ThreadRegister (_Jv_Thread_t *data)
|
---|
333 | {
|
---|
334 | pthread_setspecific (_Jv_ThreadKey, data->thread_obj);
|
---|
335 | pthread_setspecific (_Jv_ThreadDataKey, data);
|
---|
336 |
|
---|
337 | // glibc 2.1.3 doesn't set the value of `thread' until after start_routine
|
---|
338 | // is called. Since it may need to be accessed from the new thread, work
|
---|
339 | // around the potential race here by explicitly setting it again.
|
---|
340 | data->thread = pthread_self ();
|
---|
341 |
|
---|
342 | # ifdef SLOW_PTHREAD_SELF
|
---|
343 | // Clear all self cache slots that might be needed by this thread.
|
---|
344 | int dummy;
|
---|
345 | int low_index = SC_INDEX(&dummy) + SC_CLEAR_MIN;
|
---|
346 | int high_index = SC_INDEX(&dummy) + SC_CLEAR_MAX;
|
---|
347 | for (int i = low_index; i <= high_index; ++i)
|
---|
348 | {
|
---|
349 | int current_index = i;
|
---|
350 | if (current_index < 0)
|
---|
351 | current_index += SELF_CACHE_SIZE;
|
---|
352 | if (current_index >= SELF_CACHE_SIZE)
|
---|
353 | current_index -= SELF_CACHE_SIZE;
|
---|
354 | _Jv_self_cache[current_index].high_sp_bits = BAD_HIGH_SP_VALUE;
|
---|
355 | }
|
---|
356 | # endif
|
---|
357 | }
|
---|
358 |
|
---|
359 | void
|
---|
360 | _Jv_ThreadUnRegister ()
|
---|
361 | {
|
---|
362 | pthread_setspecific (_Jv_ThreadKey, NULL);
|
---|
363 | pthread_setspecific (_Jv_ThreadDataKey, NULL);
|
---|
364 | }
|
---|
365 |
|
---|
366 | // This function is called when a thread is started. We don't arrange
|
---|
367 | // to call the `run' method directly, because this function must
|
---|
368 | // return a value.
|
---|
369 | static void *
|
---|
370 | really_start (void *x)
|
---|
371 | {
|
---|
372 | struct starter *info = (struct starter *) x;
|
---|
373 |
|
---|
374 | _Jv_ThreadRegister (info->data);
|
---|
375 |
|
---|
376 | info->method (info->data->thread_obj);
|
---|
377 |
|
---|
378 | if (! (info->data->flags & FLAG_DAEMON))
|
---|
379 | {
|
---|
380 | pthread_mutex_lock (&daemon_mutex);
|
---|
381 | --non_daemon_count;
|
---|
382 | if (! non_daemon_count)
|
---|
383 | pthread_cond_signal (&daemon_cond);
|
---|
384 | pthread_mutex_unlock (&daemon_mutex);
|
---|
385 | }
|
---|
386 |
|
---|
387 | return NULL;
|
---|
388 | }
|
---|
389 |
|
---|
390 | void
|
---|
391 | _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data,
|
---|
392 | _Jv_ThreadStartFunc *meth)
|
---|
393 | {
|
---|
394 | struct sched_param param;
|
---|
395 | pthread_attr_t attr;
|
---|
396 | struct starter *info;
|
---|
397 |
|
---|
398 | if (data->flags & FLAG_START)
|
---|
399 | return;
|
---|
400 | data->flags |= FLAG_START;
|
---|
401 |
|
---|
402 | param.sched_priority = thread->getPriority();
|
---|
403 |
|
---|
404 | pthread_attr_init (&attr);
|
---|
405 | pthread_attr_setschedparam (&attr, ¶m);
|
---|
406 | pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
|
---|
407 |
|
---|
408 | info = (struct starter *) _Jv_AllocBytes (sizeof (struct starter));
|
---|
409 | info->method = meth;
|
---|
410 | info->data = data;
|
---|
411 |
|
---|
412 | if (! thread->isDaemon())
|
---|
413 | {
|
---|
414 | pthread_mutex_lock (&daemon_mutex);
|
---|
415 | ++non_daemon_count;
|
---|
416 | pthread_mutex_unlock (&daemon_mutex);
|
---|
417 | }
|
---|
418 | else
|
---|
419 | data->flags |= FLAG_DAEMON;
|
---|
420 | int r = pthread_create (&data->thread, &attr, really_start, (void *) info);
|
---|
421 |
|
---|
422 | pthread_attr_destroy (&attr);
|
---|
423 |
|
---|
424 | if (r)
|
---|
425 | {
|
---|
426 | const char* msg = "Cannot create additional threads";
|
---|
427 | throw new java::lang::OutOfMemoryError (JvNewStringUTF (msg));
|
---|
428 | }
|
---|
429 | }
|
---|
430 |
|
---|
431 | void
|
---|
432 | _Jv_ThreadWait (void)
|
---|
433 | {
|
---|
434 | pthread_mutex_lock (&daemon_mutex);
|
---|
435 | if (non_daemon_count)
|
---|
436 | pthread_cond_wait (&daemon_cond, &daemon_mutex);
|
---|
437 | pthread_mutex_unlock (&daemon_mutex);
|
---|
438 | }
|
---|
439 |
|
---|
440 | #if defined(SLOW_PTHREAD_SELF)
|
---|
441 |
|
---|
442 | #include "sysdep/locks.h"
|
---|
443 |
|
---|
444 | // Support for pthread_self() lookup cache.
|
---|
445 | volatile self_cache_entry _Jv_self_cache[SELF_CACHE_SIZE];
|
---|
446 |
|
---|
447 | _Jv_ThreadId_t
|
---|
448 | _Jv_ThreadSelf_out_of_line(volatile self_cache_entry *sce, size_t high_sp_bits)
|
---|
449 | {
|
---|
450 | pthread_t self = pthread_self();
|
---|
451 | sce -> high_sp_bits = high_sp_bits;
|
---|
452 | write_barrier();
|
---|
453 | sce -> self = self;
|
---|
454 | return self;
|
---|
455 | }
|
---|
456 |
|
---|
457 | #endif /* SLOW_PTHREAD_SELF */
|
---|