diff --git a/haskell/DEVLOG.md b/haskell/DEVLOG.md index 26855911..dc5fc3b7 100644 --- a/haskell/DEVLOG.md +++ b/haskell/DEVLOG.md @@ -594,6 +594,42 @@ Haven't seen this one before, a compile failure on the cfa package: ... ld: symbol(s) not found for architecture x86_64 + +[2014.01.24] {Failure after recent nonidem merge} +------------------------------------------------- + + Failed to install lvish-1.2.0.0 + Last 10 lines of the build log ( /ffh/ryan/cloud_drive/working_copies/lvars/lvars/haskell/.cabal-sandbox/logs/lvish-1.2.0.0.log ): + Passed 5 64 69 + Failed 0 1 1 + Total 5 65 70 + [*] test-framework exiting with: ExitFailure 1 + [*] GC finished on main thread. + [*] Main thread exiting. + Test suite test-lvish: FAIL + Test suite logged to: + dist/dist-sandbox-38f74c87/test/lvish-1.2.0.0-test-lvish.log + 0 of 1 test suites (0 of 1 test cases) passed. + +Specifically, the failure is: + + ThreadKilled exception inside child thread, ThreadId 79270 (not propagating!): "worker thread" + v4: [Failed] + Bad test outcome--exception: PutAfterFreezeExn "Attempt to change a frozen LVar" + +It's proving a bit hard to reproduce, however. + +Also... test after i9h is apparently deadlocking on -N4. Hmm.. why +are timeouts not working? + (And I'm getting plenty of the blocked-indefinitely errors in + various papers... these are probably the same failure but sometimes + the GC turns it into an exception. Not sure why timeouts aren't + working consistently on this branch. I see them sometimes.) + +Ah, ok, I can get failures on AddRemoveSetTests + + + [2014.01.24] {More scheduler debugging} ---------------------------------------- diff --git a/haskell/lvish/Control/LVish.hs b/haskell/lvish/Control/LVish.hs index de0fa5cc..3ce6ab0f 100755 --- a/haskell/lvish/Control/LVish.hs +++ b/haskell/lvish/Control/LVish.hs @@ -102,8 +102,8 @@ import Control.LVish.Types import Control.LVish.Internal as I import Control.LVish.Basics as B import Control.LVish.Logical -import qualified Control.LVish.SchedIdempotent as L -import Control.LVish.SchedIdempotentInternal (State) +import qualified Control.LVish.Sched as L +import Control.LVish.SchedQueue (State) import Control.LVish.Logging (OutDest(..)) import Data.LVar.IVar diff --git a/haskell/lvish/Control/LVish/Basics.hs b/haskell/lvish/Control/LVish/Basics.hs index 2d78a3a7..4182dda9 100644 --- a/haskell/lvish/Control/LVish/Basics.hs +++ b/haskell/lvish/Control/LVish/Basics.hs @@ -37,7 +37,7 @@ import qualified Data.Foldable as F import Control.Exception (Exception, SomeException) import Control.LVish.Internal as I import Control.LVish.DeepFrz.Internal (Frzn, Trvrsbl) -import qualified Control.LVish.SchedIdempotent as L +import qualified Control.LVish.Sched as L import qualified Control.LVish.Logging as Lg import Control.LVish.Types import System.IO.Unsafe (unsafePerformIO, unsafeDupablePerformIO) diff --git a/haskell/lvish/Control/LVish/DeepFrz.hs b/haskell/lvish/Control/LVish/DeepFrz.hs index 2efa44d1..e369403a 100644 --- a/haskell/lvish/Control/LVish/DeepFrz.hs +++ b/haskell/lvish/Control/LVish/DeepFrz.hs @@ -53,7 +53,7 @@ import GHC.Prim (unsafeCoerce#) -- import Control.LVish (LVarData1(..)) import Control.LVish.DeepFrz.Internal (DeepFrz(..), NonFrzn, Frzn, Trvrsbl) import Control.LVish.Internal (Determinism(..), Par(WrapPar)) -import Control.LVish.SchedIdempotent (runPar, runParIO) +import Control.LVish.Sched (runPar, runParIO) -------------------------------------------------------------------------------- -- | Under normal conditions, calling a `freeze` operation inside a diff --git a/haskell/lvish/Control/LVish/Internal.hs b/haskell/lvish/Control/LVish/Internal.hs index 8cdda32a..c4526ec6 100644 --- a/haskell/lvish/Control/LVish/Internal.hs +++ b/haskell/lvish/Control/LVish/Internal.hs @@ -34,7 +34,7 @@ module Control.LVish.Internal import Control.LVish.MonadToss import Control.Applicative -import qualified Control.LVish.SchedIdempotent as L +import qualified Control.LVish.Sched as L import Control.LVish.DeepFrz.Internal (Frzn, Trvrsbl) import qualified Data.Foldable as F import Data.List (sort) @@ -69,7 +69,7 @@ type QPar = Par QuasiDet -- to. -- LK: I don't care if we use `a` and `d` or `all` and `delt`, but why --- not be consistent between here and SchedIdempotent.hs? Also, what +-- not be consistent between here and Sched.hs? Also, what -- does `all` mean? newtype LVar s all delt = WrapLVar { unWrapLVar :: L.LVar all delt } diff --git a/haskell/lvish/Control/LVish/Logical.hs b/haskell/lvish/Control/LVish/Logical.hs index 060cb184..bfab3f99 100644 --- a/haskell/lvish/Control/LVish/Logical.hs +++ b/haskell/lvish/Control/LVish/Logical.hs @@ -5,7 +5,7 @@ module Control.LVish.Logical (asyncAnd, asyncOr, andMap, orMap) where import Control.LVish.Basics import Control.LVish.Internal (Par(WrapPar), unsafeDet) -import Control.LVish.SchedIdempotent (liftIO, HandlerPool) +import Control.LVish.Sched (liftIO, HandlerPool) import Data.LVar.IVar as IV import qualified Data.Atomics.Counter as C diff --git a/haskell/lvish/Control/LVish/SchedIdempotent.hs b/haskell/lvish/Control/LVish/Sched.hs similarity index 78% rename from haskell/lvish/Control/LVish/SchedIdempotent.hs rename to haskell/lvish/Control/LVish/Sched.hs index 82773dfe..551f5318 100644 --- a/haskell/lvish/Control/LVish/SchedIdempotent.hs +++ b/haskell/lvish/Control/LVish/Sched.hs @@ -18,7 +18,7 @@ -- | This is an internal module that provides the core parallel scheduler. -- It is /not/ for end-users. -module Control.LVish.SchedIdempotent +module Control.LVish.Sched ( -- * Basic types and accessors LVar(..), state, HandlerPool(), @@ -76,7 +76,7 @@ import Text.Printf (printf, hPrintf) import Data.Traversable hiding (forM) import Control.LVish.Types -import qualified Control.LVish.SchedIdempotentInternal as Sched +import qualified Control.LVish.SchedQueue as Queue ------------------------------------------------------------------------------ -- LVar and Par monad representation @@ -102,7 +102,8 @@ import qualified Control.LVish.SchedIdempotentInternal as Sched data LVar a d = LVar { state :: a, -- the current, "global" state of the LVar status :: {-# UNPACK #-} !(IORef (Status d)), -- is the LVar active or frozen? - name :: {-# UNPACK #-} !LVarID -- a unique identifier for this LVar + name :: {-# UNPACK #-} !LVarID, -- a unique identifier for this LVar + handlerStatus :: {-# UNPACK #-} !(IORef HandlerStatus) -- are handlers being installed? } type LVarID = IORef () @@ -135,6 +136,11 @@ data Listener d = Listener { onFreeze :: B.Token (Listener d) -> SchedState -> IO () } +data HandlerStatus + = Dormant -- no handlers currently being installed + | Installing Int [ClosedPar] -- some number of handlers being installed, with + -- a list of blocked puts waiting on completion + -- | A @HandlerPool@ contains a way to count outstanding parallel computations that -- are affiliated with the pool. It detects the condition where all such threads -- have completed. @@ -159,7 +165,7 @@ newtype ClosedPar = ClosedPar { exec :: SchedState -> IO () } -type SchedState = Sched.State ClosedPar LVarID +type SchedState = Queue.State ClosedPar LVarID instance Functor Par where fmap f m = Par $ \k -> close m (k . f) @@ -189,7 +195,8 @@ isFrozen (LVar {status}) = do curStatus <- readIORef status case curStatus of Active _ -> return False - _ -> return True + Frozen -> return True + -- | Logging within the (internal) Par monad. logStrLn :: Int -> String -> Par () @@ -212,17 +219,18 @@ logHelper lgr num msg = when (dbgLvl >= 1) $ do Just lgr -> L.logOn lgr msg' Nothing -> hPutStrLn stderr ("WARNING/nologger:"++show msg') -logWith :: Sched.State a s -> Int -> String -> IO () -logOffRecord :: Sched.State a s -> Int -> String -> IO () +logWith :: Queue.State a s -> Int -> String -> IO () +logOffRecord :: Queue.State a s -> Int -> String -> IO () #ifdef DEBUG_LVAR -- Only when the debug level is 1 or higher is the logger even initialized: -logWith q lvl str = logHelper (Sched.logger q) (Sched.no q) (L.StrMsg lvl str) -logOffRecord q lvl str = logHelper (Sched.logger q) (Sched.no q) (L.OffTheRecord lvl str) +logWith q lvl str = logHelper (Queue.logger q) (Queue.no q) (L.StrMsg lvl str) +logOffRecord q lvl str = logHelper (Queue.logger q) (Queue.no q) (L.OffTheRecord lvl str) #else logWith _ _ _ = return () logOffRecord _ _ _ = return () #endif + ------------------------------------------------------------------------------ -- LVar operations ------------------------------------------------------------------------------ @@ -240,7 +248,8 @@ newLV init = mkPar $ \k q -> do listeners <- B.new status <- newIORef $ Active listeners name <- newLVID - exec (k $ LVar {state, status, name}) q + handlerStatus <- newIORef Dormant + exec (k $ LVar {state, status, name, handlerStatus}) q -- | Do a threshold read on an LVar getLV :: (LVar a d) -- ^ the LVar @@ -267,8 +276,10 @@ getLV lv@(LVar {state, status}) globalThresh deltaThresh = mkPar $ \k q -> do -- continuation immediately Nothing -> do -- /transiently/ not past the threshhold; block - execFlag <- newDedupCheck + let enableCont b = unless (Queue.idemp q) $ + winnerCheck execFlag q (Queue.pushWork q (k b)) (return ()) + let onUpdate d = unblockWhen $ deltaThresh d onFreeze = unblockWhen $ globalThresh state True {-# INLINE unblockWhen #-} @@ -278,10 +289,9 @@ getLV lv@(LVar {state, status}) globalThresh deltaThresh = mkPar $ \k q -> do tripped <- thresh whenJust tripped $ \b -> do B.remove tok - winnerCheck execFlag q (Sched.pushWork q (k b)) (return ()) + enableCont b - logWith q 8$ " [dbg-lvish] getLV "++show(unsafeName execFlag)++ - ": blocking on LVar, registering listeners..." + logWith q 8$ " [dbg-lvish] getLV: blocking on LVar, registering listeners..." -- add listener, i.e., move the continuation to the waiting bag tok <- B.put listeners $ Listener onUpdate onFreeze @@ -318,7 +328,7 @@ getLV lv@(LVar {state, status}) globalThresh deltaThresh = mkPar $ \k q -> do {-# INLINE newDedupCheck #-} {-# INLINE winnerCheck #-} -winnerCheck :: DedupCell -> Sched.State a s -> IO () -> IO () -> IO () +winnerCheck :: DedupCell -> Queue.State a s -> IO () -> IO () -> IO () newDedupCheck :: IO DedupCell #if GET_ONCE @@ -334,7 +344,7 @@ winnerCheck execFlag q tru fal = do else do (winner, _) <- casIORef execFlag ticket True logWith q 8 $ " [dbg-lvish] getLV "++show(unsafeName execFlag) - ++" on worker "++ (show$ Sched.no q) ++": winner check? " ++show winner + ++" on worker "++ (show$ Queue.no q) ++": winner check? " ++show winner ++ ", ticks " ++ show (ticket, peekTicket ticket) if winner then tru else fal # else @@ -344,7 +354,7 @@ newDedupCheck = C2.newCounter 0 winnerCheck execFlag q tru fal = do cnt <- C2.incrCounter 1 execFlag logWith q 8 $ " [dbg-lvish] getLV "++show(unsafeName execFlag) - ++" on worker "++ (show$ Sched.no q) ++": winner check? " ++show (cnt==1) + ++" on worker "++ (show$ Queue.no q) ++": winner check? " ++show (cnt==1) ++ ", counter val " ++ show cnt if cnt==1 then tru else fal @@ -359,40 +369,62 @@ winnerCheck _ _ tr _ = tr - - -- | Update an LVar. putLV_ :: LVar a d -- ^ the LVar -> (a -> Par (Maybe d, b)) -- ^ how to do the put, and whether the LVar's -- value changed -> Par b -putLV_ lv@(LVar {state, status, name}) doPut = mkPar $ \k q -> do - let uniqsuf = ", lv "++(lvarDbgName lv)++" on worker "++(show$ Sched.no q) - putAfterFrzExn = E.throw$ PutAfterFreezeExn "Attempt to change a frozen LVar" - logWith q 8 $ " [dbg-lvish] putLV: initial lvar status read"++uniqsuf - fstStatus <- readIORef status - case fstStatus of - Freezing -> putAfterFrzExn - Frozen -> putAfterFrzExn - Active listeners -> do - logWith q 8 $ " [dbg-lvish] putLV: setStatus,"++uniqsuf - Sched.setStatus q name -- publish our intent to modify the LVar - let cont (delta, ret) = ClosedPar $ \q -> do - logWith q 8 $ " [dbg-lvish] putLV: read final status before unsetting"++uniqsuf - sndStatus <- readIORef status -- read the frozen bit *while q's status is marked* - logWith q 8 $ " [dbg-lvish] putLV: UN-setStatus"++uniqsuf - Sched.setStatus q noName -- retract our modification intent - -- AFTER the retraction, freezeLV is allowed to set the state to Frozen. - whenJust delta $ \d -> do - case sndStatus of - Frozen -> putAfterFrzExn - _ -> do - logWith q 9 $ " [dbg-lvish] putLV: calling each listener's onUpdate"++uniqsuf - B.foreach listeners $ \(Listener onUpdate _) tok -> onUpdate d tok q - exec (k ret) q - logWith q 5 $ " [dbg-lvish] putLV: about to mutate lvar"++uniqsuf - exec (close (doPut state) cont) q +putLV_ lv@(LVar {state, status, name, handlerStatus}) doPut = + mkPar body where + body k q = + let uniqsuf = ", lv "++(lvarDbgName state)++" on worker "++(show$ Queue.no q) + putAfterFrzExn = E.throw$ PutAfterFreezeExn "Attempt to change a frozen LVar" + + setPutFlag = Queue.setStatus q name + clearPutFlag = Queue.setStatus q noName + + cont (delta, ret) = ClosedPar $ \q -> do + logWith q 8 $ " [dbg-lvish] putLV/cont: read status"++uniqsuf + curStatus <- readIORef status -- read the frozen bit *while q's status is marked* + logWith q 8 $ " [dbg-lvish] putLV/cont: clearPutFlag"++uniqsuf + clearPutFlag -- retract our modification intent + whenJust delta $ \d -> do + case curStatus of + Freezing -> putAfterFrzExn + Frozen -> putAfterFrzExn + Active listeners -> do + -- FIXME: need finer granularity here: + logWith q 9 $ " [dbg-lvish] putLV/cont: calling each listener's onUpdate"++uniqsuf + B.foreach listeners $ \(Listener onUpdate _) tok -> do onUpdate d tok q + exec (k ret) q + + execPut = do + logWith q 8 $ " [dbg-lvish] putLV: about to exec the real mutation"++uniqsuf + exec (close (doPut state) cont) q -- possibly modify the LVar + + putIdemp = do + logWith q 8 $ " [dbg-lvish] putLV/idem: setPutFlag"++uniqsuf + setPutFlag -- publish our intent to modify the LVar + execPut -- do the modification (and subsequently clear the flag) + + putNonidemp = do + logWith q 8 $ " [dbg-lvish] putLV/nonidem: setPutFlag"++uniqsuf + setPutFlag -- publish our intent to modify the LVar + logWith q 8 $ " [dbg-lvish] putLV/nonidem: initial handlerStatus read"++uniqsuf + ticket <- readForCAS handlerStatus + case peekTicket ticket of + Dormant -> execPut + Installing n ps -> do + logWith q 8 $ " [dbg-lvish] putLV/nonidem: casIORef handlerStatus"++uniqsuf + (success, _) <- casIORef handlerStatus ticket $! + Installing n $! (ClosedPar $ body k):ps + logWith q 8 $ " [dbg-lvish] putLV/nonidem: clearPutFlag"++uniqsuf + clearPutFlag + if success then sched q else putNonidemp + + in if Queue.idemp q then putIdemp else putNonidemp + -- | Update an LVar without generating a result. putLV :: LVar a d -- ^ the LVar @@ -405,8 +437,8 @@ putLV lv doPut = putLV_ lv doPut' -- | Freeze an LVar (introducing quasi-determinism). -- It is the data structure implementor's responsibility to expose this as quasi-deterministc. freezeLV :: LVar a d -> Par () -freezeLV lv@(LVar {name, status}) = mkPar $ \k q -> do - let uniqsuf = ", lv "++(lvarDbgName lv)++" on worker "++(show$ Sched.no q) +freezeLV LVar {name, status} = mkPar $ \k q -> do + let uniqsuf = ", lv "++(lvarDbgName lv)++" on worker "++(show$ Queue.no q) logWith q 5 $ " [dbg-lvish] freezeLV: atomic modify status to Freezing"++uniqsuf oldStatus <- atomicModifyIORef status $ \s -> (Freezing, s) case oldStatus of @@ -414,7 +446,7 @@ freezeLV lv@(LVar {name, status}) = mkPar $ \k q -> do Freezing -> return () Active listeners -> do logWith q 7 $ " [dbg-lvish] freezeLV: begin busy-wait for putter status"++uniqsuf - Sched.await q (name /=) -- wait until all currently-running puts have + Queue.await q (name /=) -- wait until all currently-running puts have -- snapshotted the active status logWith q 7 $ " [dbg-lvish] freezeLV: calling each listener's onFreeze"++uniqsuf B.foreach listeners $ \Listener {onFreeze} tok -> onFreeze tok q @@ -450,38 +482,27 @@ withNewPool_ f = do f hp return hp -data DecStatus = HasDec | HasNotDec - -- | Close a @Par@ task so that it is properly registered with a handler pool. -closeInPool :: Maybe HandlerPool -> Par () -> IO ClosedPar -closeInPool Nothing c = return $ close c $ const (ClosedPar sched) -closeInPool (Just hp) c = do - decRef <- newIORef HasNotDec -- in case the thread is duplicated, ensure - -- that the counter is decremented only once - -- on termination - let cnt = numHandlers hp - - tryDecRef = do -- attempt to claim the role of decrementer - ticket <- readForCAS decRef - case peekTicket ticket of - HasDec -> return False - HasNotDec -> do - (firstToDec, _) <- casIORef decRef ticket HasDec - return firstToDec - - onFinishHandler _ = ClosedPar $ \q -> do - shouldDec <- tryDecRef -- are we the first copy of the thread to - -- terminate? - when shouldDec $ do - C.dec cnt -- record handler completion in pool - quiescent <- C.poll cnt -- check for (transient) quiescence - when quiescent $ do -- wake any threads waiting on quiescence - hpMsg q " [dbg-lvish] -> Quiescent now.. waking conts" hp - let invoke t tok = do - B.remove tok - Sched.pushWork q t - B.foreach (blockedOnQuiesce hp) invoke +closeInPool :: Maybe HandlerPool -> Bool -> Par () -> IO ClosedPar +closeInPool Nothing dedup c = return $ close c $ const (ClosedPar sched) +closeInPool (Just hp) dedup c = do + let cnt = numHandlers hp + onTerminate_ q = do + C.dec cnt -- record handler completion in pool + quiescent <- C.poll cnt -- check for (transient) quiescence + when quiescent $ do -- wake any threads waiting on quiescence + hpMsg q " [dbg-lvish] -> Quiescent now.. waking conts" hp + let invoke t tok = do + B.remove tok + Queue.pushWork q t + B.foreach (blockedOnQuiesce hp) invoke + + dedupFlag <- newDedupCheck + + let onFinishHandler _ = ClosedPar $ \q -> do + when dedup $ winnerCheck dedupFlag q (onTerminate_ q) (return ()) sched q + C.inc $ numHandlers hp -- record handler invocation in pool return $ close c onFinishHandler -- close the task with a special "done" -- continuation that clears it from the @@ -494,17 +515,42 @@ addHandler :: Maybe HandlerPool -- ^ pool to enroll in, if any -> (a -> Par ()) -- ^ initial snapshot callback on handler registration -> (d -> IO (Maybe (Par ()))) -- ^ subsequent callbacks: updates -> Par () -addHandler hp LVar {state, status} globalCB updateThresh = - let spawnWhen thresh q = do +addHandler hp LVar {state, status, handlerStatus, name} globalCB updateThresh = + let acqLock q = when (not $ Queue.idemp q) $ do + ticket <- readForCAS handlerStatus + let (newStatus, wait) = case peekTicket ticket of + Dormant -> (Installing 1 [], True) + Installing n ps -> (Installing (n+1) ps, False) + (success, _) <- casIORef handlerStatus ticket newStatus + if success + then when wait $ Queue.await q (name /=) -- first handler installation; wait + -- for existing puts to complete + else acqLock q -- retry lock acquisition + + relLock q = when (not $ Queue.idemp q) $ do + ticket <- readForCAS handlerStatus + let (newStatus, ps) = case peekTicket ticket of + Dormant -> error "BUG: acq/rel mismatch on handler lock" + Installing 1 ps -> (Dormant, ps) + Installing n ps -> (Installing (n-1) ps, []) + (success, _) <- casIORef handlerStatus ticket newStatus + if success + then forM_ ps $ Queue.pushWork q + else relLock q -- retry lock release + + spawnWhen thresh q = do tripped <- thresh whenJust tripped $ \cb -> do logWith q 5 " [dbg-lvish] addHandler: Delta threshold triggered, pushing work.." - closed <- closeInPool hp cb - Sched.pushWork q closed - onUpdate d _ q = spawnWhen (updateThresh d) q - onFreeze _ _ = return () + -- deduplicate only if we ARE assuming idempotence (since then + -- termination task might itself be duplicated) + closed <- closeInPool hp (Queue.idemp q) cb + Queue.pushWork q closed + onUpdate d _ q = spawnWhen (updateThresh d) q + onFreeze _ _ = return () in mkPar $ \k q -> do + acqLock q curStatus <- readIORef status case curStatus of Active listeners -> -- enroll the handler as a listener @@ -515,7 +561,16 @@ addHandler hp LVar {state, status} globalCB updateThresh = logWith q 4 " [dbg-lvish] addHandler: calling globalCB.." -- At registration time, traverse (globally) over the previously inserted items -- to launch any required callbacks. - exec (close (globalCB state) k) q + let k2 :: () -> ClosedPar + k2 () = case k () of + ClosedPar go -> ClosedPar $ \ q2 -> do + -- Warning! What happens if the globalCB blocks and then wakes on a different thread? + relLock q -- Release lock on original worker. + go q2 -- Continue after the addHandler. + -- Ported over bugfix here from master branch. + -- There's a quirk here where we need to stick in the lock release + -- to happen afetr the globalCB is done (in the continuation). + exec (close (globalCB state) k2) q -- | Block until a handler pool is quiescent. quiesce :: HandlerPool -> Par () @@ -566,9 +621,11 @@ freezeLVAfter lv globalCB updateCB = do -- | Fork a child thread, optionally in the context of a handler pool. forkHP :: Maybe HandlerPool -> Par () -> Par () forkHP mh child = mkPar $ \k q -> do - closed <- closeInPool mh child - Sched.pushWork q (k ()) -- "Work-first" policy. --- hpMsg q " [dbg-lvish] incremented and pushed work in forkInPool, now running cont" hp + -- deduplicate only if we ARE assuming idempotence (since then termination + -- task might itself be duplicated) + closed <- closeInPool mh (Queue.idemp q) child + Queue.pushWork q (k ()) -- "Work-first" policy. +-- hpMsg q " [dbg-lvish] incremented and pushed work in forkInPool, now running cont" hp exec closed q -- | Fork a child thread. @@ -585,25 +642,25 @@ liftIO io = mkPar $ \k q -> do -- current Par session, otherwise it will simply throw an exception. getLogger :: Par L.Logger getLogger = mkPar $ \k q -> - let Just lgr = Sched.logger q in + let Just lgr = Queue.logger q in exec (k lgr) q -- | Return the worker that we happen to be running on. (NONDETERMINISTIC.) getWorkerNum :: Par Int -getWorkerNum = mkPar $ \k q -> exec (k (Sched.no q)) q +getWorkerNum = mkPar $ \k q -> exec (k (Queue.no q)) q -- | Generate a random boolean in a core-local way. Fully nondeterministic! instance MonadToss Par where toss = mkPar $ \k q -> do - g <- readIORef $ Sched.prng q + g <- readIORef $ Queue.prng q let (b, g' ) = random g - writeIORef (Sched.prng q) g' + writeIORef (Queue.prng q) g' exec (k b) q -- | Cooperatively schedule other threads. yield :: Par () yield = mkPar $ \k q -> do - Sched.yieldWork q (k ()) + Queue.yieldWork q (k ()) sched q {-# INLINE sched #-} @@ -611,7 +668,7 @@ yield = mkPar $ \k q -> do -- completed their work and idled. sched :: SchedState -> IO () sched q = do - n <- Sched.next q + n <- Queue.next q case n of Just t -> exec t q Nothing -> return () @@ -635,12 +692,12 @@ runParDetailed :: DbgCfg -- ^ Debugging config -> Par a -- ^ The computation to run. -> IO ([String], Either E.SomeException a) runParDetailed cfg@DbgCfg{dbgRange, dbgDests, dbgScheduling } numWrkrs comp = do - (lgr,queues) <- Sched.new cfg numWrkrs noName + (lgr,queues) <- Queue.new cfg numWrkrs noName -- We create a thread on each CPU with forkOn. The CPU on which -- the current thread is running will host the main thread; the -- other CPUs will host worker threads. - main_cpu <- Sched.currentCPU + main_cpu <- Queue.currentCPU answerMV <- newEmptyMVar let grabLogs = do @@ -655,7 +712,7 @@ runParDetailed cfg@DbgCfg{dbgRange, dbgDests, dbgScheduling } numWrkrs comp = do -- Use Control.Concurrent.Async to deal with exceptions: ---------------------------------------------------------------------------------- - let runWorker :: (Int,Sched.State ClosedPar LVarID) -> IO () + let runWorker :: (Int,Queue.State ClosedPar LVarID) -> IO () runWorker (cpu, q) = do if (cpu /= main_cpu) then do logOffRecord q 3 $ " [dbg-lvish] Auxillary worker #"++show cpu++" starting." @@ -668,9 +725,8 @@ runParDetailed cfg@DbgCfg{dbgRange, dbgDests, dbgScheduling } numWrkrs comp = do -- FIXME: this continuation gets duplicated. logOffRecord q 3 " [dbg-lvish] Main worker: past global barrier, putting answer." b <- tryPutMVar answerMV x -#ifdef GET_ONCE - unless b $ error "Final continuation of Par computation was duplicated, in spite of GET_ONCE!" -#endif + when (not b && not (Queue.idemp q)) $ + error "Final continuation of Par computation was duplicated, in spite of GET_ONCE!" return () in do logOffRecord q 3 " [dbg-lvish] Main worker thread starting." exec (close comp k) q @@ -756,7 +812,7 @@ unsafeName x = unsafePerformIO $ do return (hashStableName sn) {-# INLINE hpMsg #-} -hpMsg :: Sched.State a s -> String -> HandlerPool -> IO () +hpMsg :: Queue.State a s -> String -> HandlerPool -> IO () hpMsg q msg hp = do #ifdef DEBUG_LVAR s <- hpId_ hp diff --git a/haskell/lvish/Control/LVish/SchedClass.hs b/haskell/lvish/Control/LVish/SchedClass.hs deleted file mode 100644 index 5b73f933..00000000 --- a/haskell/lvish/Control/LVish/SchedClass.hs +++ /dev/null @@ -1,194 +0,0 @@ -{-# LANGUAGE DataKinds, KindSignatures, FlexibleInstances #-} -{-# LANGUAGE CPP, NamedFieldPuns #-} - - -module Control.LVish.SchedClass where - -import Control.Monad -import Control.LVish.SchedIdempotent --- import Control.LVish.SchedIdempotentInternal -import qualified Control.LVish.SchedIdempotentInternal as Sched -import Data.IORef -import Data.Atomics - -import qualified Data.Concurrent.Bag as B - --------------------------------------------------------------------------------- - -data Idempotency = Idemp | NonIdemp - deriving Show - -newtype Par2 (idp :: Idempotency) a = Par2 (Par a) - --- | This exists solely to choose between idempotent and non-idempotent --- configurations of the `Par` monad. -class WorkSched par where - getLV :: (LVar a d) -- ^ the LVar - -> (a -> Bool -> IO (Maybe b)) -- ^ already past threshold? - -> (d -> IO (Maybe b)) -- ^ does @d@ pass the threshold? - -> par b - - -- TODO: figure out what to do with addHandler: - {- - addHandler :: Maybe HandlerPool -- ^ pool to enroll in, if any - -> LVar a d -- ^ LVar to listen to - -> (a -> IO (Maybe (Par ()))) -- ^ initial callback - -> (d -> IO (Maybe (Par ()))) -- ^ subsequent callbacks: updates - -> par () - -} - -instance WorkSched (Par2 Idemp) where - getLV = mkGetLV Idemp - -instance WorkSched (Par2 NonIdemp) where - getLV = mkGetLV NonIdemp - --- ARGH: everything overloaded on these two should have a SPECIALIZE pragma for both. - -{-# INLINE mkGetLV #-} -mkGetLV :: Idempotency -> LVar a1 d - -> (a1 -> Bool -> IO (Maybe a)) - -> (d -> IO (Maybe a)) - -> Par2 idp a -mkGetLV mode lv@(LVar {state, status}) globalThresh deltaThresh = Par2$ - mkPar $ \k q -> do - -- tradeoff: we fastpath the case where the LVar is already beyond the - -- threshhold by polling *before* enrolling the callback. The price is - -- that, if we are not currently above the threshhold, we will have to poll - -- /again/ after enrolling the callback. This race may also result in the - -- continuation being executed twice, which is permitted by idempotence. - - curStatus <- readIORef status - case curStatus of - Frozen -> do - tripped <- globalThresh state True - case tripped of - Just b -> exec (k b) q -- already past the threshold; invoke the - -- continuation immediately - Nothing -> sched q - Active listeners -> do - tripped <- globalThresh state False - case tripped of - Just b -> exec (k b) q -- already past the threshold; invoke the - -- continuation immediately - - Nothing -> do -- /transiently/ not past the threshhold; block - let unblockWhen1 thresh tok q = do - tripped <- thresh - whenJust tripped $ \b -> do - B.remove tok - Sched.pushWork q (k b) - -- Non-idempotent version. A small amount of duplicated code here: - unblockWhen2 execFlag thresh tok q = do - tripped <- thresh - whenJust tripped $ \b -> do - B.remove tok - ticket <- readForCAS execFlag - unless (peekTicket ticket) $ do - (winner, _) <- casIORef execFlag ticket True - when winner $ Sched.pushWork q (k b) - - mflg <- case mode of - Idemp -> return (error "getLV: This value should be unused") - NonIdemp -> newIORef False - - let unblock = case mode of - Idemp -> unblockWhen1 - NonIdemp -> unblockWhen2 mflg - onUpdate d = unblock $ deltaThresh d - onFreeze = unblock $ globalThresh state True - - - -- add listener, i.e., move the continuation to the waiting bag - tok <- B.put listeners $ Listener onUpdate onFreeze - - -- but there's a race: the threshold might be passed (or the LVar - -- frozen) between our check and the enrollment as a listener, so we - -- must poll again - frozen <- isFrozen lv - tripped' <- globalThresh state frozen - case tripped' of - Just b -> do - B.remove tok -- remove the listener we just added, and - exec (k b) q -- execute the continuation. this work might be - -- redundant, but by idempotence that's OK - Nothing -> sched q - - - --- getLV :: (LVar a d) -- ^ the LVar --- -> (a -> Bool -> IO (Maybe b)) -- ^ already past threshold? --- -> (d -> IO (Maybe b)) -- ^ does @d@ pass the threshold? --- -> Par b - --- getLV lv@(LVar {state, status}) globalThresh deltaThresh = mkPar $ \k q -> do --- -- tradeoff: we fastpath the case where the LVar is already beyond the --- -- threshhold by polling *before* enrolling the callback. The price is --- -- that, if we are not currently above the threshhold, we will have to poll --- -- /again/ after enrolling the callback. This race may also result in the --- -- continuation being executed twice, which is permitted by idempotence. - --- curStatus <- readIORef status --- case curStatus of --- Frozen -> do --- tripped <- globalThresh state True --- case tripped of --- Just b -> exec (k b) q -- already past the threshold; invoke the --- -- continuation immediately --- Nothing -> sched q --- Active listeners -> do --- tripped <- globalThresh state False --- case tripped of --- Just b -> exec (k b) q -- already past the threshold; invoke the --- -- continuation immediately - --- Nothing -> do -- /transiently/ not past the threshhold; block - --- #if GET_ONCE --- execFlag <- newIORef False --- #endif - --- let onUpdate d = unblockWhen $ deltaThresh d --- onFreeze = unblockWhen $ globalThresh state True - --- unblockWhen thresh tok q = do --- tripped <- thresh --- whenJust tripped $ \b -> do --- B.remove tok --- #if GET_ONCE --- ticket <- readForCAS execFlag --- unless (peekTicket ticket) $ do --- (winner, _) <- casIORef execFlag ticket True --- when winner $ Sched.pushWork q (k b) --- #else --- Sched.pushWork q (k b) --- #endif - --- -- add listener, i.e., move the continuation to the waiting bag --- tok <- B.put listeners $ Listener onUpdate onFreeze - --- -- but there's a race: the threshold might be passed (or the LVar --- -- frozen) between our check and the enrollment as a listener, so we --- -- must poll again --- frozen <- isFrozen lv --- tripped' <- globalThresh state frozen --- case tripped' of --- Just b -> do --- B.remove tok -- remove the listener we just added, and --- exec (k b) q -- execute the continuation. this work might be --- -- redundant, but by idempotence that's OK --- Nothing -> sched q - -isFrozen :: LVar a d -> IO Bool -isFrozen (LVar {status}) = do - curStatus <- readIORef status - case curStatus of - Active _ -> return False - Frozen -> return True - --- mkPar :: ((a -> ClosedPar) -> SchedState -> IO ()) -> Par a --- mkPar f = Par $ \k -> ClosedPar $ \q -> f k q - -whenJust :: Maybe a -> (a -> IO ()) -> IO () -whenJust Nothing _ = return () -whenJust (Just a) f = f a diff --git a/haskell/lvish/Control/LVish/SchedIdempotentInternal.hs b/haskell/lvish/Control/LVish/SchedQueue.hs similarity index 95% rename from haskell/lvish/Control/LVish/SchedIdempotentInternal.hs rename to haskell/lvish/Control/LVish/SchedQueue.hs index 022454bb..9fd09ec3 100644 --- a/haskell/lvish/Control/LVish/SchedIdempotentInternal.hs +++ b/haskell/lvish/Control/LVish/SchedQueue.hs @@ -3,9 +3,10 @@ {-# LANGUAGE NamedFieldPuns, BangPatterns #-} {-# LANGUAGE RecursiveDo #-} -module Control.LVish.SchedIdempotentInternal ( - State(logger, no), - new, number, next, pushWork, nullQ, yieldWork, currentCPU, setStatus, await, prng + +module Control.LVish.SchedQueue ( + State(logger, no), + new, number, idemp, next, pushWork, yieldWork, currentCPU, setStatus, await, prng ) where @@ -85,6 +86,7 @@ popOther = popMine -- All the state relevant to a single worker thread data State a s = State { no :: {-# UNPACK #-} !Int, -- ^ The number of this worker + idemp :: Bool, -- ^ are we assuming task idempotence? numWorkers :: Int, -- ^ Total number of workers in this runPar prng :: IORef StdGen, -- ^ core-local random number generation status :: IORef s, -- ^ A thread-local flag @@ -189,7 +191,13 @@ new DbgCfg{dbgDests,dbgRange,dbgScheduling} numWorkers s = do workpool <- newDeque status <- newIORef s prng <- newIORef $ mkStdGen i - return State { no = i, workpool, idle, status, states, prng, logger, numWorkers } + return State { no = i, +#ifdef LVISH_DEDUP + idemp = False, +#else + idemp = True, +#endif + workpool, idle, status, states, prng, logger, numWorkers } rec states <- forM [0..(numWorkers-1)] $ mkState states return (logger,states) diff --git a/haskell/lvish/Control/LVish/Unsafe.hs b/haskell/lvish/Control/LVish/Unsafe.hs index 8d4e820a..52d8d0db 100644 --- a/haskell/lvish/Control/LVish/Unsafe.hs +++ b/haskell/lvish/Control/LVish/Unsafe.hs @@ -7,7 +7,7 @@ module Control.LVish.Unsafe() where import Control.LVish.Internal import Control.Monad.IO.Class -import qualified Control.LVish.SchedIdempotent as L +import qualified Control.LVish.Sched as L instance MonadIO (Par d s) where liftIO = WrapPar . L.liftIO diff --git a/haskell/lvish/Control/Reagent.hs b/haskell/lvish/Control/Reagent.hs index d7cd803a..cb1c398f 100644 --- a/haskell/lvish/Control/Reagent.hs +++ b/haskell/lvish/Control/Reagent.hs @@ -39,4 +39,4 @@ postCommit :: Reagent a -> (a -> IO b) -> Reagent b postCommit r f succ fail = r (\x -> f x >>= succ) fail choice :: Reagent a -> Reagent a -> Reagent a -choice = error "TODO" \ No newline at end of file +choice = error "TODO" diff --git a/haskell/lvish/Data/Concurrent/AlignedIORef.hs b/haskell/lvish/Data/Concurrent/AlignedIORef.hs index 087f3a93..fc438ae0 100644 --- a/haskell/lvish/Data/Concurrent/AlignedIORef.hs +++ b/haskell/lvish/Data/Concurrent/AlignedIORef.hs @@ -21,4 +21,4 @@ newAlignedIORef v = do return AlignedIORef { -- padding, ref - } \ No newline at end of file + } diff --git a/haskell/lvish/Data/Concurrent/SNZI.hs b/haskell/lvish/Data/Concurrent/SNZI.hs index 28742ab7..e40eee02 100644 --- a/haskell/lvish/Data/Concurrent/SNZI.hs +++ b/haskell/lvish/Data/Concurrent/SNZI.hs @@ -106,4 +106,4 @@ newSNZI :: IO ([SNZI], IO Bool) newSNZI = do rootRef <- newAlignedIORef 0 leaves <- makeTree 1 [] [Root rootRef] - return (leaves, readIORef (ref rootRef) >>= return . (== 0)) \ No newline at end of file + return (leaves, readIORef (ref rootRef) >>= return . (== 0)) diff --git a/haskell/lvish/Data/LVar/CycGraph.hs b/haskell/lvish/Data/LVar/CycGraph.hs index 47b87e22..85a03cca 100644 --- a/haskell/lvish/Data/LVar/CycGraph.hs +++ b/haskell/lvish/Data/LVar/CycGraph.hs @@ -43,7 +43,7 @@ import Debug.Trace -- LVish: import Control.LVish import qualified Control.LVish.Internal as LV -import qualified Control.LVish.SchedIdempotent as LI +import qualified Control.LVish.Sched as LI import Data.LVar.PureSet as IS import Data.LVar.IVar as IV import qualified Data.Concurrent.SkipListMap as SLM diff --git a/haskell/lvish/Data/LVar/Generic/Internal.hs b/haskell/lvish/Data/LVar/Generic/Internal.hs index 19fcbfca..787884fc 100644 --- a/haskell/lvish/Data/LVar/Generic/Internal.hs +++ b/haskell/lvish/Data/LVar/Generic/Internal.hs @@ -24,7 +24,7 @@ module Data.LVar.Generic.Internal import Control.LVish.Types import Control.LVish.Basics import Control.LVish.Internal (Par, Determinism(..)) -import Control.LVish.SchedIdempotent (HandlerPool) +import Control.LVish.Sched (HandlerPool) import Control.LVish.DeepFrz.Internal (Frzn, Trvrsbl) import qualified Data.Foldable as F import Data.List (sort, intersperse) diff --git a/haskell/lvish/Data/LVar/IStructure.hs b/haskell/lvish/Data/LVar/IStructure.hs index f63c326c..365ff912 100644 --- a/haskell/lvish/Data/LVar/IStructure.hs +++ b/haskell/lvish/Data/LVar/IStructure.hs @@ -43,7 +43,7 @@ import Data.List (intersperse) import Control.LVish as LV hiding (put,put_,get) import Control.LVish.DeepFrz.Internal import Control.LVish.Internal as LI -import Control.LVish.SchedIdempotent (newLV, putLV, getLV, freezeLV, +import Control.LVish.Sched (newLV, putLV, getLV, freezeLV, freezeLVAfter, liftIO) import Data.LVar.Generic as G import Data.LVar.Generic.Internal (unsafeCoerceLVar) diff --git a/haskell/lvish/Data/LVar/IVar.hs b/haskell/lvish/Data/LVar/IVar.hs index 61e533ec..479b2a5a 100644 --- a/haskell/lvish/Data/LVar/IVar.hs +++ b/haskell/lvish/Data/LVar/IVar.hs @@ -55,8 +55,8 @@ import qualified Control.LVish.Basics as LV import Control.LVish.DeepFrz.Internal import qualified Control.LVish.Internal as I import Control.LVish.Internal (Par(WrapPar), LVar(WrapLVar), Determinism(QuasiDet)) -import Control.LVish.SchedIdempotent (newLV, putLV, getLV, freezeLV) -import qualified Control.LVish.SchedIdempotent as LI +import Control.LVish.Sched (newLV, putLV, getLV, freezeLV) +import qualified Control.LVish.Sched as LI import Data.LVar.Generic import Data.LVar.Generic.Internal (unsafeCoerceLVar) import GHC.Prim (unsafeCoerce#) diff --git a/haskell/lvish/Data/LVar/Internal/Pure.hs b/haskell/lvish/Data/LVar/Internal/Pure.hs index c37d0a6d..5c7238c0 100644 --- a/haskell/lvish/Data/LVar/Internal/Pure.hs +++ b/haskell/lvish/Data/LVar/Internal/Pure.hs @@ -34,7 +34,7 @@ import Control.LVish import Control.LVish.DeepFrz.Internal import Control.LVish.Internal import Data.IORef -import qualified Control.LVish.SchedIdempotent as LI +import qualified Control.LVish.Sched as LI import Algebra.Lattice import GHC.Prim (unsafeCoerce#) import System.IO.Unsafe (unsafePerformIO, unsafeDupablePerformIO) diff --git a/haskell/lvish/Data/LVar/NatArray.hs b/haskell/lvish/Data/LVar/NatArray.hs index 2cc4cdb0..bfd2444d 100644 --- a/haskell/lvish/Data/LVar/NatArray.hs +++ b/haskell/lvish/Data/LVar/NatArray.hs @@ -85,9 +85,9 @@ import Data.LVar.Generic import Control.LVish as LV hiding (addHandler, put,get) import Control.LVish.DeepFrz.Internal as DF import Control.LVish.Internal as LI -import Control.LVish.SchedIdempotent (newLV, putLV, getLV, freezeLV, +import Control.LVish.Sched (newLV, putLV, getLV, freezeLV, freezeLVAfter, liftIO) -import qualified Control.LVish.SchedIdempotent as L +import qualified Control.LVish.Sched as L import System.IO.Unsafe (unsafeDupablePerformIO) import Data.LVar.NatArray.Unsafe (NatArray(..)) diff --git a/haskell/lvish/Data/LVar/PNCounter.hs b/haskell/lvish/Data/LVar/PNCounter.hs index 791d7c71..1a82fcfb 100644 --- a/haskell/lvish/Data/LVar/PNCounter.hs +++ b/haskell/lvish/Data/LVar/PNCounter.hs @@ -27,7 +27,7 @@ import Control.LVish import Control.LVish.Internal import qualified Data.Atomics.Counter.Reference as AC -- LK: FIXME: it can't be okay to use SchedIdempotent if we're using bump, can it?! -import Control.LVish.SchedIdempotent (newLV) +-- import Control.LVish.SchedIdempotent (newLV) import Data.IORef diff --git a/haskell/lvish/Data/LVar/Pair.hs b/haskell/lvish/Data/LVar/Pair.hs index 6fc071ed..361f9e73 100644 --- a/haskell/lvish/Data/LVar/Pair.hs +++ b/haskell/lvish/Data/LVar/Pair.hs @@ -10,8 +10,8 @@ import Data.IORef import Control.Exception (throw) import Control.LVish import Control.LVish.Internal -import Control.LVish.SchedIdempotent (newLV, putLV, getLV) -import qualified Control.LVish.SchedIdempotent as L +import Control.LVish.Sched (newLV, putLV, getLV) +import qualified Control.LVish.Sched as L import Data.LVar.Generic ------------------------------------------------------------------------------ diff --git a/haskell/lvish/Data/LVar/PureMap.hs b/haskell/lvish/Data/LVar/PureMap.hs index c352669e..e902e5ca 100644 --- a/haskell/lvish/Data/LVar/PureMap.hs +++ b/haskell/lvish/Data/LVar/PureMap.hs @@ -50,8 +50,8 @@ module Data.LVar.PureMap import Control.LVish.DeepFrz.Internal import Control.LVish import Control.LVish.Internal as LI -import Control.LVish.SchedIdempotent (newLV, putLV, putLV_, getLV, freezeLV, freezeLVAfter) -import qualified Control.LVish.SchedIdempotent as L +import Control.LVish.Sched (newLV, putLV, putLV_, getLV, freezeLV, freezeLVAfter) +import qualified Control.LVish.Sched as L import qualified Data.LVar.IVar as IV import Data.LVar.Generic as G import Data.LVar.PureMap.Unsafe diff --git a/haskell/lvish/Data/LVar/PureMap/Unsafe.hs b/haskell/lvish/Data/LVar/PureMap/Unsafe.hs index 8b68ea47..85fe71d7 100644 --- a/haskell/lvish/Data/LVar/PureMap/Unsafe.hs +++ b/haskell/lvish/Data/LVar/PureMap/Unsafe.hs @@ -19,8 +19,8 @@ module Data.LVar.PureMap.Unsafe import Control.LVish.DeepFrz.Internal import Control.LVish import Control.LVish.Internal as LI -import Control.LVish.SchedIdempotent (freezeLV) -import qualified Control.LVish.SchedIdempotent as L +import Control.LVish.Sched (freezeLV) +import qualified Control.LVish.Sched as L import Data.LVar.Generic as G import Data.LVar.Generic.Internal (unsafeCoerceLVar) import Data.UtilInternal (traverseWithKey_) diff --git a/haskell/lvish/Data/LVar/PureSet.hs b/haskell/lvish/Data/LVar/PureSet.hs index bb823cab..7295f218 100644 --- a/haskell/lvish/Data/LVar/PureSet.hs +++ b/haskell/lvish/Data/LVar/PureSet.hs @@ -56,8 +56,8 @@ import Data.LVar.Generic.Internal (unsafeCoerceLVar) import Control.LVish as LV import Control.LVish.DeepFrz.Internal import Control.LVish.Internal as LI -import Control.LVish.SchedIdempotent (newLV, putLV, getLV, freezeLV, freezeLVAfter) -import qualified Control.LVish.SchedIdempotent as L +import Control.LVish.Sched (newLV, putLV, getLV, freezeLV, freezeLVAfter) +import qualified Control.LVish.Sched as L import System.IO.Unsafe (unsafeDupablePerformIO) import Prelude hiding (insert) diff --git a/haskell/lvish/Data/LVar/SLMap.hs b/haskell/lvish/Data/LVar/SLMap.hs index c0c3e445..994995b5 100644 --- a/haskell/lvish/Data/LVar/SLMap.hs +++ b/haskell/lvish/Data/LVar/SLMap.hs @@ -68,8 +68,9 @@ import Control.Monad.IO.Class import Control.LVish import Control.LVish.DeepFrz.Internal import Control.LVish.Internal as LI -import Control.LVish.SchedIdempotent (newLV, putLV, putLV_, getLV, freezeLV) -import qualified Control.LVish.SchedIdempotent as L +import Control.LVish.Sched (newLV, putLV, putLV_, getLV, freezeLV) +import qualified Control.LVish.Sched as L +import System.Random (randomIO) import System.IO.Unsafe (unsafeDupablePerformIO) import GHC.Prim (unsafeCoerce#) import Prelude diff --git a/haskell/lvish/Data/LVar/SLSet.hs b/haskell/lvish/Data/LVar/SLSet.hs index 57359a24..dff22d3e 100644 --- a/haskell/lvish/Data/LVar/SLSet.hs +++ b/haskell/lvish/Data/LVar/SLSet.hs @@ -58,8 +58,8 @@ import Control.Monad import Control.LVish as LV import Control.LVish.DeepFrz.Internal import Control.LVish.Internal as LI -import Control.LVish.SchedIdempotent (newLV, putLV, getLV, freezeLV) -import qualified Control.LVish.SchedIdempotent as L +import Control.LVish.Sched (newLV, putLV, getLV, freezeLV) +import qualified Control.LVish.Sched as L import System.IO.Unsafe (unsafeDupablePerformIO) import Prelude hiding (insert) diff --git a/haskell/lvish/Experimental/BitArray.hs b/haskell/lvish/Experimental/BitArray.hs index fa5becc1..445c6e32 100644 --- a/haskell/lvish/Experimental/BitArray.hs +++ b/haskell/lvish/Experimental/BitArray.hs @@ -61,9 +61,9 @@ import qualified Data.Traversable as T import Control.LVish as LV hiding (addHandler) import Control.LVish.Internal as LI -import Control.LVish.SchedIdempotent (newLV, putLV, getLV, freezeLV, +import Control.LVish.Sched (newLV, putLV, getLV, freezeLV, freezeLVAfter, liftIO) -import qualified Control.LVish.SchedIdempotent as L +import qualified Control.LVish.Sched as L ------------------------------------------------------------------------------ diff --git a/haskell/lvish/lvish.cabal b/haskell/lvish/lvish.cabal index 22b3e844..cbdf59e6 100644 --- a/haskell/lvish/lvish.cabal +++ b/haskell/lvish/lvish.cabal @@ -68,10 +68,9 @@ flag debug flag chaselev description: Use the Chase-Lev work-stealing deque default: False - manual: True - -flag getonce - description: Ensure that continuations of get run at most once + +flag dedup + description: Ensure that both handlers and continuations of get run at most once (by using extra synchronization) default: False manual: True @@ -150,8 +149,8 @@ library Data.Concurrent.LinkedMap Data.Concurrent.AlignedIORef Control.Reagent - Control.LVish.SchedIdempotent - Control.LVish.SchedIdempotentInternal + Control.LVish.Sched + Control.LVish.SchedQueue Control.LVish.MonadToss Control.LVish.Types Control.LVish.Basics @@ -190,8 +189,8 @@ library if flag(chaselev) build-depends: chaselev-deque cpp-options: -DCHASE_LEV - if flag(getonce) - cpp-options: -DGET_ONCE + if flag(dedup) + cpp-options: -DLVISH_DEDUP -------------------------------------------------------------------------------- @@ -248,11 +247,10 @@ test-suite test-lvish if flag(chaselev) build-depends: chaselev-deque cpp-options: -DCHASE_LEV - if flag(getonce) - cpp-options: -DGET_ONCE + if flag(dedup) + cpp-options: -DLVISH_DEDUP -- Atomic-primops fails when used by template-haskell/ghci on linux: if impl(ghc < 7.7) && os(linux) { buildable: False } - diff --git a/haskell/lvish/tests/ArrayTests.hs b/haskell/lvish/tests/ArrayTests.hs index 1870556d..14279891 100644 --- a/haskell/lvish/tests/ArrayTests.hs +++ b/haskell/lvish/tests/ArrayTests.hs @@ -59,7 +59,7 @@ import qualified Data.LVar.Pair as IP import Control.LVish import Control.LVish.DeepFrz (DeepFrz(..), Frzn, Trvrsbl, runParThenFreeze, runParThenFreezeIO) import qualified Control.LVish.Internal as I -import Control.LVish.SchedIdempotent (liftIO, dbgLvl, forkWithExceptions) +import Control.LVish.Sched (liftIO, dbgLvl, forkWithExceptions) import Debug.Trace import TestHelpers as T diff --git a/haskell/lvish/tests/LVishAndIVar.hs b/haskell/lvish/tests/LVishAndIVar.hs index e133dfb7..a54ba181 100644 --- a/haskell/lvish/tests/LVishAndIVar.hs +++ b/haskell/lvish/tests/LVishAndIVar.hs @@ -45,8 +45,8 @@ import qualified Data.LVar.IVar as IV import Control.LVish import Control.LVish.DeepFrz (DeepFrz(..), Frzn, Trvrsbl, runParThenFreeze, runParThenFreezeIO) import qualified Control.LVish.Internal as I -import Control.LVish.SchedIdempotent (liftIO, dbgLvl, forkWithExceptions) -import qualified Control.LVish.SchedIdempotent as L +import Control.LVish.Sched (liftIO, dbgLvl, forkWithExceptions) +import qualified Control.LVish.Sched as L import TestHelpers2 as T diff --git a/haskell/lvish/tests/SNZITests.hs b/haskell/lvish/tests/SNZITests.hs index 03ae5206..0f704c0f 100644 --- a/haskell/lvish/tests/SNZITests.hs +++ b/haskell/lvish/tests/SNZITests.hs @@ -54,8 +54,8 @@ import qualified Data.LVar.Pair as IP import Control.LVish import Control.LVish.DeepFrz (DeepFrz(..), Frzn, Trvrsbl, runParThenFreeze, runParThenFreezeIO) import qualified Control.LVish.Internal as I -import Control.LVish.SchedIdempotent (liftIO, dbgLvl, forkWithExceptions) -import qualified Control.LVish.SchedIdempotent as L +import Control.LVish.Sched (liftIO, dbgLvl, forkWithExceptions) +import qualified Control.LVish.Sched as L import qualified Data.Concurrent.SNZI as SNZI import qualified Data.Concurrent.LinkedMap as LM diff --git a/haskell/lvish/tests/SkipListTests.hs b/haskell/lvish/tests/SkipListTests.hs index ca96da65..255a62c9 100644 --- a/haskell/lvish/tests/SkipListTests.hs +++ b/haskell/lvish/tests/SkipListTests.hs @@ -22,7 +22,7 @@ import GHC.Conc import Data.Word import Data.IORef import System.Random (random, mkStdGen) -import Control.LVish.SchedIdempotent (liftIO, dbgLvl, forkWithExceptions) +import Control.LVish.Sched (liftIO, dbgLvl, forkWithExceptions) -- import Control.LVish (logDbgLn_) import qualified Data.Concurrent.LinkedMap as LM import qualified Data.Concurrent.SkipListMap as SLM