Merge from mainline
[official-gcc.git] / libjava / java / lang / natThread.cc
blobda9dcbabfd0755de63af0117ae990c2deefb6055
1 // natThread.cc - Native part of Thread class.
3 /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2006 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
11 #include <config.h>
13 #include <stdlib.h>
15 #include <gcj/cni.h>
16 #include <jvm.h>
17 #include <java-threads.h>
19 #include <gnu/gcj/RawDataManaged.h>
20 #include <java/lang/Thread.h>
21 #include <java/lang/ThreadGroup.h>
22 #include <java/lang/IllegalArgumentException.h>
23 #include <java/lang/UnsupportedOperationException.h>
24 #include <java/lang/IllegalThreadStateException.h>
25 #include <java/lang/InterruptedException.h>
26 #include <java/lang/NullPointerException.h>
28 #include <jni.h>
30 #ifdef ENABLE_JVMPI
31 #include <jvmpi.h>
32 #endif
36 // This structure is used to represent all the data the native side
37 // needs. An object of this type is assigned to the `data' member of
38 // the Thread class.
39 struct natThread
41 // These are used to interrupt sleep and join calls. We can share a
42 // condition variable here since it only ever gets notified when the thread
43 // exits.
44 _Jv_Mutex_t join_mutex;
45 _Jv_ConditionVariable_t join_cond;
47 // This is private data for the thread system layer.
48 _Jv_Thread_t *thread;
50 // Each thread has its own JNI object.
51 JNIEnv *jni_env;
54 static void finalize_native (jobject ptr);
56 // This is called from the constructor to initialize the native side
57 // of the Thread.
58 void
59 java::lang::Thread::initialize_native (void)
61 natThread *nt = (natThread *) _Jv_AllocBytes (sizeof (natThread));
63 data = (gnu::gcj::RawDataManaged *) nt;
65 // Register a finalizer to clean up the native thread resources.
66 _Jv_RegisterFinalizer (data, finalize_native);
68 _Jv_MutexInit (&nt->join_mutex);
69 _Jv_CondInit (&nt->join_cond);
70 nt->thread = _Jv_ThreadInitData (this);
71 // FIXME: if JNI_ENV is set we will want to free it. It is
72 // malloc()d.
73 nt->jni_env = NULL;
76 static void
77 finalize_native (jobject ptr)
79 natThread *nt = (natThread *) ptr;
80 _Jv_ThreadDestroyData (nt->thread);
81 #ifdef _Jv_HaveCondDestroy
82 _Jv_CondDestroy (&nt->join_cond);
83 #endif
84 #ifdef _Jv_HaveMutexDestroy
85 _Jv_MutexDestroy (&nt->join_mutex);
86 #endif
87 _Jv_FreeJNIEnv(nt->jni_env);
90 jint
91 java::lang::Thread::countStackFrames (void)
93 // NOTE: This is deprecated in JDK 1.2.
94 throw new UnsupportedOperationException
95 (JvNewStringLatin1 ("Thread.countStackFrames unimplemented"));
96 return 0;
99 java::lang::Thread *
100 java::lang::Thread::currentThread (void)
102 return _Jv_ThreadCurrent ();
105 jboolean
106 java::lang::Thread::holdsLock (jobject obj)
108 if (!obj)
109 throw new NullPointerException;
110 return !_Jv_ObjectCheckMonitor (obj);
113 void
114 java::lang::Thread::interrupt (void)
116 checkAccess ();
117 natThread *nt = (natThread *) data;
118 JvSynchronize sync (this);
119 if (alive_flag)
120 _Jv_ThreadInterrupt (nt->thread);
123 void
124 java::lang::Thread::join (jlong millis, jint nanos)
126 if (millis < 0 || nanos < 0 || nanos > 999999)
127 throw new IllegalArgumentException;
129 Thread *current = currentThread ();
131 // Here `NT' is the native structure for the thread we are trying to join.
132 natThread *nt = (natThread *) data;
134 // Now wait for: (1) an interrupt, (2) the thread to exit, or (3)
135 // the timeout to occur.
136 _Jv_MutexLock (&nt->join_mutex);
137 if (! isAlive ())
139 _Jv_MutexUnlock (&nt->join_mutex);
140 return;
142 _Jv_CondWait (&nt->join_cond, &nt->join_mutex, millis, nanos);
143 _Jv_MutexUnlock (&nt->join_mutex);
145 if (current->isInterrupted (true))
146 throw new InterruptedException;
149 void
150 java::lang::Thread::resume (void)
152 checkAccess ();
153 throw new UnsupportedOperationException
154 (JvNewStringLatin1 ("Thread.resume unimplemented"));
157 void
158 java::lang::Thread::setPriority (jint newPriority)
160 checkAccess ();
161 if (newPriority < MIN_PRIORITY || newPriority > MAX_PRIORITY)
162 throw new IllegalArgumentException;
164 jint gmax = group->getMaxPriority();
165 if (newPriority > gmax)
166 newPriority = gmax;
168 priority = newPriority;
169 natThread *nt = (natThread *) data;
170 _Jv_ThreadSetPriority (nt->thread, priority);
173 void
174 java::lang::Thread::sleep (jlong millis, jint nanos)
176 if (millis < 0 || nanos < 0 || nanos > 999999)
177 throw new IllegalArgumentException;
179 if (millis == 0 && nanos == 0)
180 ++nanos;
182 Thread *current = currentThread ();
184 // We use a condition variable to implement sleeping so that an
185 // interrupt can wake us up.
186 natThread *nt = (natThread *) current->data;
187 _Jv_MutexLock (&nt->join_mutex);
188 _Jv_CondWait (&nt->join_cond, &nt->join_mutex, millis, nanos);
189 _Jv_MutexUnlock (&nt->join_mutex);
191 if (current->isInterrupted (true))
192 throw new InterruptedException;
195 void
196 java::lang::Thread::finish_ ()
198 natThread *nt = (natThread *) data;
200 group->removeThread (this);
202 #ifdef ENABLE_JVMPI
203 if (_Jv_JVMPI_Notify_THREAD_END)
205 JVMPI_Event event;
207 event.event_type = JVMPI_EVENT_THREAD_END;
208 event.env_id = _Jv_GetCurrentJNIEnv ();
210 _Jv_DisableGC ();
211 (*_Jv_JVMPI_Notify_THREAD_END) (&event);
212 _Jv_EnableGC ();
214 #endif
216 // If a method cache was created, free it.
217 _Jv_FreeMethodCache();
219 // Signal any threads that are waiting to join() us.
220 _Jv_MutexLock (&nt->join_mutex);
223 JvSynchronize sync (this);
224 alive_flag = false;
227 _Jv_CondNotifyAll (&nt->join_cond, &nt->join_mutex);
228 _Jv_MutexUnlock (&nt->join_mutex);
231 // Run once at thread startup, either when thread is attached or when
232 // _Jv_ThreadRun is called.
233 static void
234 _Jv_NotifyThreadStart (java::lang::Thread* thread)
236 #ifdef ENABLE_JVMPI
237 if (_Jv_JVMPI_Notify_THREAD_START)
239 JVMPI_Event event;
241 jstring thread_name = thread->getName ();
242 jstring group_name = NULL, parent_name = NULL;
243 java::lang::ThreadGroup *group = thread->getThreadGroup ();
245 if (group)
247 group_name = group->getName ();
248 group = group->getParent ();
250 if (group)
251 parent_name = group->getName ();
254 int thread_len = thread_name ? JvGetStringUTFLength (thread_name) : 0;
255 int group_len = group_name ? JvGetStringUTFLength (group_name) : 0;
256 int parent_len = parent_name ? JvGetStringUTFLength (parent_name) : 0;
258 char thread_chars[thread_len + 1];
259 char group_chars[group_len + 1];
260 char parent_chars[parent_len + 1];
262 if (thread_name)
263 JvGetStringUTFRegion (thread_name, 0,
264 thread_name->length(), thread_chars);
265 if (group_name)
266 JvGetStringUTFRegion (group_name, 0,
267 group_name->length(), group_chars);
268 if (parent_name)
269 JvGetStringUTFRegion (parent_name, 0,
270 parent_name->length(), parent_chars);
272 thread_chars[thread_len] = '\0';
273 group_chars[group_len] = '\0';
274 parent_chars[parent_len] = '\0';
276 event.event_type = JVMPI_EVENT_THREAD_START;
277 event.env_id = NULL;
278 event.u.thread_start.thread_name = thread_chars;
279 event.u.thread_start.group_name = group_chars;
280 event.u.thread_start.parent_name = parent_chars;
281 event.u.thread_start.thread_id = (jobjectID) thread;
282 event.u.thread_start.thread_env_id = _Jv_GetCurrentJNIEnv ();
284 _Jv_DisableGC ();
285 (*_Jv_JVMPI_Notify_THREAD_START) (&event);
286 _Jv_EnableGC ();
288 #endif
291 void
292 _Jv_ThreadRun (java::lang::Thread* thread)
296 _Jv_NotifyThreadStart (thread);
297 thread->run ();
299 catch (java::lang::Throwable *t)
301 // Uncaught exceptions are forwarded to the ThreadGroup. If
302 // this results in an uncaught exception, that is ignored.
305 thread->group->uncaughtException (thread, t);
307 catch (java::lang::Throwable *f)
309 // Nothing.
313 thread->finish_ ();
316 void
317 java::lang::Thread::start (void)
319 JvSynchronize sync (this);
321 // Its illegal to re-start() a thread, even if its dead.
322 if (!startable_flag)
323 throw new IllegalThreadStateException;
325 alive_flag = true;
326 startable_flag = false;
327 natThread *nt = (natThread *) data;
328 _Jv_ThreadStart (this, nt->thread, (_Jv_ThreadStartFunc *) &_Jv_ThreadRun);
331 void
332 java::lang::Thread::stop (java::lang::Throwable *)
334 checkAccess ();
335 throw new UnsupportedOperationException
336 (JvNewStringLatin1 ("Thread.stop unimplemented"));
339 void
340 java::lang::Thread::suspend (void)
342 checkAccess ();
343 throw new UnsupportedOperationException
344 (JvNewStringLatin1 ("Thread.suspend unimplemented"));
347 static int nextThreadNumber = 0;
349 jstring
350 java::lang::Thread::gen_name (void)
352 jint i;
353 jclass sync = &java::lang::Thread::class$;
355 JvSynchronize dummy(sync);
356 i = ++nextThreadNumber;
359 // Use an array large enough for "-2147483648"; i.e. 11 chars, + "Thread-".
360 jchar buffer[7+11];
361 jchar *bufend = (jchar *) ((char *) buffer + sizeof(buffer));
362 i = _Jv_FormatInt (bufend, i);
363 jchar *ptr = bufend - i;
364 // Prepend "Thread-".
365 *--ptr = '-';
366 *--ptr = 'd';
367 *--ptr = 'a';
368 *--ptr = 'e';
369 *--ptr = 'r';
370 *--ptr = 'h';
371 *--ptr = 'T';
372 return JvNewString (ptr, bufend - ptr);
375 void
376 java::lang::Thread::yield (void)
378 _Jv_ThreadYield ();
381 JNIEnv *
382 _Jv_GetCurrentJNIEnv ()
384 java::lang::Thread *t = _Jv_ThreadCurrent ();
385 if (t == NULL)
386 return NULL;
387 return ((natThread *) t->data)->jni_env;
390 void
391 _Jv_SetCurrentJNIEnv (JNIEnv *env)
393 java::lang::Thread *t = _Jv_ThreadCurrent ();
394 JvAssert (t != NULL);
395 ((natThread *) t->data)->jni_env = env;
398 // Attach the current native thread to an existing (but unstarted) Thread
399 // object. Returns -1 on failure, 0 upon success.
400 jint
401 _Jv_AttachCurrentThread(java::lang::Thread* thread)
403 JvSynchronize sync (thread);
404 if (thread == NULL || thread->startable_flag == false)
405 return -1;
406 thread->startable_flag = false;
407 thread->alive_flag = true;
408 natThread *nt = (natThread *) thread->data;
409 _Jv_ThreadRegister (nt->thread);
410 return 0;
413 java::lang::Thread*
414 _Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group)
416 java::lang::Thread *thread = _Jv_ThreadCurrent ();
417 if (thread != NULL)
418 return thread;
419 if (name == NULL)
420 name = java::lang::Thread::gen_name ();
421 thread = new java::lang::Thread (NULL, group, NULL, name);
422 _Jv_AttachCurrentThread (thread);
423 _Jv_NotifyThreadStart (thread);
424 return thread;
427 java::lang::Thread*
428 _Jv_AttachCurrentThreadAsDaemon(jstring name, java::lang::ThreadGroup* group)
430 java::lang::Thread *thread = _Jv_ThreadCurrent ();
431 if (thread != NULL)
432 return thread;
433 if (name == NULL)
434 name = java::lang::Thread::gen_name ();
435 thread = new java::lang::Thread (NULL, group, NULL, name);
436 thread->setDaemon (true);
437 _Jv_AttachCurrentThread (thread);
438 _Jv_NotifyThreadStart (thread);
439 return thread;
442 jint
443 _Jv_DetachCurrentThread (void)
445 java::lang::Thread *t = _Jv_ThreadCurrent ();
446 if (t == NULL)
447 return -1;
449 _Jv_ThreadUnRegister ();
450 // Release the monitors.
451 t->finish_ ();
453 return 0;