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