RE: [Haskell-cafe] STM, orElse and timed read from a channel

On 29 November 2005 12:08, Tomasz Zielonka wrote:
On Tue, Nov 29, 2005 at 12:00:03PM -0000, Simon Marlow wrote:
threadDelay is IO-only; there's no way to use threadDelay in an STM transaction. For example, if you want to wait for a TVar to go from Nothing to Just x with a timeout, you could do this:
readOrTimeout :: TVar (Maybe a) -> Int -> STM (Maybe a) readOrTimeout t secs = do timeout <- registerTimeout secs let check_timeout = do b <- readTVar timeout if b then return Nothing else retry check_t = do m <- readTVar t case m of Nothing -> retry Just x -> return x atomically $ check_timeout `orElse` check_t
Wouldn't it be readOrTimeout :: TVar (Maybe a) -> Int -> IO (Maybe a) ^^ ?
Sorry, yes.
Alternatively, it would be nice to have a new STM primitive:
wailUntil :: ClockTime -> STM ()
so you would wait until some time-point passes, not for a number of time-units (waiting for a number of time-units wouldn't work because of retries). I think it could be efficiently implemented, wouldn't it?
Interesting. You could use that do wait for idle time, for example: atomically $ do t <- readTVar last_mouse_click waitUntil (t+1000) ... so this transaction only completes when some idle time has passed since the last mouse click. But you could also implement this using registerTimeout, albeit with some more code and an extra thread, and waitUntil requires an implementation in the runtime which is not entirely trivial. Cheers, Simon

Simon, Where is this "registerTimeout" in the GHC code? Thanks, Joel On Nov 29, 2005, at 12:29 PM, Simon Marlow wrote:
But you could also implement this using registerTimeout, albeit with some more code and an extra thread, and waitUntil requires an implementation in the runtime which is not entirely trivial.

On Tue, Nov 29, 2005 at 12:29:55PM -0000, Simon Marlow wrote:
Alternatively, it would be nice to have a new STM primitive:
wailUntil :: ClockTime -> STM ()
so you would wait until some time-point passes, not for a number of time-units (waiting for a number of time-units wouldn't work because of retries). I think it could be efficiently implemented, wouldn't it?
But you could also implement this using registerTimeout, albeit with some more code and an extra thread, and waitUntil requires an implementation in the runtime which is not entirely trivial.
It is trivial to create a very inefficient implementation, in which all STM transactions waiting on waitUntil will be retried on (almost) every tick of the clock, let's say every second. You just create a TVar that is updated with current time every second. But as I say, the efficiency would be unacceptable. But this can be improved. I found a simple solution that reduces the number of transaction retries to O(log (t - t0)), where t0 is transaction start time, and t is the parameter to waitUntil. I attached a proof-of-concept implementation to this message. I simply use the binary representation of time and wait only on the part of bits, starting from most significant ones, that are enough to tell that the waitUntil time has not come. To make it simple I used unix epoch time in seconds, but the thing could be made more precise. I the thread updating the time variable I make sure that I don't update the bits that didn't change. You can compile the Test module as a program. There are two kinds of tests, some that show how many tries are made, and one that shows how the thing works for many threads. BTW, I tried to make the library interface simpler creating a default top-level time variable {-# NOINLINE timeVar #-} timeVar :: TimeVar timeVar = unsafePerformIO initTimeVar so I could export a waitUntil function with type waitUntil :: Time -> STM () but I tripped on something that was reported before, namely that STM transactions can't be nested (as a result of unsafePerformIO or unsafeInterleaveIO). Is there a plan to support such scenario? Best regards Tomasz -- I am searching for a programmer who is good at least in some of [Haskell, ML, C++, Linux, FreeBSD, math] for work in Warsaw, Poland

On Sat, Dec 03, 2005 at 10:35:54PM +0100, Tomasz Zielonka wrote:
but I tripped on something that was reported before, namely that STM transactions can't be nested (as a result of unsafePerformIO or unsafeInterleaveIO).
I should rather say "nested 'atomically' blocks". Best regards Tomasz -- I am searching for a programmer who is good at least in some of [Haskell, ML, C++, Linux, FreeBSD, math] for work in Warsaw, Poland

On Sat, Dec 03, 2005 at 10:35:54PM +0100, Tomasz Zielonka wrote:
so I could export a waitUntil function with type
waitUntil :: Time -> STM ()
but I tripped on something that was reported before, namely that STM transactions can't be nested (as a result of unsafePerformIO or unsafeInterleaveIO). Is there a plan to support such scenario?
OK, it can be worked around by running the atomically block in a new transaction. But still it would be nice if the program didn't segfault, but cause an exception for example. Updated modules attached. Best regards Tomasz -- I am searching for a programmer who is good at least in some of [Haskell, ML, C++, Linux, FreeBSD, math] for work in Warsaw, Poland
participants (3)
-
Joel Reymont
-
Simon Marlow
-
Tomasz Zielonka