]> gcc.gnu.org Git - gcc.git/blame - libjava/posix-threads.cc
* extend.texi: Update for CPP.
[gcc.git] / libjava / posix-threads.cc
CommitLineData
ee9dd372
TT
1// posix-threads.cc - interface between libjava and POSIX threads.
2
304daac5 3/* Copyright (C) 1998, 1999, 2000 Free Software Foundation
ee9dd372
TT
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
19extern "C"
20{
8fbe2d95 21#include <gcconfig.h>
ee9dd372
TT
22#include <gc.h>
23};
24#endif /* HAVE_BOEHM_GC */
25
26#include <stdlib.h>
27#include <time.h>
28#include <signal.h>
d55d01bd 29#include <errno.h>
43cbc943 30#include <limits.h>
ee9dd372 31
27e934d8 32#include <gcj/cni.h>
ee9dd372
TT
33#include <jvm.h>
34#include <java/lang/Thread.h>
35#include <java/lang/System.h>
43cbc943
BM
36#include <java/lang/Long.h>
37#include <java/lang/OutOfMemoryError.h>
ee9dd372
TT
38
39// This is used to implement thread startup.
40struct starter
41{
42 _Jv_ThreadStartFunc *method;
ee9dd372
TT
43 _Jv_Thread_t *data;
44};
45
46// This is the key used to map from the POSIX thread value back to the
47// Java object representing the thread. The key is global to all
48// threads, so it is ok to make it a global here.
49pthread_key_t _Jv_ThreadKey;
50
fd59e3a0
TT
51// This is the key used to map from the POSIX thread value back to the
52// _Jv_Thread_t* representing the thread.
53pthread_key_t _Jv_ThreadDataKey;
54
ee9dd372
TT
55// We keep a count of all non-daemon threads which are running. When
56// this reaches zero, _Jv_ThreadWait returns.
57static pthread_mutex_t daemon_mutex;
58static pthread_cond_t daemon_cond;
59static int non_daemon_count;
60
61// The signal to use when interrupting a thread.
62#ifdef LINUX_THREADS
43cbc943 63 // LinuxThreads (prior to glibc 2.1) usurps both SIGUSR1 and SIGUSR2.
ee9dd372
TT
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\f
79
b834f1fa
BM
80// Wait for the condition variable "CV" to be notified.
81// Return values:
82// 0: the condition was notified, or the timeout expired.
83// _JV_NOT_OWNER: the thread does not own the mutex "MU".
84// _JV_INTERRUPTED: the thread was interrupted. Its interrupted flag is set.
ee9dd372
TT
85int
86_Jv_CondWait (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu,
87 jlong millis, jint nanos)
88{
b834f1fa
BM
89 pthread_t self = pthread_self();
90 if (mu->owner != self)
91 return _JV_NOT_OWNER;
6e87747b 92
43cbc943 93 struct timespec ts;
b834f1fa 94 jlong m, startTime;
6e87747b 95
b834f1fa 96 if (millis > 0 || nanos > 0)
ee9dd372 97 {
fd59e3a0
TT
98 startTime = java::lang::System::currentTimeMillis();
99 m = millis + startTime;
43cbc943
BM
100 ts.tv_sec = m / 1000;
101 ts.tv_nsec = ((m % 1000) * 1000000) + nanos;
102 }
fd59e3a0 103
b834f1fa
BM
104 _Jv_Thread_t *current = _Jv_ThreadCurrentData ();
105 java::lang::Thread *current_obj = _Jv_ThreadCurrent ();
106
304daac5
TT
107 pthread_mutex_lock (&current->wait_mutex);
108
109 // Now that we hold the wait mutex, check if this thread has been
110 // interrupted already.
111 if (current_obj->interrupt_flag)
112 {
113 pthread_mutex_unlock (&current->wait_mutex);
114 return _JV_INTERRUPTED;
115 }
116
b834f1fa
BM
117 // Add this thread to the cv's wait set.
118 current->next = NULL;
fd59e3a0 119
b834f1fa
BM
120 if (cv->first == NULL)
121 cv->first = current;
122 else
123 for (_Jv_Thread_t *t = cv->first;; t = t->next)
124 {
125 if (t->next == NULL)
126 {
127 t->next = current;
128 break;
129 }
130 }
131
b834f1fa
BM
132 // Record the current lock depth, so it can be restored when we re-aquire it.
133 int count = mu->count;
134
135 // Release the monitor mutex.
136 mu->count = 0;
137 mu->owner = 0;
138 pthread_mutex_unlock (&mu->mutex);
139
140 int r = 0;
141 bool done_sleeping = false;
142
143 while (! done_sleeping)
144 {
145 if (millis == 0 && nanos == 0)
146 r = pthread_cond_wait (&current->wait_cond, &current->wait_mutex);
147 else
148 r = pthread_cond_timedwait (&current->wait_cond, &current->wait_mutex,
149 &ts);
e301621d 150
b834f1fa
BM
151 // In older glibc's (prior to 2.1.3), the cond_wait functions may
152 // spuriously wake up on a signal. Catch that here.
153 if (r != EINTR)
154 done_sleeping = true;
155 }
156
304daac5 157 // Check for an interrupt *before* releasing the wait mutex.
b834f1fa
BM
158 jboolean interrupted = current_obj->interrupt_flag;
159
160 pthread_mutex_unlock (&current->wait_mutex);
161
162 // Reaquire the monitor mutex, and restore the lock count.
163 pthread_mutex_lock (&mu->mutex);
164 mu->owner = self;
165 mu->count = count;
166
167 // If we were interrupted, or if a timeout occured, remove ourself from
168 // the cv wait list now. (If we were notified normally, notify() will have
169 // already taken care of this)
170 if (r == ETIMEDOUT || interrupted)
171 {
172 _Jv_Thread_t *prev = NULL;
173 for (_Jv_Thread_t *t = cv->first; t != NULL; t = t->next)
43cbc943 174 {
b834f1fa 175 if (t == current)
fd59e3a0 176 {
b834f1fa
BM
177 if (prev != NULL)
178 prev->next = t->next;
179 else
180 cv->first = t->next;
181 t->next = NULL;
182 break;
fd59e3a0 183 }
b834f1fa 184 prev = t;
fd59e3a0 185 }
b834f1fa
BM
186 if (interrupted)
187 return _JV_INTERRUPTED;
ee9dd372 188 }
b834f1fa
BM
189
190 return 0;
ee9dd372
TT
191}
192
b834f1fa
BM
193int
194_Jv_CondNotify (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu)
ee9dd372 195{
b834f1fa
BM
196 if (_Jv_PthreadCheckMonitor (mu))
197 return _JV_NOT_OWNER;
ee9dd372 198
b834f1fa
BM
199 _Jv_Thread_t *target;
200 _Jv_Thread_t *prev = NULL;
ee9dd372 201
b834f1fa
BM
202 for (target = cv->first; target != NULL; target = target->next)
203 {
204 pthread_mutex_lock (&target->wait_mutex);
ee9dd372 205
b834f1fa
BM
206 if (target->thread_obj->interrupt_flag)
207 {
208 // Don't notify a thread that has already been interrupted.
209 pthread_mutex_unlock (&target->wait_mutex);
210 prev = target;
211 continue;
212 }
ee9dd372 213
b834f1fa
BM
214 pthread_cond_signal (&target->wait_cond);
215 pthread_mutex_unlock (&target->wait_mutex);
ee9dd372 216
f52c7239
BM
217 // Two concurrent notify() calls must not be delivered to the same
218 // thread, so remove the target thread from the cv wait list now.
b834f1fa
BM
219 if (prev == NULL)
220 cv->first = target->next;
221 else
222 prev->next = target->next;
223
224 target->next = NULL;
225
226 break;
227 }
ee9dd372 228
b834f1fa 229 return 0;
ee9dd372
TT
230}
231
232int
b834f1fa 233_Jv_CondNotifyAll (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu)
ee9dd372 234{
b834f1fa
BM
235 if (_Jv_PthreadCheckMonitor (mu))
236 return _JV_NOT_OWNER;
237
238 _Jv_Thread_t *target;
239 _Jv_Thread_t *prev = NULL;
240
241 for (target = cv->first; target != NULL; target = target->next)
ee9dd372 242 {
b834f1fa
BM
243 pthread_mutex_lock (&target->wait_mutex);
244 pthread_cond_signal (&target->wait_cond);
245 pthread_mutex_unlock (&target->wait_mutex);
246
247 if (prev != NULL)
248 prev->next = NULL;
249 prev = target;
ee9dd372 250 }
b834f1fa
BM
251 if (prev != NULL)
252 prev->next = NULL;
253
254 cv->first = NULL;
255
ee9dd372
TT
256 return 0;
257}
258
b834f1fa
BM
259void
260_Jv_ThreadInterrupt (_Jv_Thread_t *data)
ee9dd372 261{
b834f1fa 262 pthread_mutex_lock (&data->wait_mutex);
ee9dd372 263
b834f1fa
BM
264 // Set the thread's interrupted flag *after* aquiring its wait_mutex. This
265 // ensures that there are no races with the interrupt flag being set after
266 // the waiting thread checks it and before pthread_cond_wait is entered.
267 data->thread_obj->interrupt_flag = true;
268
269 // Interrupt blocking system calls using a signal.
270// pthread_kill (data->thread, INTR);
271
272 pthread_cond_signal (&data->wait_cond);
273
274 pthread_mutex_unlock (&data->wait_mutex);
275}
ee9dd372
TT
276
277static void
278handle_intr (int)
279{
280 // Do nothing.
281}
282
283void
284_Jv_InitThreads (void)
285{
286 pthread_key_create (&_Jv_ThreadKey, NULL);
fd59e3a0 287 pthread_key_create (&_Jv_ThreadDataKey, NULL);
ee9dd372
TT
288 pthread_mutex_init (&daemon_mutex, NULL);
289 pthread_cond_init (&daemon_cond, 0);
290 non_daemon_count = 0;
291
292 // Arrange for the interrupt signal to interrupt system calls.
293 struct sigaction act;
294 act.sa_handler = handle_intr;
295 sigemptyset (&act.sa_mask);
296 act.sa_flags = 0;
297 sigaction (INTR, &act, NULL);
ee9dd372
TT
298}
299
e301621d
BM
300_Jv_Thread_t *
301_Jv_ThreadInitData (java::lang::Thread *obj)
ee9dd372 302{
e301621d
BM
303 _Jv_Thread_t *data = new _Jv_Thread_t;
304 data->flags = 0;
305 data->thread_obj = obj;
b834f1fa 306
e301621d
BM
307 pthread_mutex_init (&data->wait_mutex, NULL);
308 pthread_cond_init (&data->wait_cond, NULL);
ee9dd372 309
e301621d
BM
310 return data;
311}
ee9dd372 312
e301621d
BM
313void
314_Jv_ThreadDestroyData (_Jv_Thread_t *data)
315{
316 pthread_mutex_destroy (&data->wait_mutex);
317 pthread_cond_destroy (&data->wait_cond);
318 delete data;
ee9dd372
TT
319}
320
321void
322_Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio)
323{
324 if (data->flags & FLAG_START)
325 {
326 struct sched_param param;
327
328 param.sched_priority = prio;
329 pthread_setschedparam (data->thread, SCHED_RR, &param);
330 }
331}
332
ee9dd372
TT
333// This function is called when a thread is started. We don't arrange
334// to call the `run' method directly, because this function must
335// return a value.
336static void *
337really_start (void *x)
338{
339 struct starter *info = (struct starter *) x;
340
b834f1fa 341 pthread_setspecific (_Jv_ThreadKey, info->data->thread_obj);
fd59e3a0 342 pthread_setspecific (_Jv_ThreadDataKey, info->data);
ee9dd372 343
b834f1fa
BM
344 // glibc 2.1.3 doesn't set the value of `thread' until after start_routine
345 // is called. Since it may need to be accessed from the new thread, work
346 // around the potential race here by explicitly setting it again.
347 info->data->thread = pthread_self ();
348
349 info->method (info->data->thread_obj);
350
ee9dd372
TT
351 if (! (info->data->flags & FLAG_DAEMON))
352 {
353 pthread_mutex_lock (&daemon_mutex);
354 --non_daemon_count;
355 if (! non_daemon_count)
356 pthread_cond_signal (&daemon_cond);
357 pthread_mutex_unlock (&daemon_mutex);
358 }
b834f1fa 359
ee9dd372
TT
360 return NULL;
361}
362
363void
364_Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data,
365 _Jv_ThreadStartFunc *meth)
366{
367 struct sched_param param;
368 pthread_attr_t attr;
369 struct starter *info;
370
371 if (data->flags & FLAG_START)
372 return;
373 data->flags |= FLAG_START;
374
375 param.sched_priority = thread->getPriority();
376
377 pthread_attr_init (&attr);
378 pthread_attr_setschedparam (&attr, &param);
e301621d 379 pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
ee9dd372
TT
380
381 // FIXME: handle marking the info object for GC.
382 info = (struct starter *) _Jv_AllocBytes (sizeof (struct starter));
383 info->method = meth;
ee9dd372
TT
384 info->data = data;
385
386 if (! thread->isDaemon())
387 {
388 pthread_mutex_lock (&daemon_mutex);
389 ++non_daemon_count;
390 pthread_mutex_unlock (&daemon_mutex);
391 }
392 else
393 data->flags |= FLAG_DAEMON;
43cbc943
BM
394 int r = pthread_create (&data->thread, &attr, really_start, (void *) info);
395
ee9dd372 396 pthread_attr_destroy (&attr);
43cbc943
BM
397
398 if (r)
399 {
400 const char* msg = "Cannot create additional threads";
401 JvThrow (new java::lang::OutOfMemoryError (JvNewStringUTF (msg)));
402 }
ee9dd372
TT
403}
404
405void
406_Jv_ThreadWait (void)
407{
ee9dd372
TT
408 pthread_mutex_lock (&daemon_mutex);
409 if (non_daemon_count)
410 pthread_cond_wait (&daemon_cond, &daemon_mutex);
411 pthread_mutex_unlock (&daemon_mutex);
412}
This page took 0.195709 seconds and 5 git commands to generate.