source: trunk/third/gcc/libjava/posix-threads.cc @ 16960

Revision 16960, 10.1 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r16959, which included commits to RCS files with non-trunk default branches.
Line 
1// posix-threads.cc - interface between libjava and POSIX threads.
2
3/* Copyright (C) 1998, 1999, 2000  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
19extern "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.
40struct starter
41{
42  _Jv_ThreadStartFunc *method;
43  _Jv_Thread_t *data;
44};
45
46// This is the key used to map from the POSIX thread value back to the
47// Java object representing the thread.  The key is global to all
48// threads, so it is ok to make it a global here.
49pthread_key_t _Jv_ThreadKey;
50
51// This is the key used to map from the POSIX thread value back to the
52// _Jv_Thread_t* representing the thread.
53pthread_key_t _Jv_ThreadDataKey;
54
55// We keep a count of all non-daemon threads which are running.  When
56// this reaches zero, _Jv_ThreadWait returns.
57static pthread_mutex_t daemon_mutex;
58static pthread_cond_t daemon_cond;
59static int non_daemon_count;
60
61// The signal to use when interrupting a thread.
62#ifdef LINUX_THREADS
63  // LinuxThreads (prior to glibc 2.1) usurps 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// Wait for the condition variable "CV" to be notified.
81// Return values:
82// 0: the condition was notified, or the timeout expired.
83// _JV_NOT_OWNER: the thread does not own the mutex "MU".   
84// _JV_INTERRUPTED: the thread was interrupted. Its interrupted flag is set.   
85int
86_Jv_CondWait (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu,
87              jlong millis, jint nanos)
88{
89  pthread_t self = pthread_self();
90  if (mu->owner != self)
91    return _JV_NOT_OWNER;
92
93  struct timespec ts;
94  jlong m, startTime;
95
96  if (millis > 0 || nanos > 0)
97    {
98      startTime = java::lang::System::currentTimeMillis();
99      m = millis + startTime;
100      ts.tv_sec = m / 1000;
101      ts.tv_nsec = ((m % 1000) * 1000000) + nanos;
102    }
103
104  _Jv_Thread_t *current = _Jv_ThreadCurrentData ();
105  java::lang::Thread *current_obj = _Jv_ThreadCurrent ();
106
107  pthread_mutex_lock (&current->wait_mutex);
108
109  // Now that we hold the wait mutex, check if this thread has been
110  // interrupted already.
111  if (current_obj->interrupt_flag)
112    {
113      pthread_mutex_unlock (&current->wait_mutex);
114      return _JV_INTERRUPTED;
115    }
116
117  // Add this thread to the cv's wait set.
118  current->next = NULL;
119
120  if (cv->first == NULL)
121    cv->first = current;
122  else
123    for (_Jv_Thread_t *t = cv->first;; t = t->next)
124      {
125        if (t->next == NULL)
126          {
127            t->next = current;
128            break;
129          }
130      }
131
132  // Record the current lock depth, so it can be restored when we re-aquire it.
133  int count = mu->count;
134
135  // Release the monitor mutex.
136  mu->count = 0;
137  mu->owner = 0;
138  pthread_mutex_unlock (&mu->mutex);
139 
140  int r = 0;
141  bool done_sleeping = false;
142
143  while (! done_sleeping)
144    {
145      if (millis == 0 && nanos == 0)
146        r = pthread_cond_wait (&current->wait_cond, &current->wait_mutex);
147      else
148        r = pthread_cond_timedwait (&current->wait_cond, &current->wait_mutex,
149                                    &ts);
150
151      // In older glibc's (prior to 2.1.3), the cond_wait functions may
152      // spuriously wake up on a signal. Catch that here.
153      if (r != EINTR)
154        done_sleeping = true;
155    }
156 
157  // Check for an interrupt *before* releasing the wait mutex.
158  jboolean interrupted = current_obj->interrupt_flag;
159 
160  pthread_mutex_unlock (&current->wait_mutex);
161
162  //  Reaquire the monitor mutex, and restore the lock count.
163  pthread_mutex_lock (&mu->mutex);
164  mu->owner = self;
165  mu->count = count;
166
167  // If we were interrupted, or if a timeout occured, remove ourself from
168  // the cv wait list now. (If we were notified normally, notify() will have
169  // already taken care of this)
170  if (r == ETIMEDOUT || interrupted)
171    {
172      _Jv_Thread_t *prev = NULL;
173      for (_Jv_Thread_t *t = cv->first; t != NULL; t = t->next)
174        {
175          if (t == current)
176            {
177              if (prev != NULL)
178                prev->next = t->next;
179              else
180                cv->first = t->next;
181              t->next = NULL;
182              break;
183            }
184          prev = t;
185        }
186      if (interrupted)
187        return _JV_INTERRUPTED;
188    }
189 
190  return 0;
191}
192
193int
194_Jv_CondNotify (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu)
195{
196  if (_Jv_PthreadCheckMonitor (mu))
197    return _JV_NOT_OWNER;
198
199  _Jv_Thread_t *target;
200  _Jv_Thread_t *prev = NULL;
201
202  for (target = cv->first; target != NULL; target = target->next)
203    {
204      pthread_mutex_lock (&target->wait_mutex);
205
206      if (target->thread_obj->interrupt_flag)
207        {
208          // Don't notify a thread that has already been interrupted.
209          pthread_mutex_unlock (&target->wait_mutex);
210          prev = target;
211          continue;
212        }
213
214      pthread_cond_signal (&target->wait_cond);
215      pthread_mutex_unlock (&target->wait_mutex);
216
217      // Two concurrent notify() calls must not be delivered to the same
218      // thread, so remove the target thread from the cv wait list now.
219      if (prev == NULL)
220        cv->first = target->next;
221      else
222        prev->next = target->next;
223               
224      target->next = NULL;
225     
226      break;
227    }
228
229  return 0;
230}
231
232int
233_Jv_CondNotifyAll (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu)
234{
235  if (_Jv_PthreadCheckMonitor (mu))
236    return _JV_NOT_OWNER;
237
238  _Jv_Thread_t *target;
239  _Jv_Thread_t *prev = NULL;
240
241  for (target = cv->first; target != NULL; target = target->next)
242    {
243      pthread_mutex_lock (&target->wait_mutex);
244      pthread_cond_signal (&target->wait_cond);
245      pthread_mutex_unlock (&target->wait_mutex);
246
247      if (prev != NULL)
248        prev->next = NULL;
249      prev = target;
250    }
251  if (prev != NULL)
252    prev->next = NULL;
253   
254  cv->first = NULL;
255
256  return 0;
257}
258
259void
260_Jv_ThreadInterrupt (_Jv_Thread_t *data)
261{
262  pthread_mutex_lock (&data->wait_mutex);
263
264  // Set the thread's interrupted flag *after* aquiring its wait_mutex. This
265  // ensures that there are no races with the interrupt flag being set after
266  // the waiting thread checks it and before pthread_cond_wait is entered.
267  data->thread_obj->interrupt_flag = true;
268
269  // Interrupt blocking system calls using a signal.
270//  pthread_kill (data->thread, INTR);
271 
272  pthread_cond_signal (&data->wait_cond);
273 
274  pthread_mutex_unlock (&data->wait_mutex);
275}
276
277static void
278handle_intr (int)
279{
280  // Do nothing.
281}
282
283void
284_Jv_InitThreads (void)
285{
286  pthread_key_create (&_Jv_ThreadKey, NULL);
287  pthread_key_create (&_Jv_ThreadDataKey, NULL);
288  pthread_mutex_init (&daemon_mutex, NULL);
289  pthread_cond_init (&daemon_cond, 0);
290  non_daemon_count = 0;
291
292  // Arrange for the interrupt signal to interrupt system calls.
293  struct sigaction act;
294  act.sa_handler = handle_intr;
295  sigemptyset (&act.sa_mask);
296  act.sa_flags = 0;
297  sigaction (INTR, &act, NULL);
298}
299
300_Jv_Thread_t *
301_Jv_ThreadInitData (java::lang::Thread *obj)
302{
303  _Jv_Thread_t *data = (_Jv_Thread_t *) _Jv_Malloc (sizeof (_Jv_Thread_t));
304  data->flags = 0;
305  data->thread_obj = obj;
306
307  pthread_mutex_init (&data->wait_mutex, NULL);
308  pthread_cond_init (&data->wait_cond, NULL);
309
310  return data;
311}
312
313void
314_Jv_ThreadDestroyData (_Jv_Thread_t *data)
315{
316  pthread_mutex_destroy (&data->wait_mutex);
317  pthread_cond_destroy (&data->wait_cond);
318  _Jv_Free ((void *)data);
319}
320
321void
322_Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio)
323{
324  if (data->flags & FLAG_START)
325    {
326      struct sched_param param;
327
328      param.sched_priority = prio;
329      pthread_setschedparam (data->thread, SCHED_RR, &param);
330    }
331}
332
333// This function is called when a thread is started.  We don't arrange
334// to call the `run' method directly, because this function must
335// return a value.
336static void *
337really_start (void *x)
338{
339  struct starter *info = (struct starter *) x;
340
341  pthread_setspecific (_Jv_ThreadKey, info->data->thread_obj);
342  pthread_setspecific (_Jv_ThreadDataKey, info->data);
343
344  // glibc 2.1.3 doesn't set the value of `thread' until after start_routine
345  // is called. Since it may need to be accessed from the new thread, work
346  // around the potential race here by explicitly setting it again.
347  info->data->thread = pthread_self ();
348
349  info->method (info->data->thread_obj);
350 
351  if (! (info->data->flags & FLAG_DAEMON))
352    {
353      pthread_mutex_lock (&daemon_mutex);
354      --non_daemon_count;
355      if (! non_daemon_count)
356        pthread_cond_signal (&daemon_cond);
357      pthread_mutex_unlock (&daemon_mutex);
358    }
359 
360  return NULL;
361}
362
363void
364_Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data,
365                 _Jv_ThreadStartFunc *meth)
366{
367  struct sched_param param;
368  pthread_attr_t attr;
369  struct starter *info;
370
371  if (data->flags & FLAG_START)
372    return;
373  data->flags |= FLAG_START;
374
375  param.sched_priority = thread->getPriority();
376
377  pthread_attr_init (&attr);
378  pthread_attr_setschedparam (&attr, &param);
379  pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
380
381  // FIXME: handle marking the info object for GC.
382  info = (struct starter *) _Jv_AllocBytes (sizeof (struct starter));
383  info->method = meth;
384  info->data = data;
385
386  if (! thread->isDaemon())
387    {
388      pthread_mutex_lock (&daemon_mutex);
389      ++non_daemon_count;
390      pthread_mutex_unlock (&daemon_mutex);
391    }
392  else
393    data->flags |= FLAG_DAEMON;
394  int r = pthread_create (&data->thread, &attr, really_start, (void *) info);
395 
396  pthread_attr_destroy (&attr);
397
398  if (r)
399    {
400      const char* msg = "Cannot create additional threads";
401      JvThrow (new java::lang::OutOfMemoryError (JvNewStringUTF (msg)));
402    }
403}
404
405void
406_Jv_ThreadWait (void)
407{
408  pthread_mutex_lock (&daemon_mutex);
409  if (non_daemon_count)
410    pthread_cond_wait (&daemon_cond, &daemon_mutex);
411  pthread_mutex_unlock (&daemon_mutex);
412}
Note: See TracBrowser for help on using the repository browser.