source: trunk/gcc/libjava/posix-threads.cc

Last change on this file was 1392, checked in by bird, 22 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