caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Using camljava library in a multithreaded context
@ 2005-02-23 14:35 EL CHAAR RABIH
       [not found] ` <71A291D8E360AF4EA6FFFAF9CAD136CA03773585@FR-MAILBOX2.fr.sgam.socgen>
  2005-03-07 16:47 ` Using camljava library in a multithreaded context Xavier Leroy
  0 siblings, 2 replies; 3+ messages in thread
From: EL CHAAR RABIH @ 2005-02-23 14:35 UTC (permalink / raw)
  To: 'Xavier.Leroy@inria.fr', 'caml-list@yquem.inria.fr'
  Cc: 'jeanmarc.eber@lexifi.com'

Hello,

I have been using the camljava library for a certain time, in order to
establish communications between java and caml.
The initial use of the library (maintained by Mr Leroy) supposed explicitly
that it is ocaml that initiates the call to java (it is ocaml that creates a
jvm instance).

I was confronted to the situation where java is the instancianting process
that should initialize the ocaml runtime. This was done by a little effort,
by making the following :
*	Java makes call through native methods
*	At each call, the JNIEnv variable used in the c code in jnistubs.c
is set to the actual JNIEnv passed in the native call.
*	The instanciation and deltetion of the jvm (used when ocaml was the
instanciating process) is not realised, since a valid JNIEnv is passed at
each native call.


This solution seems satisfactory, but should be used (due to use of global
variable JNIEnv) in a context where each call to a native method is atomic.
This reflects in the java world that the call to native methods should be
made synchronised.

I am now facing a context where i need to make the library coherent with a
java multi threaded context.
The JNI manual states that each java thread will have it's own JNIEnv inside
the jvm. Therefore, two threads calling the same native method will pass two
different JNIEnv values. 

The camljava API used to achieve communications between java and caml should
be made reentrant. In order to achieve this, i made a deeper change in the
camljava library by making all function calls reentrant, handling the JNIEnv
as a method parameter.
In the caml world, this was made by defining a new type, jniInterface in
jni.mli, and by making all fuctions calling java take this new type as an
additional parameter.

I am aware of the fact that the GC is not thread safe, and therefore the
synchronisation issues are delicate to handle.
The other difficulty is the fact that the caml code executed inside a native
method makes callbacks to java.

The idea that i would like to investigate more thoroughly is the possibility
to transpose the java threads into caml threads. If this is feasible, will
the execution be thread safe inside the GC ??

Another possible problem is the fact that java threads are not always
equivalent to native threads. After doing some exeperimentations, i was
executing a java multithreaded program and java threads didn't always
reflect native threads.
I am appending the trace of the executale after two consecutive runs :


****************************** first run
**********************************************

$ make -C bin runt
make: Entering directory `/cygdrive/d/recherche/java_engine1/bin'
java -Djava.class.path="./;test.jar" TestEngineT 
------------------------Thread number: 0 starts----------------------------
------------------------Thread number: 1 starts----------------------------
------------------------Thread number: 2 starts----------------------------
------------------------Thread number: 3 starts----------------------------
trying thread attach 2
trying thread attach 3
trying thread attach 4
Thread 3 speaks: calling pure caml method 1
Thread 2 speaks: calling pure caml method 1

Thread 1 speaks: calling pure caml method 1
Thread 0 speaks: calling pure caml method 1


****************
Another exception has been detected while we were handling last error.
Dumping information about last error:
ERROR REPORT FILE = (N/A)
PC                = 0x113E657D
SIGNAL            = -1073741819
FUNCTION NAME     = (N/A)
OFFSET            = 0xFFFFFFFF
LIBRARY NAME      = (N/A)
Please check ERROR REPORT FILE for further information, if there is any.
Good bye.
process detach 4
make: *** [runt] Error 1
make: Leaving directory `/cygdrive/d/recherche/java_engine1/bin'




****************************** second run
**********************************************

$ make -C bin runt
make: Entering directory `/cygdrive/d/recherche/java_engine1/bin'
java -Djava.class.path="./;test.jar" TestEngineT 
------------------------Thread number: 0 starts----------------------------
------------------------Thread number: 1 starts----------------------------
------------------------Thread number: 2 starts----------------------------
------------------------Thread number: 3 starts----------------------------
Thread 0 speaks: calling pure caml method 1
Thread 2 speaks: calling pure caml method 1

****************
Another exception has been detected while we were handling last error.
Dumping information about last error:
ERROR REPORT FILE = (N/A)
PC                = 0x77F77552
SIGNAL            = -1073741819
FUNCTION NAME     = (N/A)
OFFSET            = 0xFFFFFFFF
LIBRARY NAME      = (N/A)
Please check ERROR REPORT FILE for further information, if there is any.
Good bye.
process detach 1
make: *** [runt] Error 1
make: Leaving directory `/cygdrive/d/recherche/java_mgt_engine1/bin'

****************************************************************************
***************

Each time that a native thread calls the DLLmain function (under windows)
and goes inside the DLL_THREAD_ATTACH, i increment a global counter, and
print the message printf("trying thread attach %d",counter)
At exit (DLL_PROCESS_DETACH), i print the state of counter printf("process
detach %d",counter)

At the first run, it seems that each java thread is equivalent to a native
thread, and at exit, counter is equal to 4.
On the contrary, in the second run, all java threads seems to execute in the
same native thread.



My questions are the following :
*	Will i be able to prolonge a java thread into a caml thread
*	Will this make the execution GC safe
*	If java threads are not native threads, can there still be a work
around ?


Thanks in advance for your help and your suggestions.

Sincerely

Rabih El Chaar




*************************************************************************
Ce message et toutes les pieces jointes (ci-apres le "message") sont
confidentiels et etablis a l'intention exclusive de ses destinataires.
Toute utilisation ou diffusion non autorisee est interdite. 
Tout message electronique est susceptible d'alteration. 
SG Asset Management et ses filiales declinent toute responsabilite au titre
de ce message s'il a ete altere, deforme ou falsifie.

Découvrez l'offre et les services de SG Asset Management sur le site
www.sgam.fr 

				********

This message and any attachments (the "message") are confidential and
intended solely for the addressees.
Any unauthorised use or dissemination is prohibited. 
E-mails are susceptible to alteration.   
Neither SG Asset Management nor any of its subsidiaries or affiliates shall
be liable for the message if altered, changed or falsified. 

*************************************************************************




^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [Caml-list] Re: C-threads & callbacks vs camljava in a multithrea ded context
       [not found] ` <71A291D8E360AF4EA6FFFAF9CAD136CA03773585@FR-MAILBOX2.fr.sgam.socgen>
@ 2005-03-07 16:22   ` Markus Mottl
  0 siblings, 0 replies; 3+ messages in thread
From: Markus Mottl @ 2005-03-07 16:22 UTC (permalink / raw)
  To: EL CHAAR RABIH; +Cc: OCaml

Hi,

sorry for the delay, but I was extremely busy answering a huge backlog
of mails recently.

On Wed, 23 Feb 2005, EL CHAAR RABIH wrote:
> I sent today a mail concenrning external threads (java threads) and caml.
> When looking inside the caml-list, i came up upon your mail, which attracted
> my attention.
> 
> My goal is to try and switch the jvm thread into a caml thread.
> 
> Is it possible to have your opinion upon my post "Using camljava library in
> a multithreaded context"?
> Is it also possible to have a small example (C and ocaml) realising this
> coordination issue ?

Unfortunately, I have no experience with Java so I cannot tell you
whether there is a way to let Java-threads migrate to OCaml.

My C-solution, which seems to work very well in practice, looks roughly
as follows:

  pthread_mutex_t cb_act_mtx;
  pthread_cond_t cb_act_cnd;
  value *cb_act;

  pthread_mutex_t cb_res_mtx;
  pthread_cond_t cb_res_cnd;

The first mutex and condition variable protect "cb_act", the callback
action to be performed.

If there is a C-thread that wants to call OCaml, it calls the following
function/method (it's actually C++):

  void do_cb(value *action)
  {
    pthread_mutex_lock(&cb_act_mtx);
      cb_act = action;
      pthread_cond_signal(&cb_act_cnd);
    pthread_mutex_unlock(&cb_act_mtx);

    pthread_mutex_lock(&cb_res_mtx);
      while (not cb_res_avail) pthread_cond_wait(&cb_res_cnd, &cb_res_mtx);
    pthread_mutex_unlock(&cb_res_mtx);

    cb_res_avail = false;
  }

Depending on the kind of action that should be performed, an OCaml-thread
that has previously gone into C-land will eventually convert C-data to
OCaml-values before performing the callback.  After returning it will
signal the C-thread that a result is available (or simply that it has
completed the job).  The OCaml-thread has to perform all the conversions,
because the C-thread must not call the GC.  Our C-function, in which
the OCaml-thread waits for callbacks + associated data looks as follows:

  virtual value handle_cbs()
  {
    while (true) {
      caml_enter_blocking_section();
        pthread_mutex_lock(&cb_act_mtx);
          while (cb_act == NULL)
            pthread_cond_wait(&cb_act_cnd, &cb_act_mtx);
        pthread_mutex_unlock(&cb_act_mtx);
      caml_leave_blocking_section();

      if (cb_act == &v_OnRecordUpdateCallback)
        caml_callback(*cb_act,
                      vrc_make(rup, free_record_update, lev1_GC_setting));
      else if (cb_act == &v_Terminate) {}
      else cb_sc = caml_callback(*cb_act, Val_int(cb_sc));

      pthread_mutex_lock(&cb_res_mtx);
        cb_act = NULL;
        cb_res_avail = true;
        pthread_cond_signal(&cb_res_cnd);
      pthread_mutex_unlock(&cb_res_mtx);

      if (cb_act == &v_Terminate) return Val_unit;
    };

    return Val_unit;  // we should never get here
  }

In OCaml you just need to specify the external function that the
OCaml-thread should call:

  external handle_cbs : t -> unit = "activ_handle_cbs_stub"

Then do something like the following at startup:

  let wrap_handle_cbs () =
    try handle_cbs cgc
    with exc ->
      (match exc with
      | Status sc ->
          eprintf "Activ-exception: Status %s\n" (Status_code.to_string sc)
      | FieldStatus fs ->
          eprintf
            "Activ-exception: FieldStatus %s\n" (Field_status.to_string fs)
      | _ ->
          eprintf "Exception escaping callback: %s\n" (Printexc.to_string exc)
      );
      exit 2 in
  ignore (Thread.create wrap_handle_cbs ());

I hope that this info is enough so that you can make OCaml- and C-threads
interact smoothly.

Regards,
Markus

-- 
Markus Mottl    markus.mottl@gmail.com    http://www.ocaml.info


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Using camljava library in a multithreaded context
  2005-02-23 14:35 Using camljava library in a multithreaded context EL CHAAR RABIH
       [not found] ` <71A291D8E360AF4EA6FFFAF9CAD136CA03773585@FR-MAILBOX2.fr.sgam.socgen>
@ 2005-03-07 16:47 ` Xavier Leroy
  1 sibling, 0 replies; 3+ messages in thread
From: Xavier Leroy @ 2005-03-07 16:47 UTC (permalink / raw)
  To: EL CHAAR RABIH
  Cc: 'caml-list@yquem.inria.fr', 'jeanmarc.eber@lexifi.com'

> I have been using the camljava library for a certain time, in order to
> establish communications between java and caml.
> The initial use of the library (maintained by Mr Leroy) supposed explicitly
> that it is ocaml that initiates the call to java (it is ocaml that creates a
> jvm instance).
> 
> I was confronted to the situation where java is the instancianting process
> that should initialize the ocaml runtime. This was done by a little effort,
> by making the following :
> *	Java makes call through native methods
> *	At each call, the JNIEnv variable used in the c code in jnistubs.c
> is set to the actual JNIEnv passed in the native call.
> *	The instanciation and deltetion of the jvm (used when ocaml was the
> instanciating process) is not realised, since a valid JNIEnv is passed at
> each native call.

This looks fine, I would have done it in the same manner.

> This solution seems satisfactory, but should be used (due to use of global
> variable JNIEnv) in a context where each call to a native method is atomic.
> This reflects in the java world that the call to native methods should be
> made synchronised.
> 
> I am now facing a context where i need to make the library coherent with a
> java multi threaded context.
> The JNI manual states that each java thread will have it's own JNIEnv inside
> the jvm. Therefore, two threads calling the same native method will pass two
> different JNIEnv values. 

Yes, but with correct locking, these two calls will execute in
sequence, not in parallel, so it is still OK to store the JNIEnv in
the global variable from jnistubs.c.

The locking can be achieved either at the Java level (by using
synchronized methods on a unique, global object, or equivalently by
using the "synchronized" statement over such an object), or at the C
level using Pthread mutexes or Win32 critical sections.  I'd recommend
doing the locking at the Java level to ensure maximal compatibility
with the Java threading model.

> The camljava API used to achieve communications between java and caml should
> be made reentrant. In order to achieve this, i made a deeper change in the
> camljava library by making all function calls reentrant, handling the JNIEnv
> as a method parameter.

This is not necessary with proper locking as described above.

> The idea that i would like to investigate more thoroughly is the possibility
> to transpose the java threads into caml threads. If this is feasible, will
> the execution be thread safe inside the GC ??

Probably not.  Moreover, as you mention, Java, Caml and the C layer
between the two can have different notions of threads, so a direct
mapping is generally not possible.

> My questions are the following :
> *	Will i be able to prolonge a java thread into a caml thread

No.

> *	Will this make the execution GC safe

I don't think so.

> *	If java threads are not native threads, can there still be a work
> around ?

Locking at the Java level will ensure sequential (not concurrent)
execution of the Caml code and Caml runtime system functions, which is
what you need to enforce.

Hope this helps,

- Xavier Leroy


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2005-03-07 16:47 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-02-23 14:35 Using camljava library in a multithreaded context EL CHAAR RABIH
     [not found] ` <71A291D8E360AF4EA6FFFAF9CAD136CA03773585@FR-MAILBOX2.fr.sgam.socgen>
2005-03-07 16:22   ` [Caml-list] Re: C-threads & callbacks vs camljava in a multithrea ded context Markus Mottl
2005-03-07 16:47 ` Using camljava library in a multithreaded context Xavier Leroy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).