source: trunk/src/gcc/libjava/posix-threads.cc@ 2094

Last change on this file since 2094 was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

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