OSDN Git Service

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