on master help sign in
adding comments.
commit4f5731769e0882b45edf7bf6ff107c0d4c31a433 authorKazu Yamamoto <kazu@iij.ad.jp> dateWed 16 Jul 2014, 12:08 (12 years ago) parent641ae83
1 file changed+13−2
auto-update/Control/AutoUpdate.hs+13−2
auto-update/Control/AutoUpdate.hs+13−2
@@ -131,10 +131,13 @@ getCurrent freq spawnThreshold action istatus = do
131131 where
132132 act = if i > spawnThreshold then Spawn else Manual
133133
134− turnToAuto a tid (AutoUpdated _ cnt old) = (AutoUpdated a cnt tid
135− ,throwTo old Replaced)
134+ -- Normal case.
136135 turnToAuto a tid (ManualUpdates cnt) = (AutoUpdated a cnt tid
137136 ,return ())
137+ -- Race condition: multiple threads were spawned.
138+ -- So, let's kill the previous one by this thread.
139+ turnToAuto a tid (AutoUpdated _ cnt old) = (AutoUpdated a cnt tid
140+ ,throwTo old Replaced)
138141
139142spawn :: Int -> IO a -> IORef (Status a) -> IO ()
140143spawn freq action istatus = handle (onErr istatus) $ forever $ do
@@ -157,6 +160,14 @@ onErr istatus ex = case fromException ex of
157160 atomicModifyIORef istatus $ clear tid
158161 throwIO ex
159162 where
163+ -- In the race condition described above,
164+ -- suppose thread A is running, and is killed by thread B.
165+ -- Thread B then updates the IORef to refer to thread B.
166+ -- Then thread A's exception handler fires.
167+ -- We don't want to modify the IORef at all,
168+ -- since it refers to thread B already.
169+ -- Solution: only switch back to manual updates
170+ -- if the IORef is pointing at the current thread.
160171 clear tid (AutoUpdated _ _ tid') | tid == tid' = (ManualUpdates 0, ())
161172 clear _ status = (status, ())
162173