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