caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* crash under macos x but not win32
@ 2007-04-10  0:19 Jeffrey Loren Shaw
  2007-04-10  1:07 ` [Caml-list] " Jacques Garrigue
  0 siblings, 1 reply; 7+ messages in thread
From: Jeffrey Loren Shaw @ 2007-04-10  0:19 UTC (permalink / raw)
  To: caml-list

The following works as intended in Win32 (the ui counts slowly from 0 to 5), 
but crashes in Mac OS X with "Bus Error". I'm running ocaml 3.09.3 installed 
with macports. For windows I used the Ocaml 3.09.3 MinGW binary 
distribution. 

(* looptest.ml *) 

open Tk 

let testone () =
 let top = openTk () in
 let l = Label.create top in
 let loopfun () =
   ignore
     (
	Thread.create
	  (fun () ->
	    for i=0 to 5 do
	      Thread.delay 1.;
	      Label.configure ~text:(string_of_int i) l
	    done
	  )
	  ()
     )
 in
 let b = Button.create ~text:"Run the test" ~command:loopfun top in
 pack  [l];
 pack [b];
 mainLoop ();; 

testone () 

(* end looptest.ml *) 

runs with: ocaml -I +labltk -I +threads unix.cma threads.cma labltk.cma 
looptest.ml 

Any ideas? Perhaps the following information will help, I don't know. 

Thread 3 Crashed:
0   com.tcltk.tklibrary  	0x9acead88 Tk_FreeGC + 30
1   com.tcltk.tklibrary  	0x9acbe64d TkButtonWorldChanged + 117
2   com.tcltk.tklibrary  	0x9acbed53 ConfigureButton + 1400
3   com.tcltk.tklibrary  	0x9acbf68f ButtonWidgetObjCmd + 416
4   com.tcltk.tcllibrary 	0x9ac2b2c3 TclInvokeObjectCommand + 264
5   dlllabltk.so         	0x000e294b camltk_tcl_direct_eval + 623
6   ocamlrun             	0x00012ba3 caml_interprete + 6262
7   ocamlrun             	0x0000e0ba caml_callbackN_exn + 185
8   ocamlrun             	0x0000e103 caml_callback_exn + 38
9   dllthreads.so        	0x000d73e8 caml_thread_start + 80
10  libSystem.B.dylib    	0x90024147 _pthread_body + 84 

Thread 3 crashed with X86 Thread State (32-bit):
 eax: 0x00000000  ebx: 0x9acead78  ecx: 0x0c5a9048  edx: 0x00000015
 edi: 0x01668608  esi: 0x00000000  ebp: 0xb0203838  esp: 0xb0203810
  ss: 0x0000001f  efl: 0x00010286  eip: 0x9acead88   cs: 0x00000017
  ds: 0x0000001f   es: 0x0000001f   fs: 0x00000000   gs: 0x00000037


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

* Re: [Caml-list] crash under macos x but not win32
  2007-04-10  0:19 crash under macos x but not win32 Jeffrey Loren Shaw
@ 2007-04-10  1:07 ` Jacques Garrigue
  2007-04-10  2:08   ` skaller
  2007-04-10  3:56   ` Jeffrey Loren Shaw
  0 siblings, 2 replies; 7+ messages in thread
From: Jacques Garrigue @ 2007-04-10  1:07 UTC (permalink / raw)
  To: shawjef3; +Cc: caml-list

From: "Jeffrey Loren Shaw" <shawjef3@msu.edu>
> The following works as intended in Win32 (the ui counts slowly from 0 to 5), 
> but crashes in Mac OS X with "Bus Error". I'm running ocaml 3.09.3 installed 
> with macports. For windows I used the Ocaml 3.09.3 MinGW binary 
> distribution. 
> 
> (* looptest.ml *) 
> 
> open Tk 
> 
> let testone () =
>  let top = openTk () in
>  let l = Label.create top in
>  let loopfun () =
>    ignore
>      (
> 	Thread.create
> 	  (fun () ->
> 	    for i=0 to 5 do
> 	      Thread.delay 1.;
> 	      Label.configure ~text:(string_of_int i) l
> 	    done
> 	  )
> 	  ()
>      )
>  in
>  let b = Button.create ~text:"Run the test" ~command:loopfun top in
>  pack  [l];
>  pack [b];
>  mainLoop ();; 
> 
> testone () 
> 
> (* end looptest.ml *) 
> 
> runs with: ocaml -I +labltk -I +threads unix.cma threads.cma labltk.cma 
> looptest.ml 

The Aqua version of Tk is notoriously unstable when used with labltk,
but this doesn't seem to be the problem here. Rather, it appears not
to be reentrant (or rather not callable from several threads.) By the
way I am surprised you have no problem under Win32, which often has
reentrance problems too.

Anyway, there is a Tkthread module to solve these reentrance problems.
Here is the code using it, adding "sync" and "async" where needed.

open Tk 
open Tkthread

let tk = start () (* Calls openTk and mainLoop in a new thread *)

let testone () =
 Thread.delay 0.1; (* wait for initialization *)
 let l = sync Label.create top in
 let loopfun () =
   ignore
     (
	Thread.create
	  (fun () ->
	    for i=0 to 5 do
	      Thread.delay 1.;
	      async (Label.configure ~text:(string_of_int i)) l
	    done
	  )
	  ()
     )
 in
 let b = sync (Button.create ~text:"Run the test" ~command:loopfun) top in
 async pack  [l];
 async pack [b];
 Thread.join tk;; (* wait for mainLoop to finish *)

testone ()

And start it with

ocaml -I +labltk -I +threads unix.cma threads.cma labltk.cma tkthread.cmo looptest2.ml

The wait for initialization part is kind of hacky, as the thread start
function was rather intended for interactive use, but it should be
portable enough.

Jacques Garrigue


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

* Re: [Caml-list] crash under macos x but not win32
  2007-04-10  1:07 ` [Caml-list] " Jacques Garrigue
@ 2007-04-10  2:08   ` skaller
  2007-04-10  2:41     ` Jacques Garrigue
  2007-04-10  3:56   ` Jeffrey Loren Shaw
  1 sibling, 1 reply; 7+ messages in thread
From: skaller @ 2007-04-10  2:08 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: shawjef3, caml-list

On Tue, 2007-04-10 at 10:07 +0900, Jacques Garrigue wrote:
> From: "Jeffrey Loren Shaw" <shawjef3@msu.edu>

>  Rather, it appears not
> to be reentrant (or rather not callable from several threads.) By the
> way I am surprised you have no problem under Win32, which often has
> reentrance problems too.

Tcl is re-entant since version 8. Tk is not and never will be.

-- 
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net


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

* Re: [Caml-list] crash under macos x but not win32
  2007-04-10  2:08   ` skaller
@ 2007-04-10  2:41     ` Jacques Garrigue
  0 siblings, 0 replies; 7+ messages in thread
From: Jacques Garrigue @ 2007-04-10  2:41 UTC (permalink / raw)
  To: skaller; +Cc: shawjef3, caml-list

From: skaller <skaller@users.sourceforge.net>
> On Tue, 2007-04-10 at 10:07 +0900, Jacques Garrigue wrote:
> > From: "Jeffrey Loren Shaw" <shawjef3@msu.edu>
> 
> >  Rather, it appears not
> > to be reentrant (or rather not callable from several threads.) By the
> > way I am surprised you have no problem under Win32, which often has
> > reentrance problems too.
> 
> Tcl is re-entant since version 8. Tk is not and never will be.

Actually this is not the problem here, as ocaml does not need full
reentrance (ability to call the library after preemption), but just a
weaker form (ability to call the library from any thread, after
control was given back to the ocaml process). This is because only one
ocaml thread runs at any time, and only when the control is on the
caml side. So I believe the problem is at a lower level, either in the
system's graphics libraries (I'm no OSX specialist), or in the
specifics of the Tk/Aqua implementation. For instance, on windows, GDI
functions must always be called from the same thread or you get an
error.

Jacques Garrigue


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

* Re: [Caml-list] crash under macos x but not win32
  2007-04-10  1:07 ` [Caml-list] " Jacques Garrigue
  2007-04-10  2:08   ` skaller
@ 2007-04-10  3:56   ` Jeffrey Loren Shaw
  2007-04-10  4:15     ` Jacques Garrigue
  1 sibling, 1 reply; 7+ messages in thread
From: Jeffrey Loren Shaw @ 2007-04-10  3:56 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: caml-list

Jacques Garrigue,
Thanks for your reply! Inspired by your use of Timer.set in Tkthreads, I 
decided to use a library I keep handy for queued communication between 
threads. Using it frees me of having to type sync, async, etc a lot. The 
only major improvement now would be to make it so that you don't have to 
poll the queue. I don't know how to do that right now. 

type 'a qm =
   {q : 'a Queue.t;
    m : Mutex.t;
    c : Condition.t;
  } 

let createqm () =
 {q = Queue.create ();
  m = Mutex.create ();
  c = Condition.create ();
} 

let addtoq qm a =
 Mutex.lock qm.m;
 Queue.push a qm.q;
 Condition.signal qm.c;
 Mutex.unlock qm.m 

let getfromq_noblock qm =
 if Mutex.try_lock qm.m then
   if Queue.is_empty qm.q then
     (
	Mutex.unlock qm.m;
	None
     )
   else
     let r = Some (Queue.pop qm.q) in
     Mutex.unlock qm.m;
     r
 else
   None 

let testthree () =
 let top = openTk () in
 let l = Label.create top in
 let lconfig s () = Label.configure ~text:s l in
 let qm = createqm () in
 let loopfun () =
   ignore
     (
	Thread.create
	  (fun () ->
	    for i=0 to 5 do
	      Thread.delay 1.;
	      addtoq qm (lconfig (string_of_int i))
	    done
	  )
	  ()
     )
 in
 let b = Button.create ~text:"Run the test" ~command:loopfun top in
 let rec watcher () =
   Timer.set
     ~ms:10
     ~callback:
     (fun () ->
	match getfromq_noblock qm with
	  None -> watcher ()
	| Some f -> f (); watcher ()
     )
 in
 watcher ();
 pack [l];
 pack [b];
 mainLoop ();
 exit 0;; 

testthree ()


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

* Re: [Caml-list] crash under macos x but not win32
  2007-04-10  3:56   ` Jeffrey Loren Shaw
@ 2007-04-10  4:15     ` Jacques Garrigue
  2007-04-10  5:52       ` skaller
  0 siblings, 1 reply; 7+ messages in thread
From: Jacques Garrigue @ 2007-04-10  4:15 UTC (permalink / raw)
  To: shawjef3; +Cc: caml-list

From: "Jeffrey Loren Shaw" <shawjef3@msu.edu>
> Thanks for your reply! Inspired by your use of Timer.set in Tkthreads, I 
> decided to use a library I keep handy for queued communication between 
> threads. Using it frees me of having to type sync, async, etc a lot. The 
> only major improvement now would be to make it so that you don't have to 
> poll the queue. I don't know how to do that right now. 

There may be a misunderstanding due to my translation.
You don't have to write a sync or async for each and every Tk function
call. In your example below, you could write

open Tkthread
let tk = start ()

let testthree () =
 let top = openTk () in
 let l = Label.create top in
 let lconfig s () = 
 let qm = createqm () in
 let loopfun () =
   ignore
     (
	Thread.create
	  (fun () ->
	    for i=0 to 5 do
	      Thread.delay 1.;
              async (Label.configure ~text:(string_of_int i)) l
	    done
	  )
	  ()
     )
 in
 let b = Button.create ~text:"Run the test" ~command:loopfun top in
 pack [l];
 pack [b]

let () =
  async testthree ();
  Thread.join tk;
  exit 0

By the way, the polling is needed in order to have threads running
while using the Tk main loop. One could also do the opposite, polling
for Tk events while running an ocaml main loop...

Jacques Garrigue


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

* Re: [Caml-list] crash under macos x but not win32
  2007-04-10  4:15     ` Jacques Garrigue
@ 2007-04-10  5:52       ` skaller
  0 siblings, 0 replies; 7+ messages in thread
From: skaller @ 2007-04-10  5:52 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: shawjef3, caml-list

On Tue, 2007-04-10 at 13:15 +0900, Jacques Garrigue wrote:

> By the way, the polling is needed in order to have threads running
> while using the Tk main loop. One could also do the opposite, polling
> for Tk events while running an ocaml main loop...

This the classic control inversion problem, when two top level
architectures both demand to run the event loop. From memory,
Tcl is very good in this area, since it is actually designed to 
support event loop merging, which of course was dictated by the
need to handle GUIs as an extension.

More recent offerings such as Gtk seem to have taken a massive
backwards step.

-- 
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net


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

end of thread, other threads:[~2007-04-10  5:52 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-04-10  0:19 crash under macos x but not win32 Jeffrey Loren Shaw
2007-04-10  1:07 ` [Caml-list] " Jacques Garrigue
2007-04-10  2:08   ` skaller
2007-04-10  2:41     ` Jacques Garrigue
2007-04-10  3:56   ` Jeffrey Loren Shaw
2007-04-10  4:15     ` Jacques Garrigue
2007-04-10  5:52       ` skaller

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).