Re: JNI Attach/DetachCurrentThread

Marcel Wiesweg <[email protected]> Fri, 6 May 2005 19:18:07 +0200
Newsgroups gmane.comp.java.vm.sablevm.devel
Message-ID <[email protected]>
Am Donnerstag 14 April 2005 23:02 schrieb Marcel Wiesweg:
> Hi,
>
> the attached patch implements the JNI AttachCurrentThread and
> DetachCurrentThread calls.
> I have tested this shortly without any problems so far with an application
> that accesses the VM from multiple threads. The code is combined from
> _svmf_thread_native_start and JNI_CreateJavaVM, I hope I got everything
> right.

I just learned that it is valid to call AttachCurrentThread when the thread is 
already attached. In that case env shall be set to the current env and JNI_OK 
be returned. Attached is an updated patch.

One thing still missing is handling of the JavaVMAttachArgs (thread name and 
thread group). Currently I don't know where to store this information until 
the thread_instance object is created in java_lang_VMThread.c.

Marcel

>
>
> Marcel

_______________________________________________
SableVM-devel mailing list
[email protected]
http://sablevm.org/lists/control/listinfo/sablevm-devel
attachthread.diff (text/x-diff, 4.7 KB)
Index: src/libsablevm/invoke_interface.c
===================================================================
--- src/libsablevm/invoke_interface.c	(revision 3960)
+++ src/libsablevm/invoke_interface.c	(working copy)
@@ -491,10 +491,140 @@
 */
 
 JNIEXPORT static jint JNICALL
-AttachCurrentThread (JavaVM *vm SVM_UNUSED, void **penv SVM_UNUSED,
-		     void *args SVM_UNUSED)
+AttachCurrentThread (JavaVM *_vm, void **penv,
+		     void *args)
 {
-  _svmm_fatal_error ("todo");
+  _svmt_JNIEnv *new_env = NULL;
+  _svmt_JavaVM *vm = (_svmt_JavaVM *) (void *) _vm;
+
+  /* make sure this thread isn't already attached to a vm */
+  _svmt_JNIEnv *current_env = _svmf_get_current_env ();
+  if (current_env != NULL) {
+    if (vm == current_env->vm)
+      {
+         /* if already attached and vm is valid, set penv and return OK */
+         *penv = current_env;
+         return JNI_OK;
+      }
+    else
+      {
+        goto end;
+      }
+  }
+
+  {
+    jint status = JNI_OK;
+
+    _svmm_mutex_lock (vm->global_mutex);
+
+    if (vm->threads.free_list != NULL)
+      {
+	new_env = vm->threads.free_list;
+	assert (new_env->previous == NULL);
+
+	vm->threads.free_list = new_env->next;
+	if (vm->threads.free_list != NULL)
+	  {
+	    vm->threads.free_list->previous = NULL;
+	  }
+
+	new_env->next = vm->threads.user;
+	if (new_env->next != NULL)
+	  {
+	    assert (new_env->next->previous == NULL);
+	    new_env->next->previous = new_env;
+	  }
+
+	new_env->thread_status =
+	  SVM_THREAD_STATUS_NOT_RUNNING_JAVA_RESUMING_ALLOWED;
+      }
+    else if (vm->threads.next_thread_id <= SVM_MAX_THREAD_ID)
+      {
+	if (_svmm_gzalloc_env_no_exception (new_env) != JNI_OK)
+	  {
+	    status=JNI_ERR;
+	    goto unlock;
+	  }
+
+	new_env->interface = &_svmv_native_interface;
+	new_env->vm = vm;
+
+	new_env->next = vm->threads.user;
+	vm->threads.user = new_env;
+	if (new_env->next != NULL)
+	  {
+	    assert (new_env->next->previous == NULL);
+	    new_env->next->previous = new_env;
+	  }
+
+	new_env->thread.interrupted_status = SVM_THREAD_NOT_INTERRUPTED;
+	new_env->thread.sleeping_on_fat_lock = NULL;
+
+	new_env->thread.id = vm->threads.next_thread_id++;
+	_svmf_initialize_thinlock_id (new_env);
+	vm->threads.array[new_env->thread.id] = new_env;
+
+	_svmm_cond_init (new_env->wakeup_cond);
+	_svmm_cond_init (new_env->suspension.cond);
+	_svmm_mutex_init (new_env->contention.owner.mutex);
+	_svmm_cond_init (new_env->contention.requester.cond);
+
+	new_env->thread_status =
+	  SVM_THREAD_STATUS_NOT_RUNNING_JAVA_RESUMING_ALLOWED;
+      }
+    else
+      {
+	status = JNI_ERR;
+      }
+
+  unlock:
+    _svmm_mutex_unlock ();
+
+    if (status != JNI_OK)
+      {
+	goto end;
+      }
+  }
+  
+  new_env->thread.pthread = pthread_self ();
+  _svmf_set_current_env (new_env);
+
+  if (_svmm_gzalloc_native_ref_no_exception (new_env->native_locals.list) !=
+      JNI_OK)
+    {
+      /* we should be cleaning up!  todo ... */
+      goto end;
+    }
+  new_env->throwable = _svmf_cast_jobject_nref (new_env->native_locals.list);
+
+  if (_svmm_gzalloc_native_ref_no_exception
+      (new_env->native_locals.list->next) != JNI_OK)
+    {
+      /* we should be cleaning up!  todo ... */
+      goto end;
+    }
+
+  if (_svmm_gzalloc_native_ref_no_exception
+      (new_env->native_locals.list->next) != JNI_OK)
+    {
+      /* we should be cleaning up!  todo ... */
+      goto end;
+    }
+  new_env->contention.requester.jobject =
+    _svmf_cast_jobject_nref (new_env->native_locals.list->next);
+
+  if (_svmf_stack_init (new_env) != JNI_OK)
+    {
+      /* we should be cleaning up!  todo ... */
+      goto end;
+    }
+
+  new_env->is_alive = JNI_TRUE;
+  
+  *penv = new_env;
+  return JNI_OK;
+
+end:
   return JNI_ERR;
 }
 
@@ -505,9 +635,55 @@
 */
 
 JNIEXPORT static jint JNICALL
-DetachCurrentThread (JavaVM *vm SVM_UNUSED)
+DetachCurrentThread (JavaVM *_vm)
 {
-  _svmm_fatal_error ("todo");
+  _svmt_JNIEnv *env;
+  _svmt_JavaVM *vm = (_svmt_JavaVM *) (void *) _vm;
+  
+  env = _svmf_get_current_env();
+  /* make sure this thread attached to a vm */
+  if ( env == NULL || !env->vm || env->vm != vm )
+    {
+      goto error;
+    }
+    
+  _svmm_mutex_lock (vm->global_mutex);
+
+  _svmf_halt_if_requested (env);
+
+  env->is_alive = JNI_FALSE;
+  _svmf_set_current_env( NULL );
+
+  if (env->previous != NULL)
+    {
+      env->previous->next = env->next;
+    }
+  else
+    {
+      if (env->thread.is_daemon)
+	{
+	  vm->threads.system = env->next;
+	}
+      else
+	{
+	  vm->threads.user = env->next;
+	}
+    }
+
+  if (env->next != NULL)
+    {
+      env->next->previous = env->previous;
+    }
+
+  _svmm_cond_signal (vm->threads.vm_destruction_cond);
+
+  /* leak it for now... */
+
+  _svmm_mutex_unlock ();
+
+  return JNI_OK;
+
+error:
   return JNI_ERR;
 }