First, the "bug" part: None of the libraries that use errno are compatible with concurrency. When a (lightweight) thread-switch occurs between the call to some foreign function and the corresponding call to Foreign.C.Error.getErrno, we have a problem: a) the RTS trashes the value of errno b) another Haskell thread might call a function that sets errno c) on most platforms, errno is thread-local state, with all the consequences that has for the threaded RTS (bound threads required....) Now, the "ffi" part: b) and c) could be solved by using bound threads, but that's probably too inefficient for something that's used as frequently as errno. Bound threads wouldn't solve a). I therefore propose that we make the RTS save & restore the value of errno in the TSO, thus making errno "Haskell-Thread-Local-State", and solving all of the above problems. I also propose adding a note to the FFI spec (or the bound threads document, I'm not sure which is the right place) that says that implementations have to make sure that "Errno" is local to each *Haskell* thread. Cheers, Wolfgang
I was thinking about this too but had a different idea, an alternate calling form which grabbed the result of errno and returned it to haskell land. that way the cost of geting errno is only paid for those foreign imports which care about it. like foreign import ccall_errno "unistd.h chdir" :: Ptr CChar -> IO (CInt,CInt) where the second CInt returned will be the value of errno after the call to chdir. another solution is to do everything in C wrappers which return errno as well as the return value. another is some sort of blocking function which blocks context switching within the same OS thread temporarily.. or your idea below. just thought I'd throw some alternate ideas into the mix. I am not a fan of having to stow errno for every ffi call.. John On Thu, Jul 24, 2003 at 11:48:02PM +0200, Wolfgang Thaller wrote:
First, the "bug" part:
None of the libraries that use errno are compatible with concurrency. When a (lightweight) thread-switch occurs between the call to some foreign function and the corresponding call to Foreign.C.Error.getErrno, we have a problem:
a) the RTS trashes the value of errno b) another Haskell thread might call a function that sets errno c) on most platforms, errno is thread-local state, with all the consequences that has for the threaded RTS (bound threads required....)
Now, the "ffi" part:
b) and c) could be solved by using bound threads, but that's probably too inefficient for something that's used as frequently as errno. Bound threads wouldn't solve a).
I therefore propose that we make the RTS save & restore the value of errno in the TSO, thus making errno "Haskell-Thread-Local-State", and solving all of the above problems. I also propose adding a note to the FFI spec (or the bound threads document, I'm not sure which is the right place) that says that implementations have to make sure that "Errno" is local to each *Haskell* thread.
Cheers,
Wolfgang
_______________________________________________ FFI mailing list FFI@haskell.org http://www.haskell.org/mailman/listinfo/ffi
-- --------------------------------------------------------------------------- John Meacham - California Institute of Technology, Alum. - john@foo.net ---------------------------------------------------------------------------
John Meacham wrote:
I was thinking about this too but had a different idea, an alternate calling form which grabbed the result of errno and returned it to haskell land. that way the cost of geting errno is only paid for those foreign imports which care about it. like
foreign import ccall_errno "unistd.h chdir" :: Ptr CChar -> IO (CInt,CInt)
where the second CInt returned will be the value of errno after the call to chdir.
John's first suggested alternative above seems very appealing to me, as it seems neatly to fix the fundamental design flaw in `errno`: that determining the success/failure of a system call is separated from the call itself. I'm surprised more sentiment in its favor has not shown up. What are the disadvantages of such a solution?
another solution is to do everything in C wrappers which return errno as well as the return value.
another is some sort of blocking function which blocks context switching within the same OS thread temporarily..
or your idea below. just thought I'd throw some alternate ideas into the mix. I am not a fan of having to stow errno for every ffi call.. John
On Thu, Jul 24, 2003 at 11:48:02PM +0200, Wolfgang Thaller wrote:
First, the "bug" part:
None of the libraries that use errno are compatible with concurrency. When a (lightweight) thread-switch occurs between the call to some foreign function and the corresponding call to Foreign.C.Error.getErrno, we have a problem:
a) the RTS trashes the value of errno b) another Haskell thread might call a function that sets errno c) on most platforms, errno is thread-local state, with all the consequences that has for the threaded RTS (bound threads required....)
Now, the "ffi" part:
b) and c) could be solved by using bound threads, but that's probably too inefficient for something that's used as frequently as errno. Bound threads wouldn't solve a).
I therefore propose that we make the RTS save & restore the value of errno in the TSO, thus making errno "Haskell-Thread-Local-State", and solving all of the above problems. I also propose adding a note to the FFI spec (or the bound threads document, I'm not sure which is the right place) that says that implementations have to make sure that "Errno" is local to each *Haskell* thread.
-- Dean
Dean Herington <heringto@cs.unc.edu> writes:
foreign import ccall_errno "unistd.h chdir" :: Ptr CChar -> IO (CInt,CInt)
John's first suggested alternative above seems very appealing to me, as it seems neatly to fix the fundamental design flaw in `errno`: that determining the success/failure of a system call is separated from the call itself. I'm surprised more sentiment in its favor has not shown up. What are the disadvantages of such a solution?
The first and most obvious disadvantage is that the basic FFI currently has no direct mechanism to return a pair of values. The idiomatic way to achieve the same effect is to store the two values in a C structure and return a pointer to it, unpacking the structure again on the Haskell side of the interface, and de-allocating the structure somehow afterwards. Obviously this is a tedious and mechanical job to go through, but this is exactly the province of tool support, rather than the basic FFI. There are already tools that support this idiom (e.g. GreenCard), and you can already write your errno bindings this way if you want to. For instance: %#include <errno.h> %fun chdir :: Ptr CChar -> IO (CInt,CInt) %call (ptr cd) %code res=chdir(cd); %result (cint res, cint errno) Regards, Malcolm
Dnia pią 25. lipca 2003 16:52, Dean Herington napisał:
John's first suggested alternative above seems very appealing to me, as it seems neatly to fix the fundamental design flaw in `errno`: that determining the success/failure of a system call is separated from the call itself. I'm surprised more sentiment in its favor has not shown up. What are the disadvantages of such a solution?
That you usually wrap functions which set errno in higher order functions which translate it to exceptions (there are such functions ready in FFI libraries), so it doesn't matter how it's implemented under the hood. And the current mechanism, with the change for threads, is simpler. -- __("< Marcin Kowalczyk \__/ qrczak@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/
John's first suggested alternative above seems very appealing to me, as it seems neatly to fix the fundamental design flaw in `errno`: that determining the success/failure of a system call is separated from the call itself.
Slightly off-topic but it reminds me of one of my pet peeves with C... I think the design flaw is in C and that is merely reflected in the C library. If you listen to the propaganda, C is just a portable assembly language and, in many ways, C is just that. One of the big differences though is that in assembly language, there is no problem returning multiple values -just load up multiple registers or put multiple values on the stack- but in C, there is no good way to return multiple values. -- Alastair Reid
Alastair Reid wrote:
John's first suggested alternative above seems very appealing to me, as it seems neatly to fix the fundamental design flaw in `errno`: that determining the success/failure of a system call is separated from the call itself.
Slightly off-topic but it reminds me of one of my pet peeves with C...
I think the design flaw is in C and that is merely reflected in the C library. If you listen to the propaganda, C is just a portable assembly language and, in many ways, C is just that. One of the big differences though is that in assembly language, there is no problem returning multiple values -just load up multiple registers or put multiple values on the stack- but in C, there is no good way to return multiple values.
Well, you can return a structure. The main disadvantage there is that, due to C's lack of anonymous product types (tuples), you would have to define a bunch of new structure types. The other problem, namely that the caller has to separate the "real" result from the ancilliary data, is equally applicable to Haskell. E.g.: let (y, _) = f x (z, _) = g y in z or even: fst $ g $ fst $ f x are less convenient than just "g $ f x". The overhead may be worthwhile when you frequently want to use the ancilliary information but, with one exception[1], checking errno is relatively uncommon. Most of the time you only need to know that the call failed, rather than the exact reason why it failed. [1] Of those cases where you do actually check errno, IME the majority come down to checking for EAGAIN when using non-blocking I/O. IMHO, a far bigger problem is the use of distinguished return values (typically -1 or NULL in C, Nothing in Haskell) rather than exceptions. If I ever decide to switch from C to C++ for everyday use, it's more likely to be for C++'s exceptions than for it's OO support. -- Glynn Clements <glynn.clements@virgin.net>
participants (7)
-
Alastair Reid -
Dean Herington -
Glynn Clements -
John Meacham -
Malcolm Wallace -
Marcin 'Qrczak' Kowalczyk -
Wolfgang Thaller