]>
Commit | Line | Data |
---|---|---|
ee9dd372 TT |
1 | // posix-threads.cc - interface between libjava and POSIX threads. |
2 | ||
3 | /* Copyright (C) 1998, 1999 Cygnus Solutions | |
4 | ||
5 | This file is part of libgcj. | |
6 | ||
7 | This software is copyrighted work licensed under the terms of the | |
8 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for | |
9 | details. */ | |
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 | extern "C" | |
20 | { | |
21 | #include <boehm-config.h> | |
22 | #include <gc.h> | |
23 | }; | |
24 | #endif /* HAVE_BOEHM_GC */ | |
25 | ||
26 | #include <stdlib.h> | |
27 | #include <time.h> | |
28 | #include <signal.h> | |
29 | ||
30 | #include <cni.h> | |
31 | #include <jvm.h> | |
32 | #include <java/lang/Thread.h> | |
33 | #include <java/lang/System.h> | |
34 | ||
35 | // This is used to implement thread startup. | |
36 | struct starter | |
37 | { | |
38 | _Jv_ThreadStartFunc *method; | |
39 | java::lang::Thread *object; | |
40 | _Jv_Thread_t *data; | |
41 | }; | |
42 | ||
43 | // This is the key used to map from the POSIX thread value back to the | |
44 | // Java object representing the thread. The key is global to all | |
45 | // threads, so it is ok to make it a global here. | |
46 | pthread_key_t _Jv_ThreadKey; | |
47 | ||
48 | // We keep a count of all non-daemon threads which are running. When | |
49 | // this reaches zero, _Jv_ThreadWait returns. | |
50 | static pthread_mutex_t daemon_mutex; | |
51 | static pthread_cond_t daemon_cond; | |
52 | static int non_daemon_count; | |
53 | ||
54 | // The signal to use when interrupting a thread. | |
55 | #ifdef LINUX_THREADS | |
56 | // LinuxThreads usurps both SIGUSR1 and SIGUSR2. | |
57 | # define INTR SIGHUP | |
58 | #else /* LINUX_THREADS */ | |
59 | # define INTR SIGUSR2 | |
60 | #endif /* LINUX_THREADS */ | |
61 | ||
62 | // | |
63 | // These are the flags that can appear in _Jv_Thread_t. | |
64 | // | |
65 | ||
66 | // Thread started. | |
67 | #define FLAG_START 0x01 | |
68 | // Thread is daemon. | |
69 | #define FLAG_DAEMON 0x02 | |
70 | ||
71 | \f | |
72 | ||
73 | int | |
74 | _Jv_CondWait (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu, | |
75 | jlong millis, jint nanos) | |
76 | { | |
77 | int r; | |
78 | pthread_mutex_t *pmu; | |
79 | #ifdef HAVE_RECURSIVE_MUTEX | |
80 | pmu = mu; | |
81 | #else | |
82 | pmu = &mu->mutex2; | |
83 | #endif | |
84 | if (millis == 0 && nanos == 0) | |
85 | r = pthread_cond_wait (cv, pmu); | |
86 | else | |
87 | { | |
88 | struct timespec ts; | |
89 | unsigned long m = millis + java::lang::System::currentTimeMillis (); | |
90 | ||
91 | ts.tv_sec = m / 1000; | |
92 | ts.tv_nsec = (m % 1000) * 1000 * 1000 + nanos; | |
93 | ||
94 | r = pthread_cond_timedwait (cv, pmu, &ts); | |
95 | } | |
96 | return r; | |
97 | } | |
98 | ||
99 | #ifndef RECURSIVE_MUTEX_IS_DEFAULT | |
100 | ||
101 | void | |
102 | _Jv_MutexInit (_Jv_Mutex_t *mu) | |
103 | { | |
104 | #ifdef HAVE_RECURSIVE_MUTEX | |
105 | pthread_mutexattr_t *val = NULL; | |
106 | ||
107 | #if defined (HAVE_PTHREAD_MUTEXATTR_SETTYPE) | |
108 | pthread_mutexattr_t attr; | |
109 | ||
110 | // If this is slow, then allocate it statically and only initialize | |
111 | // it once. | |
112 | pthread_mutexattr_init (&attr); | |
113 | pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); | |
114 | val = &attr; | |
115 | #elif defined (HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) | |
116 | pthread_mutexattr_t attr; | |
117 | pthread_mutexattr_init (&attr); | |
118 | pthread_mutexattr_setkind_np (&attr, PTHREAD_MUTEX_RECURSIVE_NP); | |
119 | val = &attr; | |
120 | #endif | |
121 | ||
122 | pthread_mutex_init (mu, val); | |
123 | ||
124 | #if defined (HAVE_PTHREAD_MUTEXATTR_SETTYPE) || defined (HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) | |
125 | pthread_mutexattr_destroy (&attr); | |
126 | #endif | |
127 | ||
128 | #else /* HAVE_RECURSIVE_MUTEX */ | |
129 | ||
130 | // No recursive mutex, so simulate one. | |
131 | pthread_mutex_init (&mu->mutex, NULL); | |
132 | pthread_mutex_init (&mu->mutex2, NULL); | |
133 | pthread_cond_init (&mu->cond, 0); | |
134 | mu->count = 0; | |
135 | ||
136 | #endif /* HAVE_RECURSIVE_MUTEX */ | |
137 | } | |
138 | ||
139 | #endif /* not RECURSIVE_MUTEX_IS_DEFAULT */ | |
140 | ||
141 | #if ! defined (LINUX_THREADS) && ! defined (HAVE_RECURSIVE_MUTEX) | |
142 | ||
143 | void | |
144 | _Jv_MutexDestroy (_Jv_Mutex_t *mu) | |
145 | { | |
146 | pthread_mutex_destroy (&mu->mutex); | |
147 | pthread_mutex_destroy (&mu->mutex2); | |
148 | pthread_cond_destroy (&mu->cond); | |
149 | } | |
150 | ||
151 | int | |
152 | _Jv_MutexLock (_Jv_Mutex_t *mu) | |
153 | { | |
154 | if (pthread_mutex_lock (&mu->mutex)) | |
155 | return -1; | |
156 | while (1) | |
157 | { | |
158 | if (mu->count == 0) | |
159 | { | |
160 | // Grab the lock. | |
161 | mu->thread = pthread_self (); | |
162 | mu->count = 1; | |
163 | pthread_mutex_lock (&mu->mutex2); | |
164 | break; | |
165 | } | |
166 | else if (pthread_self () == mu->thread) | |
167 | { | |
168 | // Already have the lock. | |
169 | mu->count += 1; | |
170 | break; | |
171 | } | |
172 | else | |
173 | { | |
174 | // Try to acquire the lock. | |
175 | pthread_cond_wait (&mu->cond, &mu->mutex); | |
176 | } | |
177 | } | |
178 | pthread_mutex_unlock (&mu->mutex); | |
179 | return 0; | |
180 | } | |
181 | ||
182 | int | |
183 | _Jv_MutexUnlock (_Jv_Mutex_t *mu) | |
184 | { | |
185 | if (pthread_mutex_lock (&mu->mutex)) | |
186 | return -1; | |
187 | int r = 0; | |
188 | if (mu->count == 0 || pthread_self () != mu->thread) | |
189 | r = -1; | |
190 | else | |
191 | { | |
192 | mu->count -= 1; | |
193 | if (! mu->count) | |
194 | { | |
195 | pthread_mutex_unlock (&mu->mutex2); | |
196 | pthread_cond_signal (&mu->cond); | |
197 | } | |
198 | } | |
199 | pthread_mutex_unlock (&mu->mutex); | |
200 | return r; | |
201 | } | |
202 | ||
203 | #endif /* not LINUX_THREADS and not HAVE_RECURSIVE_MUTEX */ | |
204 | ||
205 | static void | |
206 | handle_intr (int) | |
207 | { | |
208 | // Do nothing. | |
209 | } | |
210 | ||
211 | void | |
212 | _Jv_InitThreads (void) | |
213 | { | |
214 | pthread_key_create (&_Jv_ThreadKey, NULL); | |
215 | pthread_mutex_init (&daemon_mutex, NULL); | |
216 | pthread_cond_init (&daemon_cond, 0); | |
217 | non_daemon_count = 0; | |
218 | ||
219 | // Arrange for the interrupt signal to interrupt system calls. | |
220 | struct sigaction act; | |
221 | act.sa_handler = handle_intr; | |
222 | sigemptyset (&act.sa_mask); | |
223 | act.sa_flags = 0; | |
224 | sigaction (INTR, &act, NULL); | |
225 | ||
226 | // Arrange for SIGINT to be blocked to all threads. It is only | |
227 | // deliverable to the master thread. | |
228 | sigset_t mask; | |
229 | sigemptyset (&mask); | |
230 | sigaddset (&mask, SIGINT); | |
231 | pthread_sigmask (SIG_BLOCK, &mask, NULL); | |
232 | } | |
233 | ||
234 | void | |
235 | _Jv_ThreadInitData (_Jv_Thread_t **data, java::lang::Thread *) | |
236 | { | |
237 | _Jv_Thread_t *info = new _Jv_Thread_t; | |
238 | ||
239 | info->flags = 0; | |
240 | info->exception = NULL; | |
241 | ||
242 | // FIXME register a finalizer for INFO here. | |
243 | // FIXME also must mark INFO somehow. | |
244 | ||
245 | *data = info; | |
246 | } | |
247 | ||
248 | void | |
249 | _Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio) | |
250 | { | |
251 | if (data->flags & FLAG_START) | |
252 | { | |
253 | struct sched_param param; | |
254 | ||
255 | param.sched_priority = prio; | |
256 | pthread_setschedparam (data->thread, SCHED_RR, ¶m); | |
257 | } | |
258 | } | |
259 | ||
260 | ||
261 | // This is called as a cleanup handler when a thread is exiting. We | |
262 | // use it to throw the requested exception. It's entirely possible | |
263 | // that this approach is doomed to failure, in which case we'll need | |
264 | // to adopt some alternate. For instance, use a signal to implement | |
265 | // _Jv_ThreadCancel. | |
266 | static void | |
267 | throw_cleanup (void *data) | |
268 | { | |
269 | _Jv_Thread_t *td = (_Jv_Thread_t *) data; | |
270 | _Jv_Throw ((java::lang::Throwable *) td->exception); | |
271 | } | |
272 | ||
273 | void | |
274 | _Jv_ThreadCancel (_Jv_Thread_t *data, void *error) | |
275 | { | |
276 | data->exception = error; | |
277 | pthread_cancel (data->thread); | |
278 | } | |
279 | ||
280 | // This function is called when a thread is started. We don't arrange | |
281 | // to call the `run' method directly, because this function must | |
282 | // return a value. | |
283 | static void * | |
284 | really_start (void *x) | |
285 | { | |
286 | struct starter *info = (struct starter *) x; | |
287 | ||
288 | pthread_cleanup_push (throw_cleanup, info->data); | |
289 | pthread_setspecific (_Jv_ThreadKey, info->object); | |
290 | info->method (info->object); | |
291 | pthread_cleanup_pop (0); | |
292 | ||
293 | if (! (info->data->flags & FLAG_DAEMON)) | |
294 | { | |
295 | pthread_mutex_lock (&daemon_mutex); | |
296 | --non_daemon_count; | |
297 | if (! non_daemon_count) | |
298 | pthread_cond_signal (&daemon_cond); | |
299 | pthread_mutex_unlock (&daemon_mutex); | |
300 | } | |
301 | ||
302 | return NULL; | |
303 | } | |
304 | ||
305 | void | |
306 | _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data, | |
307 | _Jv_ThreadStartFunc *meth) | |
308 | { | |
309 | struct sched_param param; | |
310 | pthread_attr_t attr; | |
311 | struct starter *info; | |
312 | ||
313 | if (data->flags & FLAG_START) | |
314 | return; | |
315 | data->flags |= FLAG_START; | |
316 | ||
317 | param.sched_priority = thread->getPriority(); | |
318 | ||
319 | pthread_attr_init (&attr); | |
320 | pthread_attr_setschedparam (&attr, ¶m); | |
321 | ||
322 | // FIXME: handle marking the info object for GC. | |
323 | info = (struct starter *) _Jv_AllocBytes (sizeof (struct starter)); | |
324 | info->method = meth; | |
325 | info->object = thread; | |
326 | info->data = data; | |
327 | ||
328 | if (! thread->isDaemon()) | |
329 | { | |
330 | pthread_mutex_lock (&daemon_mutex); | |
331 | ++non_daemon_count; | |
332 | pthread_mutex_unlock (&daemon_mutex); | |
333 | } | |
334 | else | |
335 | data->flags |= FLAG_DAEMON; | |
336 | pthread_create (&data->thread, &attr, really_start, (void *) info); | |
337 | ||
338 | pthread_attr_destroy (&attr); | |
339 | } | |
340 | ||
341 | void | |
342 | _Jv_ThreadWait (void) | |
343 | { | |
344 | // Arrange for SIGINT to be delivered to the master thread. | |
345 | sigset_t mask; | |
346 | sigemptyset (&mask); | |
347 | sigaddset (&mask, SIGINT); | |
348 | pthread_sigmask (SIG_UNBLOCK, &mask, NULL); | |
349 | ||
350 | pthread_mutex_lock (&daemon_mutex); | |
351 | if (non_daemon_count) | |
352 | pthread_cond_wait (&daemon_cond, &daemon_mutex); | |
353 | pthread_mutex_unlock (&daemon_mutex); | |
354 | } | |
355 | ||
356 | void | |
357 | _Jv_ThreadInterrupt (_Jv_Thread_t *data) | |
358 | { | |
359 | pthread_kill (data->thread, INTR); | |
360 | } |