source: vendor/gcc/3.3.5/libjava/posix-threads.cc

Last change on this file was 1391, checked in by bird, 21 years ago

GCC v3.3.3 sources.

  • 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.