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

Last change on this file was 2, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 11.2 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
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.
36struct 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.
45pthread_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.
49pthread_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.
53static pthread_mutex_t daemon_mutex;
54static pthread_cond_t daemon_cond;
55static 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.
83int
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 (&current->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 (&current->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 (&current->wait_cond, &current->wait_mutex);
145 else
146 r = pthread_cond_timedwait (&current->wait_cond, &current->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 (&current->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
191int
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
230int
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
257void
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
275static void
276handle_intr (int)
277{
278 // Do nothing.
279}
280
281void
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
311void
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
319void
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, &param);
328 }
329}
330
331void
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
359void
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.
369static void *
370really_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
390void
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, &param);
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
431void
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.
445volatile 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 */
Note: See TracBrowser for help on using the repository browser.