| I have recently spent some time improving GHC's support for | "threadsafe" foreign calls. | As a side effect of fixing a crashing bug, I made "safe" behave in | exactly the same way as "threadsafe". That's a positive advantage, provided there isn't a massive efficiency cost. I'm all for nuking 'threadsafe' if we can! | Are safe calls _guaranteed_ to block all other haskell threads and | prevent garbage collection, | or is that an implementation detail? Are unsafe calls guaranteed to do | so? {In a SMP implementation, | this might require additional interthread messaging}. | What should happen when C code running in a separate OS thread calls a | foreign exported | function while the Haskell Runtime is blocked on a safe call? Would all these questions go away if we made safe=threadsafe? | Some people have said that "safe" calls are intended for serializing | access to foreign libraries | that are not multithread-safe. I think that MVars should be used for | such purposes. Blocking the | entire Haskell Runtime for the duration of a "safe" call is overkill, | but it's not always enough: | Many old C libraries keep state in global variables from one call to | the next. I don't think it was ever the intention that 'safe' should have a guaranteed serialisation property. I think the idea was that 'threadsafe' was the most desirable, with 'safe' and 'unsafe' only available for use if you wanted more efficiency and had some separate guarantees that the extra efficiency was not at the expense of correctness. To be completely explicit, I think that increasing the safety level of any foreign import should never make the program fail. Simon
Simon Peyton-Jones wrote:
That's a positive advantage, provided there isn't a massive efficiency cost. I'm all for nuking 'threadsafe' if we can!
Simon Marlow wrote:
However, at the time I don't think we appreciated the implementation diffiulties arising from "safe".
After thinking about it a little, I'm not even ready to bet that "safe" would be that much faster than "threadsafe" for GHC... Safe call-out can probably be optimized by not sending a signal to a worker thread. (Worker thread spawning happens only the first time, so it is not an issue). Afterwards, we could immediately re-grab the "Capability" (without waiting) and reenter the RTS, _unless_ there has been a call-in in the meantime. We cannot do call-ins the same way as in the non-threaded RTS, because when "threadsafe" calls are around, we cannot return from schedule() (execution might have moved to a different worker). After a call-in, the worker thread that was used to handle the call-in would still hold the capability and continue executing haskell code, so a safe call would have turned threadsafe. This might be difficult to prevent in practice. Also, the biggest piece of wasted performance that's currently lying around there is the locking for call-ins: give me a version of allocate that I can safely call with only the sched_mutex held (while STG code is executing in another thread), and I can cut the number of context switches for a call-in in half. Simon PJ wrote:
To be completely explicit, I think that increasing the safety level of any foreign import should never make the program fail.
I like that. Did I already mention that I think that the safest variant should be the default? ;-)
| [...] | What should happen when C code running in a separate OS thread calls a | foreign exported | function while the Haskell Runtime is blocked on a safe call?
Would all these questions go away if we made safe=threadsafe?
Yes. All but the last one also go away when we keep the distinction, but say that "increasing the safety level [...] should never make the program fail". Cheers, Wolfgang
participants (2)
-
Simon Peyton-Jones -
Wolfgang Thaller