In the following code I am sending a record with an IO (TMVar o) off to get populated in a function then reading
what I believe should be the same TMVar when the function returns. The problem is when I read it back it's empty and the application just blocks.
Why is this happening?
The Hook is intialised as follows:
hook = Hook {
-- other props
hookResult = newEmptyTMVarIO,
}
later in the ap:
executeHook :: (Text -> IO ()) -> Node i o -> IO ()
executeHook db =
\case
Fixture {} -> pure ()
Hook
{ hookParent,
hookStatus,
hook,
hookResult, -- IO (TMVar o)
hookChildren
} -> do
input <- db "CALL PARENT LOCK EXECUTE HOOK" >> lockExecuteHook db hookParent
result <- hook input
hr <- hookResult
mtb <- atomically $ isEmptyTMVar hr
db $ "HOOK RESULT PUT EMPTY BEFORE: " <> txt mtb
atomically $ putTMVar hr result -- writes hook result to the TMVar
mt <- atomically $ isEmptyTMVar hr
db $ "HOOK RESULT PUT EMPTY AFTER: " <> txt mt
lockExecuteHook :: (Text -> IO ()) -> Either o (Node i o) -> IO o
lockExecuteHook db parent =
eitherf
parent
(\o -> db "NO PARENT HOOK RETURNING VALUE" >> pure o)
( \case
Fixture {} -> pure ()
hk@Hook
{ hookParent,
hookStatus,
hookResult, -- IO (TMVar o)
hook,
hookChildren,
hookRelease
} -> do
bs <- hookStatus
wantLaunch <- atomically $ tryLock db bs
db $ "HOOK LOCK >>> " <> txt wantLaunch
when
wantLaunch
$ executeHook db hk -- this writes hook result to the TMVar
hr <- hookResult
mt <- atomically $ isEmptyTMVar hr
db $ "READING HOOK !!!!!!!!!!!!!!!!!!!!!!!!!! EMPTY: " <> txt mt
r <- atomically $ readTMVar hr
db "RETURNING FROM LOCK EXECUTE HOOK " >> pure r
)
Debug (db) output
CALL PARENT LOCK EXECUTE HOOK
HOOK LOCK >>> True
HOOK RESULT PUT EMPTY BEFORE: True
HOOK RESULT PUT EMPTY AFTER: False
READING HOOK !!!!!!!!!!!!!!!!!!!!!!!!!! EMPTY: True
As pointed out in the above comments by @FyodorSoikin, @DanielWagner and @chi, the reason this was not working as expected is that
hookResultwas not initialised correctly.Setting the record field to an
IO (TMVar a)will result in a newTMVar aevery timehookResultis read, similar problem would occur if the field was set to anSTM (TMVar a)usingnewTMVar. To make this workhookResultneeds to be set to aTMVar afrom within the IO or STM context.