Re: Calling Haskell from...

1999-02-25 Thread Michael Hobbs

Alex Ferguson wrote:
> 
> What's the state of the art as regards calling Haskell functions from
> 'the outside world'?  I note that Haskell Direct has this in its
> manifesto, but says "currently unsupported".  Does that mean a moderate
> size black hole at the centre of something still potentially usable,
> or nothing much at all?
> 
> Sorry if this is an 'RTFM' matter, just not sure at present precisely
> which 'FM'.

Check out the paper about a Foreign Function Interface on the HDirect
web page. It shows how to invoke Haskell from the outside world. This
method seems to work fairly well with GHC 4.02. However, I've never
tried to use Haskell functions in a C program. I've only used C
functions in a Haskell program, where the C function sometimes invokes
callback functions which are defined in Haskell.

Anyway, that's the FM.



Re: Threads in GHC's RTS

1999-04-14 Thread Michael Hobbs

We'll see if I can finally get this message to post to the list...

"Manuel M. T. Chakravarty" wrote:
> Therefore, I propose to have three kinds of FFI calls:
> 
>   unsafe- as before
>   safe  - as currently implemented
>   supersafe - (or call it "threadsafe" or "blocksafe")
>   the solution you described above
> 
> I think, the trouble of having to deal with three kinds of
> calls is worthwhile as
> 
> (a) "unsafe" and "safe" can be part of a standard FFI;
> "supersafe" is only added by implementations that also
> support multi-threading;
> (b) bindings to non-thread-safe libraries can use "unsafe"
> and "safe"; in a multi-threaded RTS, they are, so to
> speak, included into the lock that protects the Haskell
> heap etc; and
> (c) if a programmer knows that a call cannot block, but may
> re-enter the Haskell scheduler, "safe" provides a faster
> way of doing the call.

I don't think that these three FFI types are enough to cover *all* of
the bases regarding callbacks, blocking, and thread-safety. 

As a diabolical example, say that I really wanted a multithreaded GTK+
application. Say, for example, a ray-trace program where the tracing
engine is running on a separate thread than the GUI. The GUI updates the
display every few seconds and can stop, start, pause the engine
concurrently. Every GTK+ program calls gtk_main(), which won't return
until the program ends. It's conceptually vague whether or not to
classify gtk_main() as blocking or not, since it does invoke callbacks.
But at any rate, I want to keep the GTK+ FFI calls within a single OS
thread, because GTK+ is not terribly thread-safe, but I also want the
ray-tracing engine to run concurrently on a separate Haskell thread.
Which of the three types above would you use when defining gtk_main()?

Perhaps callback, blocking, and thread-safety should each be separate
boolean attributes. However, I'm not really sure what "thread-safe"
function means, within the Haskell FFI. It could be that no two
thread-safe functions can be executing at the same time. Or, it could
mean that any callbacks that a "thread-safe" function makes are run on
the same OS thread as that function. Perhaps thread-safety can be
further broken down into two different types?

I'm getting the feeling that we may be opening Pandora's Box here.
Surely, there must be a more elegant solution that resolves all of these
problems. If I come up with it, I'll let you know. :)

- Michael Hobbs



Re: greencard example does not compile

1999-04-16 Thread Michael Hobbs

[EMAIL PROTECTED] wrote:
> > data Polar = P Int Int deriving Show
> >
> > polarToCart :: Polar -> (Int, Int)
> > polarToCart (P a b) = (a, b)
> >
> > cartToPolar :: (Int, Int) -> Polar
> > cartToPolar (a, b) = P a b
> >
> > %fun mirror :: Polar -> Polar
> > %call (< polarToCart / cartToPolar > (int x) (int y))
> > %code x = -x;
> > % y = -y;
> > %result (< polarToCart / cartToPolar > (int x) (int y))
> 
> the error is this:
> 
> > [...]
> >
> > End of search list.
> >  [...]/2.8.1/cc1 /tmp/cca32238.i -quiet -dumpbase ghc32227.c -O -Wimplicit 
>-version -fomit-frame-pointer -fno-defer-pop -o ghc32227.s
> > GNU C version 2.8.1 (i586-pc-linux-gnu) compiled by GNU C version 2.8.1.
> > /tmp/ghc32227.hc:479: redeclaration of `x'
> > /tmp/ghc32227.hc:479: `x' previously declared here
> > /tmp/ghc32227.hc:479: redeclaration of `y'
> > /tmp/ghc32227.hc:479: `y' previously declared here
 
I believe that greencard may not be smart enough to realize that the
input variable names are the same as the output variable names. Thus, it
redeclares the same variable names twice. Try:

> %fun mirror :: Polar -> Polar
> %call (< polarToCart / cartToPolar > (int x) (int y))
> %code x_inv = -x;
> % y_inv = -y;
> %result (< polarToCart / cartToPolar > (int x_inv) (int y_inv))


- Michael Hobbs



Re: Threads in GHC's RTS

1999-04-16 Thread Michael Hobbs

"Manuel M. T. Chakravarty" wrote:
> 
> Michael Hobbs <[EMAIL PROTECTED]> wrote,
> 
> > I don't think that these three FFI types are enough to cover *all* of
> > the bases regarding callbacks, blocking, and thread-safety.
> 
> My point here is that, in the RTS, "unsafe", "safe", and
> "threadsafe" is enough.  The rest is a problem of the
> libraries and library bindings.

Okay, I can agree to that. :) I thought that you were trying to make a
swiss-army-knife, which would enable one to specify every type of
behaviour that he would like a foreign function to conform to.

> Following the reverse naming scheme of the FFI paper:
> 
>   unsafe - the RTS makes no special provisions and just
>calls the C function (this means the function
>must be well-behaved: no re-entry into the
>Haskell scheduler and no blocking if you
>don't want to block the whole Haskell system)
>   safe   - the RTS cleans things up, to allow the called
>function to re-enter the Haskell scheduler (but
>if the function blocks, the whole Haskell
>evaluation still blocks)
>   threadsafe - the RTS executes the foreign call in a
>   (or supersafe)   seperate OS thread (the function can do what
>it likes)
> 
> The label does NOT describe a property of the function, but
> it describes the strategy of the RTS.  For "safe" calls, the
> RTS plays safe, for "threadsafe" calls it plays supersafe.
> 
> Manuel

So what you have is increasing levels of "safety"? The first one is
completely unsafe; it could royally screw up the RTS if it invoked a
Haskell callback. The second is more safe; but it may cause the entire
RTS to block. And the third is completely safe; nothing it can do will
affect the Haskell RTS (within reason). Perhaps we should have a fourth
level of safety, where it spawns a new OS process? Ha ha, only
[slightly] serious.

This works for me, as long as I can still get barrier synchronization
like we [Manuel and myself] discussed earlier, but that's another issue.
I do think that the use of the word, "safe", is unfortunate though. It
seems to be too overloaded.

- Michael Hobbs



Mail list archives (was: Re: Mailing list)

1999-04-21 Thread Michael Hobbs

Since we're on the topic of the mailing list, has anyone else realized
that the archives are less-than-complete? For instance, most all of
Simon Marlow's recent emails are not listed there.

- Michael Hobbs



Re: Yet another Concurrency request

1999-05-11 Thread Michael Hobbs

In the short term, you can do what I do, use a combination of IORef and
unsafePerformIO to store the ThreadId into a "global variable". I try
not to use this too much though, since it does break down the purely
functional aspect of Haskell.

George Russell wrote:
> 
> Yes, it's me again.  Could there be an action in the Concurrent library
> which returns the ThreadId for the current thread?  Argument for:
> (1) this seems easy to implement.
> (2) it can't be simulated using the other functions.  (At least, not so far
> as I can see.)
> (3) if you want to write a lot of code that involves doing things to this
> thread (which seems rather likely to me), or identifying this thread in
> a unique way, you have to (a) get the ThreadID from the parent thread into
> this one (using an MVar say, ugh!) and then (b) haul it around as an
> argument all the time (ugh ugh!).
> I have purely selfish reasons for making this request; namely I have
> a chunk of Haskell to maintain which makes heavy use of such a function, but
> implements it via a _ccall which pokes around with GHC's internals.
> 
> Sorry to keep on about Concurrent, and if this is the wrong mailing list
> for talking about the Hugs/GHC extensions do let me know.
> 
> Many thanks
> 
> George Russell



Re: Trivial Haskell Concurrency problem

2000-02-14 Thread Michael Hobbs

George Russell wrote:
> The problem is that lowerFlags should appear to be atomic, so that
> if lowerFlags is called simultaneously in different threads, the result
> should be the same as if one of the calls completed before the other started.

If you want lowerFlags to be atomic, in the global sense, then you
really have no other option than to create a "global" variable (read:
unsafePerformIO). Intuitively, this make sense: if some thread needs to
know whether or not it has permission to perform lowerFlags, then there
must be some sort of common mutex with which to communicate with the
other threads. Depending on your situation, this common mutex could
perhaps exist in a closure.

However, I believe that you can be "reasonably" atomic without a global
variable. That is, if two or more lowerFlags calls are called with the
same Flag value, they will execute serially. I haven't thought enough
about it to come up with a concrete solution. If this is good enough,
I'll see if I can noodle on it some more.

- Michael Hobbs



Re: Trivial Haskell Concurrency problem

2000-02-14 Thread Michael Hobbs

George Russell wrote:
> What is the neatest solution?  There is an obvious solution, which is to
> crudely sequence all calls to lowerFlags by making them lock a single
> global variable (created using, sigh, unsafePerformIO) but this doesn't seem very
> elegant.  If MVar's were instances of Ord as well as Eq, a neat solution would
> be to always get the least MVar first, but they aren't.  So what should one do?

Okay, I thought about this a little more. You are very much on the right
track here. Breaking it down to fundamentals: somehow, some way, you
need to "lock" a Flag variable, so that if some other thread performs
lowerFlags with the same variable, it will wait. Then, considering that
the function takes two Flag variables in any arbitrary order, we can get
into a deadlock situation depending on which one is locked first. (We're
assuming that we can't lock them both simultaneously) Therefore, to get
around this, we need to impose some sort of ordering on the variables so
that one is always locked before the other, regardless of the order in
which they're passed.

Here's the solution: random. Since newFlag is declared IO Flag, you
should be able to easily embed a random number into the data type for
Flag. Granted, there is still the possibility that two Flag values get
assigned the same random number, in which case you won't know which one
will get locked first. But I think the odds of that happening are small
enough (unless you're generating billions of Flags and performing
trillions of lowerFlags calls).

A more sure-fire way of generating a unique number is to create a
"sequence" function, which will return the next number in a sequence
each time it's called. But again, such a function would require an
unsafePerformIO if it is to be used globally.

...or querying the system time, down to the nanosecond...

- Michael Hobbs



Re: Trivial Haskell Concurrency problem

2000-02-14 Thread Michael Hobbs

Michael Hobbs wrote:
> (We're assuming that we can't lock them both simultaneously)

I knew I should have read the literature on deadlock avoidance before
posting that message. :-/  In fact, I should have used the word
"atomically" above instead of "simultaneously". As it turns out, I
believe that assumption was incorrect. That is, it is possible to create
an atomic operation that locks two values, while avoiding deadlock.
Here's my stab at it. (NB: This is simply an off-the-cuff attempt. It
looks like it should work right, but it is far from rigorously tested or
analyzed.)

type PairMVar a = (MVar Bool, IORef a)

takePairMVar :: PairMVar a -> PairMVar b -> IO (a, b)
takePairMVar a@(claimA, refA) b@(claimB, refB) = do
  -- Attempt to lay claim to the A value. This will block if some other
thread
  -- has successfully completed A takePairMVar call using this value.
  aIsClaimed <- takeMVar claimA
  if aIsClaimed then do
-- Some other thread has snuck in and laid claim to A. Release
claimA and
-- try again.
putMVar claimA aIsClaimed
takePairMVar a b
   else do
-- Establish our claim on A and release claimA.
putMVar claimA True
-- Attempt to lay claim to the B value.
bIsClaimed <- takeMVar claimB
-- We need to takeMVar claimA regardless of whether bIsClaimed or
not.
-- At this point, we have a lock on claimB and are attempting to
lock
-- claimA. If some other thread has a lock on claimA and is
attempting to
-- lock claimB, we have a deadlock. However, this should never
happen since
-- we have established our claim on A so no other thread should have
claimA
-- locked indefinitely.
takeMVar claimA
if bIsClaimed then do
  -- Some other thread has snuck in and laid claim to B. Relinquish
all of
  -- our claims and try again.
  putMVar claimA False
  putMVar claimB bIsClaimed
  takePairMVar a b
 else do
  -- We have successfully locked claimA and claimB. We never
explicitly set
  -- claimB to True, since we have implicitly claimed it by keeping
it
  -- locked.
  valA <- readIORef refA
  valB <- readIORef refB
  return (valA, valB)

putPairMVar :: PairMVar a -> PairMVar b -> a -> b -> IO ()
putPairMVar (claimA, refA) (claimB, refB) a b = do
  -- Fairly straightforward. Write the values and relinquish all claims.
  writeIORef refA a
  writeIORef refB b
  putMVar claimA False
  putMVar claimB False
  return ()



Re: Trivial Haskell Concurrency problem

2000-02-14 Thread Michael Hobbs

Michael Hobbs wrote:
> Here's my stab at it. (NB: This is simply an off-the-cuff attempt. It
> looks like it should work right, but it is far from rigorously tested or
> analyzed.)



I discovered a path that would cause a deadlock in that code as well.
However, I have a change that /should/ prevent the deadlock. If anyone's
interested, email me privately, so I don't waste this list's bandwidth
with continuous revisions.

- Michael Hobbs



Re: Trivial Haskell Concurrency problem

2000-02-15 Thread Michael Hobbs

George Russell wrote:
> Does the phrase "Dining Philosophers Problem" ring a bell with anyone?

And AFAIK, the existing solutions to that problem requires a knowledge
of who all the philosophers are and what they are attempting to do. That
gets back to the issue of having a global value that stores a list of
all philosophers.