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