[MLton-devel] calling SML from C; reentrance

Stephen Weeks MLton@mlton.org
Fri, 16 May 2003 13:47:38 -0700


> However, I was also thinking about the fact
> MLton.FFI.handleCallFromC isn't reentrant (and I don't see how to
> make it so from the client side) -- in the sense that the callFromC
> handler can't call a C function that calls back into SML.

Good point.

> Interestingly, though, here is how the code fails:
... 
> Out of memory: 1,073,854,960 bytes live.
> 
> I have no idea why the runtime looking for a gig (and clearly a gig is not
> live, as this machine has 512Meg RAM + 128Meg Swap).

Once you get into segfault land, all bets are off.  I don't see that
error -- I just get a segfault.  Who knows why, or cares (unless you
want to try to figure out the appropriate type system to catch such
bugs).

> In a "single threaded" main program, there will really only ever be
> one stack of execution, just chained together through C functions.

I'm not quite sure what you mean by "one stack of execution".  With
your code, each C call causes a call to install, whic creates a new
SML thread with a new stack.

> Interestingly, this is precisely what happens on the C side, where
> the same stack is used for all the C functions, just peppered with
> returns to MLton_callFromC that side-track the execution into ML
> before returning.

Actually, it would be nice if the SML side only had one stack,
peppered with calls to Thread_returnToC.  But I couldn't figure out an
easy way to make that work.

> In a "multi threaded" main program, this should be more robust,
> since while handling a call from C to SML in one thread, we might
> switch to another ML thread that also calls C that calls SML.

Yes, handling reentrancy and multi-threading is nice.

> It also seems that we could further simplify setCallFromCHandler as
> follows:
...

That makes sense too.

How about the following, based on the idea of creating one thread per
C call, but requiring only one call in total to
Prim.setCallFromCHandler and requiring no thread creation when making
additional calls to setCallFromCHandler.  It seems cleaner to me.

val setCallFromCHandler =
   let
      val r: (unit -> unit) ref =
	 ref (fn () => raise Fail "no handler for C calls")
      val _ =
	 Prim.setCallFromCHandler
	 (toPrimitive
	  (new (let
		   fun loop (): unit =
		      let
			 val t = Prim.saved ()
			 val _ =
			    Prim.switchTo
			    (toPrimitive
			     (new (fn () => (!r ()
					     ; Prim.setSaved t
					     ; Prim.returnToC ()))))
		      in
			 loop ()
		      end
		in
		   loop
		end)))
   in
      fn f => r := f
   end

Hmm.  It occurs to me that with this code may lead to a way execute on
top of the existing SML stack that called the C function.  Maybe we
need to add a primtive for executing a function call on top of a
stack?


-------------------------------------------------------
This SF.net email is sponsored by: If flattening out C++ or Java
code to make your application fit in a relational database is painful, 
don't do it! Check out ObjectStore. Now part of Progress Software.
http://www.objectstore.net/sourceforge
_______________________________________________
MLton-devel mailing list
MLton-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mlton-devel