source: trunk/gcc/libjava/java/lang/natThread.cc

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 10.6 KB
Line 
1// natThread.cc - Native part of Thread class.
2
3/* Copyright (C) 1998, 1999, 2000, 2001, 2002 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#include <config.h>
12
13#include <stdlib.h>
14
15#include <gcj/cni.h>
16#include <jvm.h>
17#include <java-threads.h>
18
19#include <java/lang/Thread.h>
20#include <java/lang/ThreadGroup.h>
21#include <java/lang/IllegalArgumentException.h>
22#include <java/lang/UnsupportedOperationException.h>
23#include <java/lang/IllegalThreadStateException.h>
24#include <java/lang/InterruptedException.h>
25#include <java/lang/NullPointerException.h>
26
27#include <jni.h>
28
29#ifdef ENABLE_JVMPI
30#include <jvmpi.h>
31#endif
32
33
34
35
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.
39struct natThread
40{
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;
46
47 // This is private data for the thread system layer.
48 _Jv_Thread_t *thread;
49
50 // Each thread has its own JNI object.
51 JNIEnv *jni_env;
52};
53
54static void finalize_native (jobject ptr);
55
56// This is called from the constructor to initialize the native side
57// of the Thread.
58void
59java::lang::Thread::initialize_native (void)
60{
61 natThread *nt = (natThread *) _Jv_AllocBytes (sizeof (natThread));
62
63 // The native thread data is kept in a Object field, not a RawData, so that
64 // the GC allocator can be used and a finalizer run after the thread becomes
65 // unreachable. Note that this relies on the GC's ability to finalize
66 // non-Java objects. FIXME?
67 data = reinterpret_cast<jobject> (nt);
68
69 // Register a finalizer to clean up the native thread resources.
70 _Jv_RegisterFinalizer (data, finalize_native);
71
72 _Jv_MutexInit (&nt->join_mutex);
73 _Jv_CondInit (&nt->join_cond);
74 nt->thread = _Jv_ThreadInitData (this);
75 // FIXME: if JNI_ENV is set we will want to free it. It is
76 // malloc()d.
77 nt->jni_env = NULL;
78}
79
80static void
81finalize_native (jobject ptr)
82{
83 natThread *nt = (natThread *) ptr;
84 _Jv_ThreadDestroyData (nt->thread);
85}
86
87jint
88java::lang::Thread::countStackFrames (void)
89{
90 // NOTE: This is deprecated in JDK 1.2.
91 throw new UnsupportedOperationException
92 (JvNewStringLatin1 ("Thread.countStackFrames unimplemented"));
93 return 0;
94}
95
96java::lang::Thread *
97java::lang::Thread::currentThread (void)
98{
99 return _Jv_ThreadCurrent ();
100}
101
102void
103java::lang::Thread::destroy (void)
104{
105 // NOTE: This is marked as unimplemented in the JDK 1.2
106 // documentation.
107 throw new UnsupportedOperationException
108 (JvNewStringLatin1 ("Thread.destroy unimplemented"));
109}
110
111void
112java::lang::Thread::interrupt (void)
113{
114 natThread *nt = (natThread *) data;
115 _Jv_ThreadInterrupt (nt->thread);
116}
117
118void
119java::lang::Thread::join (jlong millis, jint nanos)
120{
121 if (millis < 0 || nanos < 0 || nanos > 999999)
122 throw new IllegalArgumentException;
123
124 Thread *current = currentThread ();
125
126 // Here `NT' is the native structure for the thread we are trying to join.
127 natThread *nt = (natThread *) data;
128
129 // Now wait for: (1) an interrupt, (2) the thread to exit, or (3)
130 // the timeout to occur.
131 _Jv_MutexLock (&nt->join_mutex);
132 if (! isAlive ())
133 {
134 _Jv_MutexUnlock (&nt->join_mutex);
135 return;
136 }
137 _Jv_CondWait (&nt->join_cond, &nt->join_mutex, millis, nanos);
138 _Jv_MutexUnlock (&nt->join_mutex);
139
140 if (current->isInterrupted (true))
141 throw new InterruptedException;
142}
143
144void
145java::lang::Thread::resume (void)
146{
147 checkAccess ();
148 throw new UnsupportedOperationException
149 (JvNewStringLatin1 ("Thread.resume unimplemented"));
150}
151
152void
153java::lang::Thread::setPriority (jint newPriority)
154{
155 checkAccess ();
156 if (newPriority < MIN_PRIORITY || newPriority > MAX_PRIORITY)
157 throw new IllegalArgumentException;
158
159 jint gmax = group->getMaxPriority();
160 if (newPriority > gmax)
161 newPriority = gmax;
162
163 priority = newPriority;
164 natThread *nt = (natThread *) data;
165 _Jv_ThreadSetPriority (nt->thread, priority);
166}
167
168void
169java::lang::Thread::sleep (jlong millis, jint nanos)
170{
171 if (millis < 0 || nanos < 0 || nanos > 999999)
172 throw new IllegalArgumentException;
173
174 if (millis == 0 && nanos == 0)
175 ++nanos;
176
177 Thread *current = currentThread ();
178
179 // We use a condition variable to implement sleeping so that an
180 // interrupt can wake us up.
181 natThread *nt = (natThread *) current->data;
182 _Jv_MutexLock (&nt->join_mutex);
183 _Jv_CondWait (&nt->join_cond, &nt->join_mutex, millis, nanos);
184 _Jv_MutexUnlock (&nt->join_mutex);
185
186 if (current->isInterrupted (true))
187 throw new InterruptedException;
188}
189
190void
191java::lang::Thread::finish_ ()
192{
193 natThread *nt = (natThread *) data;
194
195 group->removeThread (this);
196
197#ifdef ENABLE_JVMPI
198 if (_Jv_JVMPI_Notify_THREAD_END)
199 {
200 JVMPI_Event event;
201
202 event.event_type = JVMPI_EVENT_THREAD_END;
203 event.env_id = _Jv_GetCurrentJNIEnv ();
204
205 _Jv_DisableGC ();
206 (*_Jv_JVMPI_Notify_THREAD_END) (&event);
207 _Jv_EnableGC ();
208 }
209#endif
210
211 group = NULL;
212
213 // Signal any threads that are waiting to join() us.
214 _Jv_MutexLock (&nt->join_mutex);
215 alive_flag = false;
216 _Jv_CondNotifyAll (&nt->join_cond, &nt->join_mutex);
217 _Jv_MutexUnlock (&nt->join_mutex);
218}
219
220// Run once at thread startup, either when thread is attached or when
221// _Jv_ThreadRun is called.
222static void
223_Jv_NotifyThreadStart (java::lang::Thread* thread)
224{
225#ifdef ENABLE_JVMPI
226 if (_Jv_JVMPI_Notify_THREAD_START)
227 {
228 JVMPI_Event event;
229
230 jstring thread_name = thread->getName ();
231 jstring group_name = NULL, parent_name = NULL;
232 java::lang::ThreadGroup *group = thread->getThreadGroup ();
233
234 if (group)
235 {
236 group_name = group->getName ();
237 group = group->getParent ();
238
239 if (group)
240 parent_name = group->getName ();
241 }
242
243 int thread_len = thread_name ? JvGetStringUTFLength (thread_name) : 0;
244 int group_len = group_name ? JvGetStringUTFLength (group_name) : 0;
245 int parent_len = parent_name ? JvGetStringUTFLength (parent_name) : 0;
246
247 char thread_chars[thread_len + 1];
248 char group_chars[group_len + 1];
249 char parent_chars[parent_len + 1];
250
251 if (thread_name)
252 JvGetStringUTFRegion (thread_name, 0,
253 thread_name->length(), thread_chars);
254 if (group_name)
255 JvGetStringUTFRegion (group_name, 0,
256 group_name->length(), group_chars);
257 if (parent_name)
258 JvGetStringUTFRegion (parent_name, 0,
259 parent_name->length(), parent_chars);
260
261 thread_chars[thread_len] = '\0';
262 group_chars[group_len] = '\0';
263 parent_chars[parent_len] = '\0';
264
265 event.event_type = JVMPI_EVENT_THREAD_START;
266 event.env_id = NULL;
267 event.u.thread_start.thread_name = thread_chars;
268 event.u.thread_start.group_name = group_chars;
269 event.u.thread_start.parent_name = parent_chars;
270 event.u.thread_start.thread_id = (jobjectID) thread;
271 event.u.thread_start.thread_env_id = _Jv_GetCurrentJNIEnv ();
272
273 _Jv_DisableGC ();
274 (*_Jv_JVMPI_Notify_THREAD_START) (&event);
275 _Jv_EnableGC ();
276 }
277#endif
278}
279
280void
281_Jv_ThreadRun (java::lang::Thread* thread)
282{
283 try
284 {
285 _Jv_NotifyThreadStart (thread);
286 thread->run ();
287 }
288 catch (java::lang::Throwable *t)
289 {
290 // Uncaught exceptions are forwarded to the ThreadGroup. If
291 // this results in an uncaught exception, that is ignored.
292 try
293 {
294 thread->group->uncaughtException (thread, t);
295 }
296 catch (java::lang::Throwable *f)
297 {
298 // Nothing.
299 }
300 }
301
302 thread->finish_ ();
303}
304
305void
306java::lang::Thread::start (void)
307{
308 JvSynchronize sync (this);
309
310 // Its illegal to re-start() a thread, even if its dead.
311 if (!startable_flag)
312 throw new IllegalThreadStateException;
313
314 alive_flag = true;
315 startable_flag = false;
316 natThread *nt = (natThread *) data;
317 _Jv_ThreadStart (this, nt->thread, (_Jv_ThreadStartFunc *) &_Jv_ThreadRun);
318}
319
320void
321java::lang::Thread::stop (java::lang::Throwable *)
322{
323 throw new UnsupportedOperationException
324 (JvNewStringLatin1 ("Thread.stop unimplemented"));
325}
326
327void
328java::lang::Thread::suspend (void)
329{
330 checkAccess ();
331 throw new UnsupportedOperationException
332 (JvNewStringLatin1 ("Thread.suspend unimplemented"));
333}
334
335static int nextThreadNumber = 0;
336
337jstring
338java::lang::Thread::gen_name (void)
339{
340 jint i;
341 jclass sync = &java::lang::Thread::class$;
342 {
343 JvSynchronize dummy(sync);
344 i = ++nextThreadNumber;
345 }
346
347 // Use an array large enough for "-2147483648"; i.e. 11 chars, + "Thread-".
348 jchar buffer[7+11];
349 jchar *bufend = (jchar *) ((char *) buffer + sizeof(buffer));
350 i = _Jv_FormatInt (bufend, i);
351 jchar *ptr = bufend - i;
352 // Prepend "Thread-".
353 *--ptr = '-';
354 *--ptr = 'd';
355 *--ptr = 'a';
356 *--ptr = 'e';
357 *--ptr = 'r';
358 *--ptr = 'h';
359 *--ptr = 'T';
360 return JvNewString (ptr, bufend - ptr);
361}
362
363void
364java::lang::Thread::yield (void)
365{
366 _Jv_ThreadYield ();
367}
368
369JNIEnv *
370_Jv_GetCurrentJNIEnv ()
371{
372 java::lang::Thread *t = _Jv_ThreadCurrent ();
373 if (t == NULL)
374 return NULL;
375 return ((natThread *) t->data)->jni_env;
376}
377
378void
379_Jv_SetCurrentJNIEnv (JNIEnv *env)
380{
381 java::lang::Thread *t = _Jv_ThreadCurrent ();
382 JvAssert (t != NULL);
383 ((natThread *) t->data)->jni_env = env;
384}
385
386// Attach the current native thread to an existing (but unstarted) Thread
387// object. Returns -1 on failure, 0 upon success.
388jint
389_Jv_AttachCurrentThread(java::lang::Thread* thread)
390{
391 if (thread == NULL || thread->startable_flag == false)
392 return -1;
393 thread->startable_flag = false;
394 thread->alive_flag = true;
395 natThread *nt = (natThread *) thread->data;
396 _Jv_ThreadRegister (nt->thread);
397 return 0;
398}
399
400java::lang::Thread*
401_Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group)
402{
403 java::lang::Thread *thread = _Jv_ThreadCurrent ();
404 if (thread != NULL)
405 return thread;
406 if (name == NULL)
407 name = java::lang::Thread::gen_name ();
408 thread = new java::lang::Thread (NULL, group, NULL, name);
409 _Jv_AttachCurrentThread (thread);
410 _Jv_NotifyThreadStart (thread);
411 return thread;
412}
413
414java::lang::Thread*
415_Jv_AttachCurrentThreadAsDaemon(jstring name, java::lang::ThreadGroup* group)
416{
417 java::lang::Thread *thread = _Jv_ThreadCurrent ();
418 if (thread != NULL)
419 return thread;
420 if (name == NULL)
421 name = java::lang::Thread::gen_name ();
422 thread = new java::lang::Thread (NULL, group, NULL, name);
423 thread->setDaemon (true);
424 _Jv_AttachCurrentThread (thread);
425 _Jv_NotifyThreadStart (thread);
426 return thread;
427}
428
429jint
430_Jv_DetachCurrentThread (void)
431{
432 java::lang::Thread *t = _Jv_ThreadCurrent ();
433 if (t == NULL)
434 return -1;
435
436 _Jv_ThreadUnRegister ();
437 // Release the monitors.
438 t->finish_ ();
439
440 return 0;
441}
Note: See TracBrowser for help on using the repository browser.