summaryrefslogtreecommitdiff
path: root/testsuite/tests/concurrent/should_run
diff options
context:
space:
mode:
authorDavid Terei <davidterei@gmail.com>2011-07-20 11:09:03 -0700
committerDavid Terei <davidterei@gmail.com>2011-07-20 11:26:35 -0700
commit16514f272fb42af6e9c7674a9bd6c9dce369231f (patch)
treee4f332b45fe65e2a7a2451be5674f887b42bf199 /testsuite/tests/concurrent/should_run
parentebd422aed41048476aa61dd4c520d43becd78682 (diff)
downloadhaskell-16514f272fb42af6e9c7674a9bd6c9dce369231f.tar.gz
Move tests from tests/ghc-regress/* to just tests/*
Diffstat (limited to 'testsuite/tests/concurrent/should_run')
-rw-r--r--testsuite/tests/concurrent/should_run/1980.hs13
-rw-r--r--testsuite/tests/concurrent/should_run/2910.hs9
-rw-r--r--testsuite/tests/concurrent/should_run/2910.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/2910a.hs9
-rw-r--r--testsuite/tests/concurrent/should_run/2910a.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/3279.hs25
-rw-r--r--testsuite/tests/concurrent/should_run/3279.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/3429.hs22
-rw-r--r--testsuite/tests/concurrent/should_run/3429.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/4030.hs8
-rw-r--r--testsuite/tests/concurrent/should_run/4030.stderr1
-rw-r--r--testsuite/tests/concurrent/should_run/4262.hs27
-rw-r--r--testsuite/tests/concurrent/should_run/4262.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/4811.hs14
-rw-r--r--testsuite/tests/concurrent/should_run/4813.hs12
-rw-r--r--testsuite/tests/concurrent/should_run/Makefile6
-rw-r--r--testsuite/tests/concurrent/should_run/all.T200
-rw-r--r--testsuite/tests/concurrent/should_run/allowinterrupt001.hs13
-rw-r--r--testsuite/tests/concurrent/should_run/async001.hs19
-rw-r--r--testsuite/tests/concurrent/should_run/async001.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc001.hs15
-rw-r--r--testsuite/tests/concurrent/should_run/conc001.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc002.hs14
-rw-r--r--testsuite/tests/concurrent/should_run/conc002.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc003.hs28
-rw-r--r--testsuite/tests/concurrent/should_run/conc003.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc004.hs19
-rw-r--r--testsuite/tests/concurrent/should_run/conc004.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc006.hs23
-rw-r--r--testsuite/tests/concurrent/should_run/conc006.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc007.hs23
-rw-r--r--testsuite/tests/concurrent/should_run/conc007.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc008.hs12
-rw-r--r--testsuite/tests/concurrent/should_run/conc008.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc009.hs9
-rw-r--r--testsuite/tests/concurrent/should_run/conc009.stderr1
-rw-r--r--testsuite/tests/concurrent/should_run/conc010.hs28
-rw-r--r--testsuite/tests/concurrent/should_run/conc010.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc012.hs23
-rw-r--r--testsuite/tests/concurrent/should_run/conc012.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc013.hs10
-rw-r--r--testsuite/tests/concurrent/should_run/conc013.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc014.hs27
-rw-r--r--testsuite/tests/concurrent/should_run/conc014.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/conc015.hs44
-rw-r--r--testsuite/tests/concurrent/should_run/conc015.stdout5
-rw-r--r--testsuite/tests/concurrent/should_run/conc015a.hs47
-rw-r--r--testsuite/tests/concurrent/should_run/conc015a.stdout5
-rw-r--r--testsuite/tests/concurrent/should_run/conc016.hs27
-rw-r--r--testsuite/tests/concurrent/should_run/conc016.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc017.hs45
-rw-r--r--testsuite/tests/concurrent/should_run/conc017.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/conc017a.hs44
-rw-r--r--testsuite/tests/concurrent/should_run/conc017a.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/conc018.hs26
-rw-r--r--testsuite/tests/concurrent/should_run/conc018.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc019.hs14
-rw-r--r--testsuite/tests/concurrent/should_run/conc019.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc020.hs10
-rw-r--r--testsuite/tests/concurrent/should_run/conc020.stderr1
-rw-r--r--testsuite/tests/concurrent/should_run/conc021.hs11
-rw-r--r--testsuite/tests/concurrent/should_run/conc021.stderr1
-rw-r--r--testsuite/tests/concurrent/should_run/conc022.hs40
-rw-r--r--testsuite/tests/concurrent/should_run/conc022.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/conc023.hs23
-rw-r--r--testsuite/tests/concurrent/should_run/conc024.hs15
-rw-r--r--testsuite/tests/concurrent/should_run/conc024.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc025.hs16
-rw-r--r--testsuite/tests/concurrent/should_run/conc025.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc026.hs8
-rw-r--r--testsuite/tests/concurrent/should_run/conc027.hs9
-rw-r--r--testsuite/tests/concurrent/should_run/conc028.hs11
-rw-r--r--testsuite/tests/concurrent/should_run/conc028.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/conc029.hs11
-rw-r--r--testsuite/tests/concurrent/should_run/conc029.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc030.hs15
-rw-r--r--testsuite/tests/concurrent/should_run/conc030.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc031.hs30
-rw-r--r--testsuite/tests/concurrent/should_run/conc031.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/conc032.hs74
-rw-r--r--testsuite/tests/concurrent/should_run/conc032.stdout9
-rw-r--r--testsuite/tests/concurrent/should_run/conc033.hs10
-rw-r--r--testsuite/tests/concurrent/should_run/conc033.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc034.hs31
-rw-r--r--testsuite/tests/concurrent/should_run/conc034.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc035.hs49
-rw-r--r--testsuite/tests/concurrent/should_run/conc035.stdout5
-rw-r--r--testsuite/tests/concurrent/should_run/conc036.hs35
-rw-r--r--testsuite/tests/concurrent/should_run/conc036.stdout4
-rw-r--r--testsuite/tests/concurrent/should_run/conc037.hs27
-rw-r--r--testsuite/tests/concurrent/should_run/conc037.stdout6
-rw-r--r--testsuite/tests/concurrent/should_run/conc038.hs37
-rw-r--r--testsuite/tests/concurrent/should_run/conc038.stdout7
-rw-r--r--testsuite/tests/concurrent/should_run/conc039.hs31
-rw-r--r--testsuite/tests/concurrent/should_run/conc040.hs28
-rw-r--r--testsuite/tests/concurrent/should_run/conc040.stderr1
-rw-r--r--testsuite/tests/concurrent/should_run/conc041.hs9
-rw-r--r--testsuite/tests/concurrent/should_run/conc041.stderr0
-rw-r--r--testsuite/tests/concurrent/should_run/conc041.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/conc042.hs11
-rw-r--r--testsuite/tests/concurrent/should_run/conc042.stderr0
-rw-r--r--testsuite/tests/concurrent/should_run/conc042.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/conc043.hs13
-rw-r--r--testsuite/tests/concurrent/should_run/conc043.stderr0
-rw-r--r--testsuite/tests/concurrent/should_run/conc043.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/conc044.hs13
-rw-r--r--testsuite/tests/concurrent/should_run/conc044.stderr0
-rw-r--r--testsuite/tests/concurrent/should_run/conc044.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/conc045.hs39
-rw-r--r--testsuite/tests/concurrent/should_run/conc045.stderr0
-rw-r--r--testsuite/tests/concurrent/should_run/conc045.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/conc051.hs32
-rw-r--r--testsuite/tests/concurrent/should_run/conc058.hs13
-rw-r--r--testsuite/tests/concurrent/should_run/conc058.stderr1
-rw-r--r--testsuite/tests/concurrent/should_run/conc059.hs26
-rw-r--r--testsuite/tests/concurrent/should_run/conc059.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/conc059_c.c30
-rw-r--r--testsuite/tests/concurrent/should_run/conc064.hs30
-rw-r--r--testsuite/tests/concurrent/should_run/conc064.stderr1
-rw-r--r--testsuite/tests/concurrent/should_run/conc065.hs13
-rw-r--r--testsuite/tests/concurrent/should_run/conc066.hs13
-rw-r--r--testsuite/tests/concurrent/should_run/conc067.hs16
-rw-r--r--testsuite/tests/concurrent/should_run/conc068.hs14
-rw-r--r--testsuite/tests/concurrent/should_run/conc068.stderr1
-rw-r--r--testsuite/tests/concurrent/should_run/conc069.hs19
-rw-r--r--testsuite/tests/concurrent/should_run/conc069.stdout4
-rw-r--r--testsuite/tests/concurrent/should_run/conc069a.hs19
-rw-r--r--testsuite/tests/concurrent/should_run/conc069a.stdout4
-rw-r--r--testsuite/tests/concurrent/should_run/conc070.hs18
-rw-r--r--testsuite/tests/concurrent/should_run/conc070.stdout1
-rw-r--r--testsuite/tests/concurrent/should_run/conc071.hs11
-rw-r--r--testsuite/tests/concurrent/should_run/conc071.stdout3
-rw-r--r--testsuite/tests/concurrent/should_run/conc072.hs9
-rw-r--r--testsuite/tests/concurrent/should_run/conc072.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/foreignInterruptible.hs32
-rw-r--r--testsuite/tests/concurrent/should_run/foreignInterruptible.stdout5
-rw-r--r--testsuite/tests/concurrent/should_run/mask001.hs70
-rw-r--r--testsuite/tests/concurrent/should_run/mask002.hs32
-rw-r--r--testsuite/tests/concurrent/should_run/mask002.stdout2
-rw-r--r--testsuite/tests/concurrent/should_run/numsparks001.hs11
-rw-r--r--testsuite/tests/concurrent/should_run/numsparks001.stdout5
-rw-r--r--testsuite/tests/concurrent/should_run/throwto001.hs38
-rw-r--r--testsuite/tests/concurrent/should_run/throwto002.hs25
-rw-r--r--testsuite/tests/concurrent/should_run/throwto003.hs17
144 files changed, 2075 insertions, 0 deletions
diff --git a/testsuite/tests/concurrent/should_run/1980.hs b/testsuite/tests/concurrent/should_run/1980.hs
new file mode 100644
index 0000000000..61fcd9d15b
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/1980.hs
@@ -0,0 +1,13 @@
+import Control.Exception
+import Control.Concurrent
+
+main = do
+ thr <- myThreadId
+ evaluate $ increase_stack 1000
+ throwTo thr ThreadKilled
+ `Control.Exception.catch` (\e -> case e of
+ ThreadKilled -> return ()
+ _ -> throw e)
+ where
+ increase_stack 0 = 1
+ increase_stack n = increase_stack (n-1) + n
diff --git a/testsuite/tests/concurrent/should_run/2910.hs b/testsuite/tests/concurrent/should_run/2910.hs
new file mode 100644
index 0000000000..2867008159
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/2910.hs
@@ -0,0 +1,9 @@
+import Control.Exception
+import GHC.Conc
+
+main = do
+ t1 <- block $ forkIO yield
+ t2 <- forkIO $ killThread t1
+ threadDelay 100000
+ threadStatus t1 >>= print
+ threadStatus t2 >>= print
diff --git a/testsuite/tests/concurrent/should_run/2910.stdout b/testsuite/tests/concurrent/should_run/2910.stdout
new file mode 100644
index 0000000000..145fced527
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/2910.stdout
@@ -0,0 +1,2 @@
+ThreadFinished
+ThreadFinished
diff --git a/testsuite/tests/concurrent/should_run/2910a.hs b/testsuite/tests/concurrent/should_run/2910a.hs
new file mode 100644
index 0000000000..380c15467d
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/2910a.hs
@@ -0,0 +1,9 @@
+import Control.Exception
+import GHC.Conc
+
+main = do
+ t1 <- mask_ $ forkIO yield
+ t2 <- forkIO $ killThread t1
+ threadDelay 100000
+ threadStatus t1 >>= print
+ threadStatus t2 >>= print
diff --git a/testsuite/tests/concurrent/should_run/2910a.stdout b/testsuite/tests/concurrent/should_run/2910a.stdout
new file mode 100644
index 0000000000..145fced527
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/2910a.stdout
@@ -0,0 +1,2 @@
+ThreadFinished
+ThreadFinished
diff --git a/testsuite/tests/concurrent/should_run/3279.hs b/testsuite/tests/concurrent/should_run/3279.hs
new file mode 100644
index 0000000000..279895f444
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/3279.hs
@@ -0,0 +1,25 @@
+-- test for #3279
+
+import System.IO.Unsafe
+import GHC.Conc
+import Control.Exception
+import Prelude hiding (catch)
+
+f :: Int
+f = (1 +) . unsafePerformIO $ do
+ error "foo" `catch` \(SomeException e) -> do
+ myThreadId >>= flip throwTo e
+ -- point X
+ unblock $ return 1
+
+main :: IO ()
+main = do
+ evaluate f `catch` \(SomeException e) -> return 0
+ -- the evaluation of 'x' is now suspended at point X
+ tid <- block $ forkIO (evaluate f >> return ())
+ killThread tid
+ -- now execute the 'unblock' above with a pending exception
+ yield
+ -- should print 1 + 1 = 2
+ print f
+
diff --git a/testsuite/tests/concurrent/should_run/3279.stdout b/testsuite/tests/concurrent/should_run/3279.stdout
new file mode 100644
index 0000000000..0cfbf08886
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/3279.stdout
@@ -0,0 +1 @@
+2
diff --git a/testsuite/tests/concurrent/should_run/3429.hs b/testsuite/tests/concurrent/should_run/3429.hs
new file mode 100644
index 0000000000..8b12a8b1ff
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/3429.hs
@@ -0,0 +1,22 @@
+import Control.Monad
+import Control.Concurrent
+import Control.Concurrent.MVar
+import Control.Exception
+import System.IO
+
+main :: IO ()
+main = do hSetBuffering stdout NoBuffering
+ replicateM_ 1000 doit
+
+doit :: IO ()
+doit = do v <- newMVar ()
+ t <- forkIO (foo v)
+ threadDelay 1000
+ killThread t
+ takeMVar v
+ putChar '.'
+
+foo :: MVar () -> IO ()
+foo v = do let loop = do withMVar v $ \x -> evaluate x
+ loop
+ loop
diff --git a/testsuite/tests/concurrent/should_run/3429.stdout b/testsuite/tests/concurrent/should_run/3429.stdout
new file mode 100644
index 0000000000..ad88db8c31
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/3429.stdout
@@ -0,0 +1 @@
+........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................ \ No newline at end of file
diff --git a/testsuite/tests/concurrent/should_run/4030.hs b/testsuite/tests/concurrent/should_run/4030.hs
new file mode 100644
index 0000000000..1993bad86b
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/4030.hs
@@ -0,0 +1,8 @@
+module Main where
+
+import Control.Concurrent ( forkIO, killThread )
+import Control.Exception ( block )
+
+main :: IO ()
+main = do tid <- block $ forkIO $ let x = x in x
+ killThread tid
diff --git a/testsuite/tests/concurrent/should_run/4030.stderr b/testsuite/tests/concurrent/should_run/4030.stderr
new file mode 100644
index 0000000000..0e2a7bfc12
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/4030.stderr
@@ -0,0 +1 @@
+4030: <<loop>>
diff --git a/testsuite/tests/concurrent/should_run/4262.hs b/testsuite/tests/concurrent/should_run/4262.hs
new file mode 100644
index 0000000000..e114b558a6
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/4262.hs
@@ -0,0 +1,27 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+module Main where
+
+-- Tests that superfluous worker threads are discarded rather than
+-- being kept around by the RTS.
+
+import Control.Concurrent
+import Control.Monad
+import Foreign.C.Types
+import System.Mem
+import System.Posix.Process
+import System.Directory
+import Control.Concurrent.QSem
+
+foreign import ccall safe sleep :: CUInt -> IO ()
+
+main = do
+ let amount = 200
+ qsem <- newQSem 0
+ replicateM_ amount . forkIO $ (sleep 2 >> signalQSem qsem)
+ replicateM_ amount $ waitQSem qsem
+ -- POSIX only: check thread usage manually
+ pid <- getProcessID
+ let dir = "/proc/" ++ show pid ++ "/task"
+ contents <- getDirectoryContents dir
+ let status = length contents - 2 -- . and ..
+ print status
diff --git a/testsuite/tests/concurrent/should_run/4262.stdout b/testsuite/tests/concurrent/should_run/4262.stdout
new file mode 100644
index 0000000000..45a4fb75db
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/4262.stdout
@@ -0,0 +1 @@
+8
diff --git a/testsuite/tests/concurrent/should_run/4811.hs b/testsuite/tests/concurrent/should_run/4811.hs
new file mode 100644
index 0000000000..5aad0a51df
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/4811.hs
@@ -0,0 +1,14 @@
+import Control.Concurrent
+import Control.Monad
+
+-- tests for a bug where throwTo targets a thread just created by
+-- forkOn, which is still in the process of migrating to another CPU (#4811)
+
+main = do
+ m <- newEmptyMVar
+ forkOn 0 $ do
+ replicateM_ 1000 $ do
+ t <- forkOn 1 $ return ()
+ killThread t
+ putMVar m ()
+ takeMVar m
diff --git a/testsuite/tests/concurrent/should_run/4813.hs b/testsuite/tests/concurrent/should_run/4813.hs
new file mode 100644
index 0000000000..db3a9778c6
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/4813.hs
@@ -0,0 +1,12 @@
+import Control.Concurrent
+import Control.Monad
+import Control.Exception
+import System.Mem
+
+-- caused an assertion failure with -debug in 7.0.1 (#4813)
+
+main = do
+ m <- newEmptyMVar
+ ts <- replicateM 100 $ mask_ $ forkIO $ threadDelay 100000; putMVar m ()
+ mapM_ killThread (reverse (init ts))
+ takeMVar m
diff --git a/testsuite/tests/concurrent/should_run/Makefile b/testsuite/tests/concurrent/should_run/Makefile
new file mode 100644
index 0000000000..c6bef49619
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/Makefile
@@ -0,0 +1,6 @@
+TOP=../../..
+include $(TOP)/mk/boilerplate.mk
+include $(TOP)/mk/test.mk
+
+conc059_setup :
+ '$(TEST_HC)' $(TEST_HC_OPTS) -c conc059.hs
diff --git a/testsuite/tests/concurrent/should_run/all.T b/testsuite/tests/concurrent/should_run/all.T
new file mode 100644
index 0000000000..cdcbd6da68
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/all.T
@@ -0,0 +1,200 @@
+# -----------------------------------------------------------------------------
+# These tests we do even for 'make fast'
+
+test('conc003', normal, compile_and_run, [''])
+test('conc006', normal, compile_and_run, [''])
+test('conc027', normal, compile_and_run, [''])
+test('conc051', normal, compile_and_run, [''])
+
+if ('threaded1' in config.run_ways):
+ only_threaded_ways = only_ways(['ghci','threaded1','threaded2'])
+else:
+ only_threaded_ways = skip
+
+test('conc069', only_threaded_ways, compile_and_run, [''])
+test('conc069a', only_threaded_ways, compile_and_run, [''])
+# this test gives slightly different results for non-threaded ways, so omit
+# those for now.
+test('conc070', only_threaded_ways, compile_and_run, [''])
+
+test('conc071', omit_ways(['threaded2']), compile_and_run, [''])
+test('conc072', only_ways(['threaded2']), compile_and_run, [''])
+
+test('1980', normal, compile_and_run, [''])
+test('2910', normal, compile_and_run, [''])
+test('2910a', normal, compile_and_run, [''])
+test('3279', normal, compile_and_run, [''])
+
+# This test takes a long time with the default context switch interval
+test('3429', extra_run_opts('+RTS -i0.001 -RTS'), compile_and_run, [''])
+
+# without -O, goes into an infinite loop
+# GHCi cannot deterct the infinite loop, because the thread is always reachable
+# (see also conc033 and others). We should really fix this.
+test('4030', omit_ways('ghci'), compile_and_run, ['-O'])
+
+# each of these runs for about a second
+test('throwto001', [reqlib('random'), extra_run_opts('1000 2000')],
+ compile_and_run, [''])
+test('throwto002', [reqlib('random'), ignore_output], compile_and_run, [''])
+test('throwto003', normal, compile_and_run, [''])
+
+test('mask001', normal, compile_and_run, [''])
+# ghci does not generate the BlockedIndefinitely exceptions, so omit:
+test('mask002', omit_ways(['ghci']), compile_and_run, [''])
+
+test('async001', normal, compile_and_run, [''])
+
+test('numsparks001', only_ways(['threaded1']), compile_and_run, [''])
+
+test('4262', [ skip, # skip for now, it doesn't give reliable results
+ only_ways(['threaded1']),
+ unless_os('linux',skip),
+ if_compiler_lt('ghc', '7.1', expect_fail) ],
+ compile_and_run, [''])
+
+test('4813', normal, compile_and_run, [''])
+test('4811', normal, compile_and_run, [''])
+
+test('allowinterrupt001', normal, compile_and_run, [''])
+
+# -----------------------------------------------------------------------------
+# These tests we only do for a full run
+
+def f( opts ):
+ if config.fast:
+ opts.skip = 1
+
+setTestOpts(f)
+
+test('conc001', normal, compile_and_run, [''])
+test('conc002', normal, compile_and_run, [''])
+
+# Omit GHCi way - it blows up to 0.5G. Something to do with the threaded RTS?
+test('conc004', omit_ways(['ghci']), compile_and_run, [''])
+
+test('conc007', compose(only_compiler_types(['ghc']),
+ extra_run_opts('+RTS -H128M -RTS')),
+ compile_and_run, [''])
+test('conc008', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc009', compose(only_compiler_types(['ghc']), exit_code(1)),
+ compile_and_run, [''])
+test('conc010', only_compiler_types(['ghc']), compile_and_run, [''])
+
+# conc012(ghci) needs a smaller stack, or it takes forever
+test('conc012', normal, compile_and_run, ['+RTS -K8m -RTS'])
+
+test('conc013', only_compiler_types(['ghc']), compile_and_run, [''])
+
+test('conc014', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc015', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc015a', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc016', [ omit_ways(['threaded2']), # see comment in conc016.hs
+ only_compiler_types(['ghc']) ], compile_and_run, [''])
+test('conc017', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc017a', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc018', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc019', compose(only_compiler_types(['ghc']),
+ extra_run_opts('+RTS -K16m -RTS')),
+ compile_and_run, [''])
+test('conc020', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc021', compose(omit_ways(['ghci']), exit_code(1)),
+ compile_and_run, [''])
+test('conc022', only_compiler_types(['ghc']), compile_and_run, [''])
+
+# On Windows, the non-threaded RTS creates a real OS thread for each
+# threadDelay. conc023 creates 5000 concurrent threadDelays, and the
+# resulting creation of OS threads seems to cause the system to run
+# out of memory sometimes (I'm not sure exactly how/why this happens,
+# but the threaded RTS fixes it). See #1197.
+if config.platform == 'i386-unknown-mingw32':
+ conc023_ways = only_ways(['threaded1','threaded2'])
+else:
+ conc023_ways = normal
+
+test('conc023', composes([skip_if_fast,
+ only_compiler_types(['ghc']),
+ conc023_ways]), compile_and_run, [''])
+
+test('conc024', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc025', normal, compile_and_run, [''])
+test('conc026', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc028', normal, compile_and_run, [''])
+test('conc029', normal, compile_and_run, [''])
+test('conc030', compose(only_compiler_types(['ghc']),
+ extra_run_opts('+RTS -K4M -RTS')),
+ compile_and_run, [''])
+
+test('conc031', normal, compile_and_run, [''])
+
+test('conc032', only_compiler_types(['ghc']), compile_and_run, [''])
+
+# Omit for GHCi, because it just sits there waiting for you to press ^C
+test('conc033', omit_ways(['ghci']), compile_and_run, [''])
+
+# Omit for GHCi, because it just sits there waiting for you to press ^C
+test('conc034', compose(only_compiler_types(['ghc']),
+ compose(omit_ways(['ghci']),
+ extra_run_opts('+RTS -C0 -RTS'))),
+ compile_and_run, [''])
+
+test('conc035', only_compiler_types(['ghc']), compile_and_run, [''])
+
+# Omit for GHCi: firstly GHCi doesn't have unsafe FFI calls, and secondly
+# the main thread cannot receive the deadlock exception because it can be
+# woken up by ^C.
+# Omit for threaded2: this test is really bogus and fails to do anything
+# sensible for more than one CPU.
+test('conc036', compose(skip_if_fast,
+ compose(omit_ways(['ghci','threaded2']),
+ only_compiler_types(['ghc']))), compile_and_run, [''])
+# Interrupting foreign calls only makes sense if we are threaded
+test('foreignInterruptible', composes([skip_if_fast,
+ only_threaded_ways,
+ only_compiler_types(['ghc'])]), compile_and_run, [''])
+
+test('conc037', only_ways(['threaded1','threaded2']), compile_and_run, [''])
+test('conc038', only_ways(['threaded1','threaded2']), compile_and_run, [''])
+
+# Omit for GHCi, uses foreign export
+# Omit for the threaded ways, because in this case the main thread is allowed to
+# complete, which causes the child thread to be interrupted.
+test('conc039', omit_ways(['ghci','threaded1','threaded2','profthreaded']), compile_and_run, [''])
+
+# Omit for GHCi, uses foreign export
+test('conc040', compose(only_compiler_types(['ghc']),
+ compose(exit_code(1),
+ omit_ways(['ghci']))),
+ compile_and_run, [''])
+
+# STM-related tests.
+test('conc041', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc042', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc043', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc044', only_compiler_types(['ghc']), compile_and_run, [''])
+test('conc045', only_compiler_types(['ghc']), compile_and_run, [''])
+
+test('conc058', only_compiler_types(['ghc']), compile_and_run, [''])
+
+test('conc059',
+ [only_compiler_types(['ghc']),
+ only_ways(['threaded1','threaded2']),
+ compile_cmd_prefix('$MAKE conc059_setup && '),
+ extra_clean(['conc059_c.o'])],
+ compile_and_run,
+ ['conc059_c.c -no-hs-main'])
+
+# This test sometimes just exits successfully
+# when run the threaded2 way. The problem hasn't been diagnosed yet
+test('conc064',
+ exit_code(1),
+ compile_and_run, [''])
+
+test('conc065', ignore_output, compile_and_run, [''])
+test('conc066', ignore_output, compile_and_run, [''])
+test('conc067', ignore_output, compile_and_run, [''])
+
+# omit threaded2, the behaviour of this test is non-deterministic with more
+# than one CPU.
+test('conc068', [ omit_ways('threaded2'), exit_code(1) ], compile_and_run, [''])
+
diff --git a/testsuite/tests/concurrent/should_run/allowinterrupt001.hs b/testsuite/tests/concurrent/should_run/allowinterrupt001.hs
new file mode 100644
index 0000000000..938aa65383
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/allowinterrupt001.hs
@@ -0,0 +1,13 @@
+import Control.Exception
+import Control.Concurrent
+import GHC.Conc
+import Control.Monad
+
+nfib n = if n < 2 then 1 else nfib (n-2) + nfib (n-1)
+
+main = do
+ t <- mask_ $ forkIO $ forM_ [1..] $ \n -> nfib n `seq` allowInterrupt
+ killThread t
+ let loop = do r <- threadStatus t
+ when (r /= ThreadFinished) $ do yield; loop
+ loop
diff --git a/testsuite/tests/concurrent/should_run/async001.hs b/testsuite/tests/concurrent/should_run/async001.hs
new file mode 100644
index 0000000000..7d765e26f9
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/async001.hs
@@ -0,0 +1,19 @@
+import Control.Exception as E
+import Control.Concurrent
+import System.IO.Unsafe
+
+-- x is killed during evaluation with an asynchronous exception, but
+-- nevertheless gets overwritten with 'throw ThreadKilled' because the
+-- async exception is re-thrown as a synchrnonous exception by
+-- 'onException'.
+
+main = do
+ let x = unsafePerformIO $
+ (do threadDelay 1000000; return 42)
+ `onException` return ()
+
+ t <- forkIO $ do evaluate x; return ()
+ threadDelay 1000
+ killThread t
+
+ print x `E.catch` \e -> putStrLn ("main caught: " ++ show (e::SomeException))
diff --git a/testsuite/tests/concurrent/should_run/async001.stdout b/testsuite/tests/concurrent/should_run/async001.stdout
new file mode 100644
index 0000000000..241be4a895
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/async001.stdout
@@ -0,0 +1 @@
+main caught: thread killed
diff --git a/testsuite/tests/concurrent/should_run/conc001.hs b/testsuite/tests/concurrent/should_run/conc001.hs
new file mode 100644
index 0000000000..99488fb07b
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc001.hs
@@ -0,0 +1,15 @@
+module Main where
+
+import Control.Concurrent
+
+-- two processes, one MVar communication.
+
+main = do
+ s <- newEmptyMVar
+ let
+ write = do
+ putMVar s "hello world\n"
+
+ forkIO write
+ str <- takeMVar s
+ putStr str
diff --git a/testsuite/tests/concurrent/should_run/conc001.stdout b/testsuite/tests/concurrent/should_run/conc001.stdout
new file mode 100644
index 0000000000..3b18e512db
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc001.stdout
@@ -0,0 +1 @@
+hello world
diff --git a/testsuite/tests/concurrent/should_run/conc002.hs b/testsuite/tests/concurrent/should_run/conc002.hs
new file mode 100644
index 0000000000..93efd6fe4c
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc002.hs
@@ -0,0 +1,14 @@
+module Main where
+
+import Control.Concurrent
+
+main = do
+ c <- newChan
+ let writer = writeList2Chan c "Hello World\n"
+ forkIO writer
+ let reader = do char <- readChan c
+ if (char == '\n')
+ then return ()
+ else do putChar char; reader
+ reader
+
diff --git a/testsuite/tests/concurrent/should_run/conc002.stdout b/testsuite/tests/concurrent/should_run/conc002.stdout
new file mode 100644
index 0000000000..5e1c309dae
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc002.stdout
@@ -0,0 +1 @@
+Hello World \ No newline at end of file
diff --git a/testsuite/tests/concurrent/should_run/conc003.hs b/testsuite/tests/concurrent/should_run/conc003.hs
new file mode 100644
index 0000000000..c7b1f9a56c
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc003.hs
@@ -0,0 +1,28 @@
+module Main where
+
+import Control.Concurrent
+
+-- simple handshaking using two MVars,
+-- must context switch twice for each character.
+
+main = do
+ ready <- newEmptyMVar
+ datum <- newEmptyMVar
+ let
+ reader = do
+ putMVar ready ()
+ char <- takeMVar datum
+ if (char == '\n')
+ then return ()
+ else do putChar char; reader
+
+ writer "" = do
+ takeMVar ready
+ putMVar datum '\n'
+ writer (c:cs) = do
+ takeMVar ready
+ putMVar datum c
+ writer cs
+
+ forkIO reader
+ writer "Hello World"
diff --git a/testsuite/tests/concurrent/should_run/conc003.stdout b/testsuite/tests/concurrent/should_run/conc003.stdout
new file mode 100644
index 0000000000..5e1c309dae
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc003.stdout
@@ -0,0 +1 @@
+Hello World \ No newline at end of file
diff --git a/testsuite/tests/concurrent/should_run/conc004.hs b/testsuite/tests/concurrent/should_run/conc004.hs
new file mode 100644
index 0000000000..ec46c4ba73
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc004.hs
@@ -0,0 +1,19 @@
+module Main where
+
+-- Test thread creation.
+-- (from: Einar Wolfgang Karlsen <ewk@Informatik.Uni-Bremen.DE>)
+
+import Control.Concurrent
+
+main :: IO ()
+main = do
+ mvar <- newEmptyMVar
+
+ let
+ spawner :: (IO () -> IO ThreadId) -> Int -> IO ()
+ spawner c 0 = putMVar mvar ()
+ spawner c n = do { c (spawner c (n-1)); return ()}
+
+ spawner forkIO 100000
+ takeMVar mvar
+ putStr "done"
diff --git a/testsuite/tests/concurrent/should_run/conc004.stdout b/testsuite/tests/concurrent/should_run/conc004.stdout
new file mode 100644
index 0000000000..348ebd9491
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc004.stdout
@@ -0,0 +1 @@
+done \ No newline at end of file
diff --git a/testsuite/tests/concurrent/should_run/conc006.hs b/testsuite/tests/concurrent/should_run/conc006.hs
new file mode 100644
index 0000000000..4a77b5fc95
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc006.hs
@@ -0,0 +1,23 @@
+module Main where
+
+import Control.Concurrent
+
+-- This test hopefully exercises the black hole code. The main thread
+-- forks off another thread and starts on a large computation.
+-- The child thread attempts to get the result of the same large
+-- computation (and should get blocked doing so, because the parent
+-- won't have evaluated it yet). When the result is available, the
+-- child passes it back to the parent who prints it out.
+
+test = sum [1..10000]
+
+main = do
+ x <- newEmptyMVar
+ forkIO (if test > 0
+ then putMVar x test
+ else error "proc"
+ )
+ if test > 0 -- evaluate test
+ then do result <- takeMVar x
+ print result
+ else error "main"
diff --git a/testsuite/tests/concurrent/should_run/conc006.stdout b/testsuite/tests/concurrent/should_run/conc006.stdout
new file mode 100644
index 0000000000..b9d569380c
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc006.stdout
@@ -0,0 +1 @@
+50005000
diff --git a/testsuite/tests/concurrent/should_run/conc007.hs b/testsuite/tests/concurrent/should_run/conc007.hs
new file mode 100644
index 0000000000..74535ebe6d
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc007.hs
@@ -0,0 +1,23 @@
+
+module Main where
+
+import Control.Concurrent
+import Control.Exception as E
+
+choose :: a -> a -> IO a
+choose a b = do
+ ready <- newMVar ()
+ answer <- newEmptyMVar
+ a_id <- forkIO (a `seq` takeMVar ready >> putMVar answer a)
+ b_id <- forkIO (b `seq` takeMVar ready >> putMVar answer b)
+ it <- takeMVar answer
+ killThread a_id
+ killThread b_id
+ return it
+
+main = do
+ let big = sum [1..]
+ small = sum [1..42]
+ test1 <- choose big small
+ test2 <- choose small big
+ print (test1,test2)
diff --git a/testsuite/tests/concurrent/should_run/conc007.stdout b/testsuite/tests/concurrent/should_run/conc007.stdout
new file mode 100644
index 0000000000..ee81b5ecd3
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc007.stdout
@@ -0,0 +1 @@
+(903,903)
diff --git a/testsuite/tests/concurrent/should_run/conc008.hs b/testsuite/tests/concurrent/should_run/conc008.hs
new file mode 100644
index 0000000000..66a4b5f973
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc008.hs
@@ -0,0 +1,12 @@
+
+module Main where
+
+import Control.Concurrent
+import Control.Exception
+
+-- Send ourselves a KillThread signal, catch it and recover.
+
+main = do
+ id <- myThreadId
+ Control.Exception.catch (killThread id) $
+ \e -> putStr (show (e::SomeException))
diff --git a/testsuite/tests/concurrent/should_run/conc008.stdout b/testsuite/tests/concurrent/should_run/conc008.stdout
new file mode 100644
index 0000000000..faed5b894d
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc008.stdout
@@ -0,0 +1 @@
+thread killed \ No newline at end of file
diff --git a/testsuite/tests/concurrent/should_run/conc009.hs b/testsuite/tests/concurrent/should_run/conc009.hs
new file mode 100644
index 0000000000..94c7809332
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc009.hs
@@ -0,0 +1,9 @@
+
+module Main where
+
+import Control.Concurrent
+import Control.Exception
+
+main = do
+ id <- myThreadId
+ throwTo id (ErrorCall "hello")
diff --git a/testsuite/tests/concurrent/should_run/conc009.stderr b/testsuite/tests/concurrent/should_run/conc009.stderr
new file mode 100644
index 0000000000..e42034eba1
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc009.stderr
@@ -0,0 +1 @@
+conc009: hello
diff --git a/testsuite/tests/concurrent/should_run/conc010.hs b/testsuite/tests/concurrent/should_run/conc010.hs
new file mode 100644
index 0000000000..52acb97a35
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc010.hs
@@ -0,0 +1,28 @@
+
+module Main where
+
+import Control.Concurrent
+import Control.Exception
+
+-- Raise an exception in another thread. We need a lot of synchronisation here:
+
+-- - an MVar for the second thread to block on which it waits for the
+-- signal (block)
+
+-- - an MVar to signal the main thread that the second thread is ready to
+-- accept the signal (ready)
+
+-- - an MVar to signal the main thread that the second thread has received
+-- the signal (ready2). If we don't have this MVar, then the main
+-- thread could exit before the second thread has time to print
+-- the result.
+
+main = do
+ block <- newEmptyMVar
+ ready <- newEmptyMVar
+ ready2 <- newEmptyMVar
+ id <- forkIO (Control.Exception.catch (putMVar ready () >> takeMVar block)
+ (\e -> putStr (show (e::SomeException)) >> putMVar ready2 ()))
+ takeMVar ready
+ throwTo id (ErrorCall "hello")
+ takeMVar ready2
diff --git a/testsuite/tests/concurrent/should_run/conc010.stdout b/testsuite/tests/concurrent/should_run/conc010.stdout
new file mode 100644
index 0000000000..b6fc4c620b
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc010.stdout
@@ -0,0 +1 @@
+hello \ No newline at end of file
diff --git a/testsuite/tests/concurrent/should_run/conc012.hs b/testsuite/tests/concurrent/should_run/conc012.hs
new file mode 100644
index 0000000000..a2f139e401
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc012.hs
@@ -0,0 +1,23 @@
+module Main where
+
+import Control.Concurrent
+import Control.Exception
+--import GlaExts
+
+data Result = Died SomeException | Finished
+
+-- Test stack overflow catching. Should print "Died: stack overflow".
+
+stackoverflow :: Int -> Int
+stackoverflow 0 = 1
+stackoverflow n = n + stackoverflow n
+
+main = do
+ let x = stackoverflow 1
+ result <- newEmptyMVar
+ forkIO $ Control.Exception.catch (x `seq` putMVar result Finished) $
+ \e -> putMVar result (Died e)
+ res <- takeMVar result
+ case res of
+ Died e -> putStr ("Died: " ++ show e ++ "\n")
+ Finished -> putStr "Ok.\n"
diff --git a/testsuite/tests/concurrent/should_run/conc012.stdout b/testsuite/tests/concurrent/should_run/conc012.stdout
new file mode 100644
index 0000000000..12e0c906fc
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc012.stdout
@@ -0,0 +1 @@
+Died: stack overflow
diff --git a/testsuite/tests/concurrent/should_run/conc013.hs b/testsuite/tests/concurrent/should_run/conc013.hs
new file mode 100644
index 0000000000..ea2130ee47
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc013.hs
@@ -0,0 +1,10 @@
+module Main where
+
+-- !!! test Eq and Ord instances over thread Ids.
+
+import Control.Concurrent
+
+main = do
+ tso1 <- forkIO (return ())
+ tso2 <- forkIO (return ())
+ print [compare tso1 tso2, compare tso1 tso1, compare tso2 tso1]
diff --git a/testsuite/tests/concurrent/should_run/conc013.stdout b/testsuite/tests/concurrent/should_run/conc013.stdout
new file mode 100644
index 0000000000..98ab9c11f2
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc013.stdout
@@ -0,0 +1 @@
+[LT,EQ,GT]
diff --git a/testsuite/tests/concurrent/should_run/conc014.hs b/testsuite/tests/concurrent/should_run/conc014.hs
new file mode 100644
index 0000000000..76cb3c24b0
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc014.hs
@@ -0,0 +1,27 @@
+import Control.Concurrent
+import Control.Exception
+
+-- Test blocking of async exceptions in an exception handler.
+-- The exception raised in the main thread should not be delivered
+-- until the first exception handler finishes.
+main = do
+ main_thread <- myThreadId
+ m <- newEmptyMVar
+ forkIO (do { takeMVar m; throwTo main_thread (ErrorCall "foo") })
+ (do
+ error "wibble"
+ `Control.Exception.catch`
+ (\e -> let _ = e::ErrorCall in
+ do putMVar m (); sum [1..10000] `seq` putStrLn "done.")
+ myDelay 500000
+ )
+ `Control.Exception.catch`
+ \e -> putStrLn ("caught: " ++ show (e::SomeException))
+
+-- compensate for the fact that threadDelay is non-interruptible
+-- on Windows with the threaded RTS in 6.6.
+myDelay usec = do
+ m <- newEmptyMVar
+ forkIO $ do threadDelay usec; putMVar m ()
+ takeMVar m
+
diff --git a/testsuite/tests/concurrent/should_run/conc014.stdout b/testsuite/tests/concurrent/should_run/conc014.stdout
new file mode 100644
index 0000000000..807edef7c9
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc014.stdout
@@ -0,0 +1,2 @@
+done.
+caught: foo
diff --git a/testsuite/tests/concurrent/should_run/conc015.hs b/testsuite/tests/concurrent/should_run/conc015.hs
new file mode 100644
index 0000000000..7574e15e5e
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc015.hs
@@ -0,0 +1,44 @@
+import Control.Concurrent
+import Control.Exception
+
+-- test blocking & unblocking of async exceptions.
+
+-- the first exception "foo" should be caught by the "caught1" handler,
+-- since async exceptions are blocked outside this handler.
+
+-- the second exception "bar" should be caught by the outer "caught2" handler,
+-- (i.e. this tests that async exceptions are properly unblocked after
+-- being blocked).
+
+main = do
+ main_thread <- myThreadId
+ print =<< blocked -- False
+ m <- newEmptyMVar
+ m2 <- newEmptyMVar
+ forkIO (do takeMVar m
+ throwTo main_thread (ErrorCall "foo")
+ throwTo main_thread (ErrorCall "bar")
+ putMVar m2 ()
+ )
+ ( do
+ block (do
+ putMVar m ()
+ print =<< blocked -- True
+ sum [1..1] `seq` -- give 'foo' a chance to be raised
+ (unblock $ myDelay 500000)
+ `Control.Exception.catch`
+ \e -> putStrLn ("caught1: " ++ show (e::SomeException))
+ )
+ threadDelay 10000
+ takeMVar m2
+ )
+ `Control.Exception.catch`
+ \e -> do print =<< blocked
+ putStrLn ("caught2: " ++ show (e::SomeException))
+
+-- compensate for the fact that threadDelay is non-interruptible
+-- on Windows with the threaded RTS in 6.6.
+myDelay usec = do
+ m <- newEmptyMVar
+ forkIO $ do threadDelay usec; putMVar m ()
+ takeMVar m
diff --git a/testsuite/tests/concurrent/should_run/conc015.stdout b/testsuite/tests/concurrent/should_run/conc015.stdout
new file mode 100644
index 0000000000..be6aa71d11
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc015.stdout
@@ -0,0 +1,5 @@
+False
+True
+caught1: foo
+True
+caught2: bar
diff --git a/testsuite/tests/concurrent/should_run/conc015a.hs b/testsuite/tests/concurrent/should_run/conc015a.hs
new file mode 100644
index 0000000000..cd8d9dd6c7
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc015a.hs
@@ -0,0 +1,47 @@
+import Control.Concurrent
+import Control.Exception
+
+-- version of conc015 using mask in place of the old deprecated
+-- block/unblock.
+
+-- test blocking & unblocking of async exceptions.
+
+-- the first exception "foo" should be caught by the "caught1" handler,
+-- since async exceptions are blocked outside this handler.
+
+-- the second exception "bar" should be caught by the outer "caught2" handler,
+-- (i.e. this tests that async exceptions are properly unblocked after
+-- being blocked).
+
+main = do
+ main_thread <- myThreadId
+ print =<< getMaskingState
+ m <- newEmptyMVar
+ m2 <- newEmptyMVar
+ forkIO (do takeMVar m
+ throwTo main_thread (ErrorCall "foo")
+ throwTo main_thread (ErrorCall "bar")
+ putMVar m2 ()
+ )
+ ( do
+ mask $ \restore -> do
+ putMVar m ()
+ print =<< getMaskingState
+ sum [1..100000] `seq` -- give 'foo' a chance to be raised
+ (restore (myDelay 500000)
+ `Control.Exception.catch`
+ \e -> putStrLn ("caught1: " ++ show (e::SomeException)))
+
+ threadDelay 10000
+ takeMVar m2
+ )
+ `Control.Exception.catch`
+ \e -> do print =<< getMaskingState
+ putStrLn ("caught2: " ++ show (e::SomeException))
+
+-- compensate for the fact that threadDelay is non-interruptible
+-- on Windows with the threaded RTS in 6.6.
+myDelay usec = do
+ m <- newEmptyMVar
+ forkIO $ do threadDelay usec; putMVar m ()
+ takeMVar m
diff --git a/testsuite/tests/concurrent/should_run/conc015a.stdout b/testsuite/tests/concurrent/should_run/conc015a.stdout
new file mode 100644
index 0000000000..19b98e9b60
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc015a.stdout
@@ -0,0 +1,5 @@
+Unmasked
+MaskedInterruptible
+caught1: foo
+MaskedUninterruptible
+caught2: bar
diff --git a/testsuite/tests/concurrent/should_run/conc016.hs b/testsuite/tests/concurrent/should_run/conc016.hs
new file mode 100644
index 0000000000..639b4306b3
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc016.hs
@@ -0,0 +1,27 @@
+import Control.Concurrent
+import Control.Exception
+
+-- check that we can still kill a thread that is blocked on
+-- delivering an exception to us.
+
+-- NB. this test is non-deterministic in the threaded2 way since 6.14,
+-- because throwTo is now always interruptible, so the main thread's
+-- killThread can be legitimately interrupted by the child thread's
+-- killThread, rather than the other way around. This happens because
+-- the child thread is running on another processor, so the main
+-- thread's throwTo is blocked waiting for a response, and while
+-- waiting it is interruptible.
+
+main = do
+ main_thread <- myThreadId
+ m <- newEmptyMVar
+ sub_thread <- forkIO (do
+ takeMVar m
+ throwTo main_thread (ErrorCall "foo")
+ )
+ mask_ $ do
+ putMVar m ()
+ sum [1..10000] `seq` -- to be sure the other thread is now blocked
+ killThread sub_thread
+
+ putStrLn "ok"
diff --git a/testsuite/tests/concurrent/should_run/conc016.stdout b/testsuite/tests/concurrent/should_run/conc016.stdout
new file mode 100644
index 0000000000..9766475a41
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc016.stdout
@@ -0,0 +1 @@
+ok
diff --git a/testsuite/tests/concurrent/should_run/conc017.hs b/testsuite/tests/concurrent/should_run/conc017.hs
new file mode 100644
index 0000000000..30d8a1c56d
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc017.hs
@@ -0,0 +1,45 @@
+import Control.Concurrent
+import Control.Exception
+
+-- check that async exceptions are restored to their previous
+-- state after an exception is raised and handled.
+
+main = do
+ main_thread <- myThreadId
+ m1 <- newEmptyMVar
+ m2 <- newEmptyMVar
+ m3 <- newEmptyMVar
+ forkIO (do
+ takeMVar m1
+ throwTo main_thread (ErrorCall "foo")
+ takeMVar m2
+ throwTo main_thread (ErrorCall "bar")
+ putMVar m3 ()
+ )
+ (do
+ block (do
+ (do putMVar m1 ()
+ unblock (
+ -- unblocked, "foo" delivered to "caught1"
+ myDelay 100000
+ )
+ ) `Control.Exception.catch`
+ \e -> putStrLn ("caught1: " ++ show (e::SomeException))
+ putMVar m2 ()
+ -- blocked here, "bar" can't be delivered
+ (sum [1..10000] `seq` return ())
+ `Control.Exception.catch`
+ \e -> putStrLn ("caught2: " ++ show (e::SomeException))
+ )
+ -- unblocked here, "bar" delivered to "caught3"
+ takeMVar m3
+ )
+ `Control.Exception.catch`
+ \e -> putStrLn ("caught3: " ++ show (e::SomeException))
+
+-- compensate for the fact that threadDelay is non-interruptible
+-- on Windows with the threaded RTS in 6.6.
+myDelay usec = do
+ m <- newEmptyMVar
+ forkIO $ do threadDelay usec; putMVar m ()
+ takeMVar m
diff --git a/testsuite/tests/concurrent/should_run/conc017.stdout b/testsuite/tests/concurrent/should_run/conc017.stdout
new file mode 100644
index 0000000000..7fca279f26
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc017.stdout
@@ -0,0 +1,2 @@
+caught1: foo
+caught3: bar
diff --git a/testsuite/tests/concurrent/should_run/conc017a.hs b/testsuite/tests/concurrent/should_run/conc017a.hs
new file mode 100644
index 0000000000..ad015f7413
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc017a.hs
@@ -0,0 +1,44 @@
+import Control.Concurrent
+import Control.Exception
+
+-- check that async exceptions are restored to their previous
+-- state after an exception is raised and handled.
+
+main = do
+ main_thread <- myThreadId
+ m1 <- newEmptyMVar
+ m2 <- newEmptyMVar
+ m3 <- newEmptyMVar
+ forkIO (do
+ takeMVar m1
+ throwTo main_thread (ErrorCall "foo")
+ takeMVar m2
+ throwTo main_thread (ErrorCall "bar")
+ putMVar m3 ()
+ )
+ (do
+ mask $ \restore -> do
+ (do putMVar m1 ()
+ restore (
+ -- unblocked, "foo" delivered to "caught1"
+ myDelay 100000
+ )
+ ) `Control.Exception.catch`
+ \e -> putStrLn ("caught1: " ++ show (e::SomeException))
+ putMVar m2 ()
+ -- blocked here, "bar" can't be delivered
+ (sum [1..10000] `seq` return ())
+ `Control.Exception.catch`
+ \e -> putStrLn ("caught2: " ++ show (e::SomeException))
+ -- unblocked here, "bar" delivered to "caught3"
+ takeMVar m3
+ )
+ `Control.Exception.catch`
+ \e -> putStrLn ("caught3: " ++ show (e::SomeException))
+
+-- compensate for the fact that threadDelay is non-interruptible
+-- on Windows with the threaded RTS in 6.6.
+myDelay usec = do
+ m <- newEmptyMVar
+ forkIO $ do threadDelay usec; putMVar m ()
+ takeMVar m
diff --git a/testsuite/tests/concurrent/should_run/conc017a.stdout b/testsuite/tests/concurrent/should_run/conc017a.stdout
new file mode 100644
index 0000000000..7fca279f26
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc017a.stdout
@@ -0,0 +1,2 @@
+caught1: foo
+caught3: bar
diff --git a/testsuite/tests/concurrent/should_run/conc018.hs b/testsuite/tests/concurrent/should_run/conc018.hs
new file mode 100644
index 0000000000..aa83e31738
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc018.hs
@@ -0,0 +1,26 @@
+import Control.Concurrent
+import Control.Exception
+import GHC.Conc
+import Foreign
+
+-- test that putMVar blocks on a full MVar rather than raising an
+-- exception.
+
+main = do
+ -- In this test we want a thread to get BlockedIndefinitely; that
+ -- can't be the main thread because in GHCi the main thread
+ -- doesn't get BlockedIndefinitely. So we have to use a
+ -- subthread, and "prevent* the main thread from getting
+ -- BlockedIndefinitely when we're not in GHCi, which is what the
+ -- following hack does:
+ myThreadId >>= newStablePtr
+
+ m <- newEmptyMVar
+ t <- forkIO $ do
+ Control.Exception.catch (do
+ m <- newMVar ()
+ putMVar m ()
+ )
+ (\e -> putMVar m (e::SomeException))
+ takeMVar m >>= print
+ -- should print "thread blocked indefinitely"
diff --git a/testsuite/tests/concurrent/should_run/conc018.stdout b/testsuite/tests/concurrent/should_run/conc018.stdout
new file mode 100644
index 0000000000..dd56b71f23
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc018.stdout
@@ -0,0 +1 @@
+thread blocked indefinitely in an MVar operation
diff --git a/testsuite/tests/concurrent/should_run/conc019.hs b/testsuite/tests/concurrent/should_run/conc019.hs
new file mode 100644
index 0000000000..51b3d7563a
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc019.hs
@@ -0,0 +1,14 @@
+import Control.Concurrent
+import Control.Exception
+import Data.List
+import System.Mem
+
+-- !!! test that a child thread waiting on its own MVar will get killed by
+-- a signal.
+
+main = do
+ forkIO (Control.Exception.catch (do { m <- newEmptyMVar; takeMVar m })
+ $ \e -> putStrLn ("caught: " ++ show (e::SomeException)))
+ threadDelay 10000
+ System.Mem.performGC
+ threadDelay 10000
diff --git a/testsuite/tests/concurrent/should_run/conc019.stdout b/testsuite/tests/concurrent/should_run/conc019.stdout
new file mode 100644
index 0000000000..aba647b928
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc019.stdout
@@ -0,0 +1 @@
+caught: thread blocked indefinitely in an MVar operation
diff --git a/testsuite/tests/concurrent/should_run/conc020.hs b/testsuite/tests/concurrent/should_run/conc020.hs
new file mode 100644
index 0000000000..956b761245
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc020.hs
@@ -0,0 +1,10 @@
+import Control.Concurrent
+import Control.Exception
+
+main = do
+ m <- newEmptyMVar
+ t <- forkIO (block $ takeMVar m)
+ threadDelay 100000
+ throwTo t (ErrorCall "I'm Interruptible")
+ threadDelay 100000
+ putMVar m () -- to avoid t being garbage collected
diff --git a/testsuite/tests/concurrent/should_run/conc020.stderr b/testsuite/tests/concurrent/should_run/conc020.stderr
new file mode 100644
index 0000000000..b0bcbfb17f
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc020.stderr
@@ -0,0 +1 @@
+conc020: I'm Interruptible
diff --git a/testsuite/tests/concurrent/should_run/conc021.hs b/testsuite/tests/concurrent/should_run/conc021.hs
new file mode 100644
index 0000000000..c07c48af35
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc021.hs
@@ -0,0 +1,11 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+module Main where
+
+-- !!! test for uncaught exception
+
+foreign export ccall foo :: Int -> IO Int
+foreign import ccall safe "foo" foo_imported :: Int -> IO Int
+
+foo n = error "wurble"
+
+main = foo_imported 3
diff --git a/testsuite/tests/concurrent/should_run/conc021.stderr b/testsuite/tests/concurrent/should_run/conc021.stderr
new file mode 100644
index 0000000000..78e92140e6
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc021.stderr
@@ -0,0 +1 @@
+conc021: wurble
diff --git a/testsuite/tests/concurrent/should_run/conc022.hs b/testsuite/tests/concurrent/should_run/conc022.hs
new file mode 100644
index 0000000000..5d420d8af7
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc022.hs
@@ -0,0 +1,40 @@
+{-# LANGUAGE MagicHash #-}
+-- !!! test tryTakeMVar
+
+import Control.Concurrent
+import Control.Exception
+
+import GHC.Exts ( fork# )
+import GHC.IO ( IO(..) )
+import GHC.Conc ( ThreadId(..) )
+
+main = do
+ m <- newEmptyMVar
+ r <- timeout 5 (tryTakeMVar m) (putStrLn "timed out!" >> return Nothing)
+ print (r :: Maybe Int)
+
+ m <- newMVar True
+ r <- timeout 5 (tryTakeMVar m) (putStrLn "timed out!" >> return Nothing)
+ print r
+
+timeout
+ :: Int -- secs
+ -> IO a -- action to run
+ -> IO a -- action to run on timeout
+ -> IO a
+
+timeout secs action on_timeout
+ = do
+ threadid <- myThreadId
+ timeout <- forkIO $ do threadDelay (secs * 1000000)
+ throwTo threadid (ErrorCall "__timeout")
+ ( do result <- action
+ killThread timeout
+ return result
+ )
+ `Control.Exception.catch`
+ \exception -> case fromException exception of
+ Just (ErrorCall "__timeout") -> on_timeout
+ _other -> do killThread timeout
+ throw exception
+
diff --git a/testsuite/tests/concurrent/should_run/conc022.stdout b/testsuite/tests/concurrent/should_run/conc022.stdout
new file mode 100644
index 0000000000..07de2e62f6
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc022.stdout
@@ -0,0 +1,2 @@
+Nothing
+Just True
diff --git a/testsuite/tests/concurrent/should_run/conc023.hs b/testsuite/tests/concurrent/should_run/conc023.hs
new file mode 100644
index 0000000000..b128c224a3
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc023.hs
@@ -0,0 +1,23 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+-- !!! test threadDelay, Random, and QSemN.
+
+-- start a large number (n) of threads each of which will wait for a
+-- random delay between 0 and m seconds. We use a semaphore to wait
+-- for all the threads to finish.
+
+import System.Random
+import Control.Concurrent
+import Control.Exception
+
+n = 5000 -- no. of threads
+m = 3000 -- maximum delay
+
+main = do
+ s <- newQSemN n
+ (is :: [Int]) <- sequence (take n (repeat (getStdRandom (randomR (1,m)))))
+ mapM (fork_sleep s) is
+ waitQSemN s n
+ where
+ fork_sleep s i = forkIO (do waitQSemN s 1
+ threadDelay (i*1000)
+ signalQSemN s 1)
diff --git a/testsuite/tests/concurrent/should_run/conc024.hs b/testsuite/tests/concurrent/should_run/conc024.hs
new file mode 100644
index 0000000000..e37d64a6e2
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc024.hs
@@ -0,0 +1,15 @@
+module Main where
+
+import Control.Exception
+import Control.Concurrent
+import Prelude hiding (catch)
+import System.Mem
+
+-- illustrates the BlockOnDeadMVar exception
+
+main = do
+ id <- myThreadId
+ forkIO (catch (do m <- newEmptyMVar; takeMVar m)
+ (\e -> throwTo id (e::SomeException)))
+ catch (do yield; performGC; threadDelay 1000000)
+ (\e -> print (e::SomeException))
diff --git a/testsuite/tests/concurrent/should_run/conc024.stdout b/testsuite/tests/concurrent/should_run/conc024.stdout
new file mode 100644
index 0000000000..dd56b71f23
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc024.stdout
@@ -0,0 +1 @@
+thread blocked indefinitely in an MVar operation
diff --git a/testsuite/tests/concurrent/should_run/conc025.hs b/testsuite/tests/concurrent/should_run/conc025.hs
new file mode 100644
index 0000000000..a9591d4223
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc025.hs
@@ -0,0 +1,16 @@
+-- !!! Simple test of dupChan
+-- Embarassingly, the published version fails!
+
+module Main where
+
+import Control.Exception
+import Control.Concurrent.Chan
+
+main = do
+ chan <- newChan
+ ch <- dupChan chan
+ writeChan chan "done"
+ x <- readChan chan
+ y <- readChan ch
+ print ("Got "++x ++" "++y)
+
diff --git a/testsuite/tests/concurrent/should_run/conc025.stdout b/testsuite/tests/concurrent/should_run/conc025.stdout
new file mode 100644
index 0000000000..fb1569261c
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc025.stdout
@@ -0,0 +1 @@
+"Got done done"
diff --git a/testsuite/tests/concurrent/should_run/conc026.hs b/testsuite/tests/concurrent/should_run/conc026.hs
new file mode 100644
index 0000000000..0aa170afb5
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc026.hs
@@ -0,0 +1,8 @@
+-- test for blocking putMVar
+
+import Control.Concurrent
+
+main = do
+ m <- newMVar ()
+ forkIO (threadDelay 100000 >> takeMVar m)
+ putMVar m ()
diff --git a/testsuite/tests/concurrent/should_run/conc027.hs b/testsuite/tests/concurrent/should_run/conc027.hs
new file mode 100644
index 0000000000..4a04211824
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc027.hs
@@ -0,0 +1,9 @@
+
+import Control.Concurrent
+
+main = do
+ m <- newEmptyMVar
+ end <- newEmptyMVar
+ forkIO (sequence_ [ putMVar m () | _ <- [1 .. 10000] ])
+ forkIO (sequence_ [ takeMVar m | _ <- [1 .. 10000] ] >> putMVar end ())
+ takeMVar end
diff --git a/testsuite/tests/concurrent/should_run/conc028.hs b/testsuite/tests/concurrent/should_run/conc028.hs
new file mode 100644
index 0000000000..4d3d16866a
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc028.hs
@@ -0,0 +1,11 @@
+-- test tryPutMVar
+
+import Control.Concurrent
+
+main = do
+ m <- newMVar ()
+ r <- tryPutMVar m ()
+ print r
+ takeMVar m
+ r <- tryPutMVar m ()
+ print r
diff --git a/testsuite/tests/concurrent/should_run/conc028.stdout b/testsuite/tests/concurrent/should_run/conc028.stdout
new file mode 100644
index 0000000000..91d6f80f27
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc028.stdout
@@ -0,0 +1,2 @@
+False
+True
diff --git a/testsuite/tests/concurrent/should_run/conc029.hs b/testsuite/tests/concurrent/should_run/conc029.hs
new file mode 100644
index 0000000000..dc1150073d
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc029.hs
@@ -0,0 +1,11 @@
+module Main where
+
+import Control.Exception
+import Control.Concurrent
+import Prelude hiding (catch)
+
+-- the BlockOnDeadMVar exception doesn't cause any output by default
+
+main = do
+ forkIO (do m <- newEmptyMVar; takeMVar m)
+ print (sum [1..10000])
diff --git a/testsuite/tests/concurrent/should_run/conc029.stdout b/testsuite/tests/concurrent/should_run/conc029.stdout
new file mode 100644
index 0000000000..b9d569380c
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc029.stdout
@@ -0,0 +1 @@
+50005000
diff --git a/testsuite/tests/concurrent/should_run/conc030.hs b/testsuite/tests/concurrent/should_run/conc030.hs
new file mode 100644
index 0000000000..4f01668456
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc030.hs
@@ -0,0 +1,15 @@
+module Main where
+
+import Control.Exception
+import Control.Concurrent
+import Prelude hiding (catch)
+
+-- the ThreadKilled exception doesn't cause any output by default
+
+main = do
+ m <- newEmptyMVar
+ id <- forkIO (takeMVar m)
+ yield
+ killThread id
+ putMVar m ()
+ print (sum [1..50000])
diff --git a/testsuite/tests/concurrent/should_run/conc030.stdout b/testsuite/tests/concurrent/should_run/conc030.stdout
new file mode 100644
index 0000000000..ba6ee958ee
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc030.stdout
@@ -0,0 +1 @@
+1250025000
diff --git a/testsuite/tests/concurrent/should_run/conc031.hs b/testsuite/tests/concurrent/should_run/conc031.hs
new file mode 100644
index 0000000000..c3347550a9
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc031.hs
@@ -0,0 +1,30 @@
+import Control.Concurrent
+import Control.Exception
+import System.Mem ( performGC )
+import System.Mem.Weak ( addFinalizer )
+
+data P = P (MVar Bool)
+
+-- Bug reported by Manuel Chakravarty, namely that we weren't checking
+-- for runnable finalizers before declaring that the program is
+-- deadlocked.
+
+main = do
+-- gcThread -- with this thread enabled, no error
+ mv <- newEmptyMVar
+ let p = P mv
+ addFinalizer p (set p)
+ takeMVar mv >>= print
+ putStrLn "End."
+ where
+ set (P mv) = putMVar mv True
+ --
+ -- this is just to demonstrate that it is only about the GC timing
+ --
+ gcThread = forkIO $ let gc = do
+ putStrLn "delay"
+ threadDelay 100000
+ putStrLn "gc"
+ performGC
+ gc
+ in gc
diff --git a/testsuite/tests/concurrent/should_run/conc031.stdout b/testsuite/tests/concurrent/should_run/conc031.stdout
new file mode 100644
index 0000000000..8d45abf2c7
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc031.stdout
@@ -0,0 +1,2 @@
+True
+End.
diff --git a/testsuite/tests/concurrent/should_run/conc032.hs b/testsuite/tests/concurrent/should_run/conc032.hs
new file mode 100644
index 0000000000..42149ff477
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc032.hs
@@ -0,0 +1,74 @@
+-- !!! this test exposed a bug in the take/putMVar implementation in
+-- !!! GHC 5.00. It involves multiple blocking takes & puts on the
+-- !!! same MVar.
+
+import Control.Concurrent
+import System.IO.Unsafe
+
+awk True True z = 1
+awk False y True = 2
+awk x False False = 3
+
+awk'1 True True z = 1
+awk'2 False y True = 2
+awk'3 x False False = 3
+
+awk' x y z | ppm [a1'1,a1'2,a1'3] (x,y,z) = awk'1 x y z
+ | ppm [a2'1,a2'2,a2'3] (x,y,z) = awk'2 x y z
+ | ppm [a3'1,a3'2,a3'3] (x,y,z) = awk'3 x y z
+ | otherwise = 0
+
+a1'1 (True,y,z) s = s True
+a1'1 (x,y,z) s = s False
+
+a1'2 (x,True,z) s = s True
+a1'2 (x,y,z) s = s False
+
+a1'3 (x,y,z) s = s True
+
+a2'1 (False,y,z) s = s True
+a2'1 (x,y,z) s = s False
+
+a2'2 (x,y,z) s = s True
+
+a2'3 (x,y,True) s = s True
+a2'3 (x,y,z) s = s False
+
+a3'1 (x,y,z) s = s True
+
+a3'2 (x,False,z) s = s True
+a3'2 (x,y,z) s = s False
+
+a3'3 (x,y,False) s = s True
+a3'3 (x,y,z) s = s False
+
+ppm fs as = unsafePerformIO (ppm' fs as)
+
+ppm' fs as = do m <- newEmptyMVar
+ let s = putMVar m
+ hs <- sequence [forkIO (f as s)|f <- fs]
+ result <- assess (length fs) m
+ sequence (map killThread hs)
+ return result
+ where assess 0 m = return True
+ assess n m = do h <- takeMVar m
+ if h then (assess (n-1) m)
+ else return False
+
+main = do sequence [putStrLn (show (awk' x y z))|(x,y,z) <- args]
+ where args = [
+ (t,t,t),
+ (t,t,f),
+ (t,f,t),
+ (t,f,f),
+ (f,t,t),
+ (f,t,f),
+ (f,f,t),
+ (f,f,f),
+ (t,t,n)
+ --(f,n,t),
+ --(n,f,f),
+ ]
+ t = True
+ f = False
+ n = odd (last [1..])
diff --git a/testsuite/tests/concurrent/should_run/conc032.stdout b/testsuite/tests/concurrent/should_run/conc032.stdout
new file mode 100644
index 0000000000..a357bc8aac
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc032.stdout
@@ -0,0 +1,9 @@
+1
+1
+0
+3
+2
+0
+2
+3
+1
diff --git a/testsuite/tests/concurrent/should_run/conc033.hs b/testsuite/tests/concurrent/should_run/conc033.hs
new file mode 100644
index 0000000000..6933822e56
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc033.hs
@@ -0,0 +1,10 @@
+import Control.Concurrent
+import Control.Exception
+
+-- !!! test that deadlock is raised as an exception properly
+main = do
+ r <- Control.Exception.try $ do
+ m <- newEmptyMVar
+ takeMVar m
+ return ()
+ print (r::Either SomeException ())
diff --git a/testsuite/tests/concurrent/should_run/conc033.stdout b/testsuite/tests/concurrent/should_run/conc033.stdout
new file mode 100644
index 0000000000..1c0eba9dec
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc033.stdout
@@ -0,0 +1 @@
+Left thread blocked indefinitely in an MVar operation
diff --git a/testsuite/tests/concurrent/should_run/conc034.hs b/testsuite/tests/concurrent/should_run/conc034.hs
new file mode 100644
index 0000000000..4101212ad1
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc034.hs
@@ -0,0 +1,31 @@
+import Control.Concurrent
+import Control.Exception
+import Foreign
+
+import System.IO (hFlush,stdout)
+
+import Prelude hiding (catch)
+
+-- !!! Try to get two threads into a knot depending on each other.
+
+-- This should result in the main thread being sent a NonTermination
+-- exception (in GHC 5.02, the program is terminated with "no threads
+-- to run" instead).
+
+main = do
+ Foreign.newStablePtr stdout
+ -- HACK, because when these two threads get blocked on each other,
+ -- there's nothing keeping stdout alive so it will get finalized.
+ -- SDM 12/3/2004
+ let a = last ([1..10000] ++ [b])
+ b = last ([2..10000] ++ [a])
+ -- we have to be careful to ensure that the strictness analyser
+ -- can't see that a and b are both bottom, otherwise the
+ -- simplifier will go to town here, resulting in something like
+ -- a = a and b = a.
+ forkIO (print a `catch` \NonTermination -> return ())
+ -- we need to catch in the child thread too, because it might
+ -- get sent the NonTermination exception first.
+ r <- Control.Exception.try (print b)
+ print (r :: Either NonTermination ())
+
diff --git a/testsuite/tests/concurrent/should_run/conc034.stdout b/testsuite/tests/concurrent/should_run/conc034.stdout
new file mode 100644
index 0000000000..1f83158694
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc034.stdout
@@ -0,0 +1 @@
+Left <<loop>>
diff --git a/testsuite/tests/concurrent/should_run/conc035.hs b/testsuite/tests/concurrent/should_run/conc035.hs
new file mode 100644
index 0000000000..fcb2d5c2e4
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc035.hs
@@ -0,0 +1,49 @@
+module Main where
+
+import Control.Concurrent
+import qualified Control.Exception as E
+
+trapHandler :: MVar Int -> MVar () -> IO ()
+trapHandler inVar caughtVar =
+ (do E.block $ do
+ trapMsg <- takeMVar inVar
+ putStrLn ("Handler got: " ++ show trapMsg)
+ trapHandler inVar caughtVar
+ )
+ `E.catch`
+ (trapExc inVar caughtVar)
+
+trapExc :: MVar Int -> MVar () -> E.SomeException -> IO ()
+-- If we have been killed then we are done
+trapExc inVar caughtVar e
+ | Just E.ThreadKilled <- E.fromException e = return ()
+-- Otherwise...
+trapExc inVar caughtVar e =
+ do putStrLn ("Exception: " ++ show e)
+ putMVar caughtVar ()
+ trapHandler inVar caughtVar
+
+main :: IO ()
+main = do
+ inVar <- newEmptyMVar
+ caughtVar <- newEmptyMVar
+ tid <- forkIO (trapHandler inVar caughtVar)
+ yield
+ putMVar inVar 1
+ threadDelay 1000
+ throwTo tid (E.ErrorCall "1st")
+ takeMVar caughtVar
+ putMVar inVar 2
+ threadDelay 1000
+ throwTo tid (E.ErrorCall "2nd")
+ -- the second time around, exceptions will be blocked, because
+ -- the trapHandler is effectively "still in the handler" from the
+ -- first exception. I'm not sure if this is by design or by
+ -- accident. Anyway, the trapHandler will at some point block
+ -- in takeMVar, and thereby become interruptible, at which point
+ -- it will receive the second exception.
+ takeMVar caughtVar
+ -- Running the GHCi way complains that tid is blocked indefinitely if
+ -- it still exists, so kill it.
+ killThread tid
+ putStrLn "All done"
diff --git a/testsuite/tests/concurrent/should_run/conc035.stdout b/testsuite/tests/concurrent/should_run/conc035.stdout
new file mode 100644
index 0000000000..f667439731
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc035.stdout
@@ -0,0 +1,5 @@
+Handler got: 1
+Exception: 1st
+Handler got: 2
+Exception: 2nd
+All done
diff --git a/testsuite/tests/concurrent/should_run/conc036.hs b/testsuite/tests/concurrent/should_run/conc036.hs
new file mode 100644
index 0000000000..ead85a530d
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc036.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-# OPTIONS -cpp #-}
+module Main where
+
+import Control.Concurrent
+import Control.Exception
+import Prelude hiding (catch)
+import Foreign
+import System.IO
+
+#ifdef mingw32_HOST_OS
+sleep n = sleepBlock (n*1000)
+foreign import stdcall unsafe "Sleep" sleepBlock :: Int -> IO ()
+#else
+sleep n = sleepBlock n
+foreign import ccall unsafe "sleep" sleepBlock :: Int -> IO ()
+#endif
+
+main :: IO ()
+main = do
+ newStablePtr stdout -- prevent stdout being finalized, sigh
+ th <- newEmptyMVar
+ forkIO $ do
+ putStrLn "newThread started"
+ sleep 1
+ putMVar th "child"
+ threadDelay 500000
+ yield -- another hack, just in case child yields right after "sleep 1"
+ putMVar th "main" `catch` (\BlockedIndefinitelyOnMVar -> return ())
+ -- tests that the other thread doing an unsafe call to
+ -- sleep(3) has blocked this thread. Not sure if this
+ -- is a useful test.
+ x <- takeMVar th
+ putStrLn x
+ putStrLn "\nshutting down"
diff --git a/testsuite/tests/concurrent/should_run/conc036.stdout b/testsuite/tests/concurrent/should_run/conc036.stdout
new file mode 100644
index 0000000000..d5fb94ff25
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc036.stdout
@@ -0,0 +1,4 @@
+newThread started
+child
+
+shutting down
diff --git a/testsuite/tests/concurrent/should_run/conc037.hs b/testsuite/tests/concurrent/should_run/conc037.hs
new file mode 100644
index 0000000000..7da76f5025
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc037.hs
@@ -0,0 +1,27 @@
+{-# OPTIONS_GHC -cpp #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
+module Main where
+
+import Control.Concurrent
+
+#ifdef mingw32_HOST_OS
+foreign import stdcall safe "Sleep" _sleepBlock :: Int -> IO ()
+sleepBlock n = _sleepBlock (n*1000)
+#else
+foreign import ccall safe "sleep" sleepBlock :: Int -> IO ()
+#endif
+
+main :: IO ()
+main = do
+ th <- newEmptyMVar
+ forkIO $ do
+ putStrLn "newThread started"
+ sleepBlock 1
+ putStrLn "newThread back again"
+ putMVar th "1 sec later"
+ threadDelay 200000 -- make sure the newly created thread is run.
+ putStrLn "mainThread"
+ x <- takeMVar th
+ putStrLn x
+ putStrLn "\nshutting down"
+
diff --git a/testsuite/tests/concurrent/should_run/conc037.stdout b/testsuite/tests/concurrent/should_run/conc037.stdout
new file mode 100644
index 0000000000..18c9f447f6
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc037.stdout
@@ -0,0 +1,6 @@
+newThread started
+mainThread
+newThread back again
+1 sec later
+
+shutting down
diff --git a/testsuite/tests/concurrent/should_run/conc038.hs b/testsuite/tests/concurrent/should_run/conc038.hs
new file mode 100644
index 0000000000..0cf82f3b24
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc038.hs
@@ -0,0 +1,37 @@
+{-# OPTIONS_GHC -cpp #-}
+{-# LANGUAGE ForeignFunctionInterface #-}
+module Main where
+
+import Control.Concurrent
+
+haskellFun :: Int -> IO ()
+haskellFun c = putStrLn ("Haskell: " ++ show c)
+
+foreign export ccall "hFun" haskellFun :: Int -> IO ()
+foreign import ccall safe "hFun" hFun :: Int -> IO ()
+
+#ifdef mingw32_HOST_OS
+foreign import stdcall safe "Sleep" _sleepBlock :: Int -> IO ()
+sleepBlock n = _sleepBlock (n*1000)
+#else
+foreign import ccall safe "sleep" sleepBlock :: Int -> IO ()
+#endif
+
+
+
+main :: IO ()
+main = do
+ th <- newEmptyMVar
+ forkIO $ do
+ putStrLn "newThread started"
+ sleepBlock 1
+ putStrLn "newThread back again"
+ putMVar th "1 sec later"
+ threadDelay 500000 >> putStrLn "mainThread"
+ -- this will not be blocked in the threaded RTS
+ forkIO $ (hFun 2)
+ -- neither will this
+ x <- takeMVar th
+ putStrLn x
+ putStrLn "\nshutting down"
+
diff --git a/testsuite/tests/concurrent/should_run/conc038.stdout b/testsuite/tests/concurrent/should_run/conc038.stdout
new file mode 100644
index 0000000000..21fc15c4e2
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc038.stdout
@@ -0,0 +1,7 @@
+newThread started
+mainThread
+Haskell: 2
+newThread back again
+1 sec later
+
+shutting down
diff --git a/testsuite/tests/concurrent/should_run/conc039.hs b/testsuite/tests/concurrent/should_run/conc039.hs
new file mode 100644
index 0000000000..dc5d181a31
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc039.hs
@@ -0,0 +1,31 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+import Foreign
+import System.Mem
+import Control.Concurrent
+
+foreign export ccall "performGC_" performGC' :: IO ()
+performGC' = do putMVar m (); yield; performGC
+
+foreign import ccall "performGC_" f :: IO ()
+
+{-# NOINLINE m #-}
+m = unsafePerformIO newEmptyMVar
+
+main = do
+ forkIO f
+ takeMVar m
+
+-- This tests for a bug in the garbage collector, whereby a main
+-- thread that has completed may be GC'd before its return value is
+-- propagated back to the caller of rts_evalIO().
+--
+-- The sequence we hope to create is:
+-- - main thread (1) forks off thread (2)
+-- - thread (2) invokes new main thread (3) via a 'safe' ccall
+-- - thread (3) yields to thread (1)
+-- - thread (1) completes, but cannot return yet because (3)
+-- is the current main thread (unless we
+-- are in SMP or RTS_SUPPORTS_THREADS mode)
+-- - thread (3) invokes a GC
+-- - thread (1) is GC'd, unless we're careful!
diff --git a/testsuite/tests/concurrent/should_run/conc040.hs b/testsuite/tests/concurrent/should_run/conc040.hs
new file mode 100644
index 0000000000..be3bfdb915
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc040.hs
@@ -0,0 +1,28 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+
+import Foreign
+import Data.IORef
+import Control.Concurrent
+import Control.Exception
+
+foreign import ccall "wrapper"
+ wrap :: IO () -> IO (FunPtr (IO ()))
+
+foreign import ccall "dynamic"
+ invoke :: FunPtr (IO ()) -> IO ()
+
+{-# NOINLINE m #-}
+m :: IORef ThreadId
+m = unsafePerformIO (newIORef (error "m"))
+
+main = do
+ id <- myThreadId
+ writeIORef m id
+ raise' <- wrap raise
+ invoke raise'
+
+raise = do
+ id <- readIORef m
+ me <- myThreadId
+ forkIO $ do threadDelay 10000; throwTo me (ErrorCall "timeout")
+ throwTo id (ErrorCall "kapow!")
diff --git a/testsuite/tests/concurrent/should_run/conc040.stderr b/testsuite/tests/concurrent/should_run/conc040.stderr
new file mode 100644
index 0000000000..d113a02a99
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc040.stderr
@@ -0,0 +1 @@
+conc040: timeout
diff --git a/testsuite/tests/concurrent/should_run/conc041.hs b/testsuite/tests/concurrent/should_run/conc041.hs
new file mode 100644
index 0000000000..8aec345b1c
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc041.hs
@@ -0,0 +1,9 @@
+module Main where
+
+import GHC.Conc
+
+-- Create a new TVar and never use it
+main = do
+ putStr "Before\n"
+ t <- atomically ( newTVar 42 )
+ putStr "After\n"
diff --git a/testsuite/tests/concurrent/should_run/conc041.stderr b/testsuite/tests/concurrent/should_run/conc041.stderr
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc041.stderr
diff --git a/testsuite/tests/concurrent/should_run/conc041.stdout b/testsuite/tests/concurrent/should_run/conc041.stdout
new file mode 100644
index 0000000000..a84f0c9779
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc041.stdout
@@ -0,0 +1,2 @@
+Before
+After
diff --git a/testsuite/tests/concurrent/should_run/conc042.hs b/testsuite/tests/concurrent/should_run/conc042.hs
new file mode 100644
index 0000000000..9ebbf3e4ea
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc042.hs
@@ -0,0 +1,11 @@
+module Main where
+
+import GHC.Conc
+
+-- Create a new TVar and check that it contains the expected value
+main = do
+ putStr "Before\n"
+ t <- atomically ( newTVar 42 )
+ r <- atomically ( readTVar t )
+ putStr ("After " ++ (show r) ++ "\n")
+
diff --git a/testsuite/tests/concurrent/should_run/conc042.stderr b/testsuite/tests/concurrent/should_run/conc042.stderr
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc042.stderr
diff --git a/testsuite/tests/concurrent/should_run/conc042.stdout b/testsuite/tests/concurrent/should_run/conc042.stdout
new file mode 100644
index 0000000000..6fea5e3fe9
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc042.stdout
@@ -0,0 +1,2 @@
+Before
+After 42
diff --git a/testsuite/tests/concurrent/should_run/conc043.hs b/testsuite/tests/concurrent/should_run/conc043.hs
new file mode 100644
index 0000000000..18cf1196f7
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc043.hs
@@ -0,0 +1,13 @@
+module Main where
+
+import GHC.Conc
+
+-- Create a new TVar, update it and check that it contains the expected value after the
+-- transaction
+main = do
+ putStr "Before\n"
+ t <- atomically ( newTVar 42 )
+ atomically ( writeTVar t 17 )
+ r <- atomically ( readTVar t )
+ putStr ("After " ++ (show r) ++ "\n")
+
diff --git a/testsuite/tests/concurrent/should_run/conc043.stderr b/testsuite/tests/concurrent/should_run/conc043.stderr
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc043.stderr
diff --git a/testsuite/tests/concurrent/should_run/conc043.stdout b/testsuite/tests/concurrent/should_run/conc043.stdout
new file mode 100644
index 0000000000..8b2ff8961d
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc043.stdout
@@ -0,0 +1,2 @@
+Before
+After 17
diff --git a/testsuite/tests/concurrent/should_run/conc044.hs b/testsuite/tests/concurrent/should_run/conc044.hs
new file mode 100644
index 0000000000..0ad4701f8b
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc044.hs
@@ -0,0 +1,13 @@
+module Main where
+
+import GHC.Conc
+
+-- Create a new TVar, update it and check that it contains the expected value within
+-- the transaction
+main = do
+ putStr "Before\n"
+ t <- atomically ( newTVar 42 )
+ r <- atomically ( do writeTVar t 17
+ readTVar t)
+ putStr ("After " ++ (show r) ++ "\n")
+
diff --git a/testsuite/tests/concurrent/should_run/conc044.stderr b/testsuite/tests/concurrent/should_run/conc044.stderr
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc044.stderr
diff --git a/testsuite/tests/concurrent/should_run/conc044.stdout b/testsuite/tests/concurrent/should_run/conc044.stdout
new file mode 100644
index 0000000000..8b2ff8961d
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc044.stdout
@@ -0,0 +1,2 @@
+Before
+After 17
diff --git a/testsuite/tests/concurrent/should_run/conc045.hs b/testsuite/tests/concurrent/should_run/conc045.hs
new file mode 100644
index 0000000000..4ab585eef3
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc045.hs
@@ -0,0 +1,39 @@
+module Main where
+
+import GHC.Conc
+import Control.Concurrent
+
+snapshot t1 t2 = atomically ( do v1 <- readTVar t1
+ v2 <- readTVar t2
+ return (v1, v2) )
+
+twiddle mv _ _ 0 = putMVar mv ()
+twiddle mv t1 t2 n = do atomically ( do v1 <- readTVar t1
+ v2 <- readTVar t2
+ writeTVar t2 (v1+1)
+ writeTVar t1 (v2+1) )
+ twiddle mv t1 t2 (n-1)
+
+
+-- Contended updates to a pair of TVars
+main = do
+ putStr "Before\n"
+ (t1,t2) <- atomically ( do t1 <- newTVar 0
+ t2 <- newTVar 1
+ return (t1, t2))
+
+ -- MVars used to signal completion
+ t1c <- newEmptyMVar
+ t2c <- newEmptyMVar
+
+ forkIO (twiddle t1c t1 t2 1000)
+ forkIO (twiddle t2c t1 t2 1000)
+
+ -- Wait for threads to exit
+ takeMVar t1c
+ takeMVar t2c
+
+ -- Display final state
+ (r1,r2) <- snapshot t1 t2
+ putStr ("After " ++ (show r1) ++ " , " ++ (show r2) ++ "\n")
+
diff --git a/testsuite/tests/concurrent/should_run/conc045.stderr b/testsuite/tests/concurrent/should_run/conc045.stderr
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc045.stderr
diff --git a/testsuite/tests/concurrent/should_run/conc045.stdout b/testsuite/tests/concurrent/should_run/conc045.stdout
new file mode 100644
index 0000000000..31640611f4
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc045.stdout
@@ -0,0 +1,2 @@
+Before
+After 2000 , 2001
diff --git a/testsuite/tests/concurrent/should_run/conc051.hs b/testsuite/tests/concurrent/should_run/conc051.hs
new file mode 100644
index 0000000000..db8a796a9c
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc051.hs
@@ -0,0 +1,32 @@
+module Main (main) where
+
+import System.Environment
+import Control.Concurrent
+import Control.Monad
+
+-----------------------------------------------------------------------------
+-- test MVar throughput between the main thread and a child thread
+
+-- This test runs quite slowly on the threaded/SMP RTS vs. the normal RTS,
+-- because the main thread and child thread are run by different OS threads,
+-- so each MVar communication requires real OS thread switching.
+--
+-- Figures I get are about a factor of 10 difference in speed, at GHC 6.5.
+
+main = chanTest 300000
+
+chanTest :: Int -> IO ()
+chanTest n = do
+ chan <- newEmptyMVar
+ forkIO (writer chan n)
+ reader chan n
+
+reader chan 0 = return ()
+reader chan n = do
+ takeMVar chan
+ reader chan (n-1)
+
+writer chan 0 = return ()
+writer chan n = do
+ putMVar chan ()
+ writer chan (n-1)
diff --git a/testsuite/tests/concurrent/should_run/conc058.hs b/testsuite/tests/concurrent/should_run/conc058.hs
new file mode 100644
index 0000000000..5fbe4e5af8
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc058.hs
@@ -0,0 +1,13 @@
+import Control.Concurrent
+import Control.Exception
+
+-- variation on conc020 that tests for threadDelay being interruptible.
+-- On Windows, with the threaded RTS, in 6.6 and earlier, threadDelay is
+-- not interruptible.
+main = do
+ m <- newEmptyMVar
+ t <- forkIO (block $ threadDelay 1000000)
+ threadDelay 100000
+ throwTo t (ErrorCall "I'm Interruptible")
+ threadDelay 100000
+ putMVar m () -- to avoid t being garbage collected
diff --git a/testsuite/tests/concurrent/should_run/conc058.stderr b/testsuite/tests/concurrent/should_run/conc058.stderr
new file mode 100644
index 0000000000..2b5ddd02dc
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc058.stderr
@@ -0,0 +1 @@
+conc058: I'm Interruptible
diff --git a/testsuite/tests/concurrent/should_run/conc059.hs b/testsuite/tests/concurrent/should_run/conc059.hs
new file mode 100644
index 0000000000..bed28d27cb
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc059.hs
@@ -0,0 +1,26 @@
+{-# LANGUAGE CPP, ForeignFunctionInterface #-}
+module Test where
+
+import Control.Concurrent
+import Control.Monad
+import Foreign.C
+
+-- See also conc059_c.c
+--
+-- This test fires off some threads that will return after the RTS has
+-- shut down. This should not crash or confuse the RTS.
+
+f :: Int -> IO ()
+f x = do
+ print x
+ replicateM_ 10 $ forkIO $ do usleep (fromIntegral x); putStrLn "hello"
+ return ()
+
+foreign export ccall "f" f :: Int -> IO ()
+
+#ifdef mingw32_HOST_OS
+foreign import stdcall safe "Sleep" _sleep :: Int -> IO ()
+usleep n = _sleep (n `quot` 1000)
+#else
+foreign import ccall safe "usleep" usleep :: Int -> IO ()
+#endif
diff --git a/testsuite/tests/concurrent/should_run/conc059.stdout b/testsuite/tests/concurrent/should_run/conc059.stdout
new file mode 100644
index 0000000000..92911bfda2
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc059.stdout
@@ -0,0 +1,2 @@
+exiting...
+exited.
diff --git a/testsuite/tests/concurrent/should_run/conc059_c.c b/testsuite/tests/concurrent/should_run/conc059_c.c
new file mode 100644
index 0000000000..f15fbdd735
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc059_c.c
@@ -0,0 +1,30 @@
+#include "HsFFI.h"
+#include "conc059_stub.h"
+#include <unistd.h>
+#include <stdio.h>
+#if mingw32_HOST_OS
+#include <windows.h>
+#endif
+
+void __stginit_Test(void);
+
+int main(int argc, char *argv[])
+{
+ hs_init(&argc,&argv);
+ hs_add_root(__stginit_Test);
+ f(500000);
+#if mingw32_HOST_OS
+ Sleep(100);
+#else
+ usleep(100000);
+#endif
+ printf("exiting...\n");
+ hs_exit();
+ printf("exited.\n");
+#if mingw32_HOST_OS
+ Sleep(1000);
+#else
+ usleep(1000000);
+#endif
+ exit(0);
+}
diff --git a/testsuite/tests/concurrent/should_run/conc064.hs b/testsuite/tests/concurrent/should_run/conc064.hs
new file mode 100644
index 0000000000..d37387c601
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc064.hs
@@ -0,0 +1,30 @@
+-- test for bug #1067
+
+import Control.Concurrent
+import Control.Exception
+
+main = do
+ master <- myThreadId
+ test master 10
+ -- make sure we catch a final NonTermination exception to get
+ -- a consistent result.
+ threadDelay (10 * one_second)
+
+test tid 0 = return ()
+test tid n = do
+ e <- try threads
+ case e of
+ Left NonTermination -> test tid (n-1)
+ Right _ -> return ()
+ where
+ threads = do sequence $ replicate 3 $
+ forkIO $ do t <- myThreadId
+ --putStrLn ("Start " ++ show t)
+ threadDelay one_second
+ --putStrLn ("End " ++ show t)
+ throwTo tid NonTermination
+ --putStrLn ("Thrown " ++ show t)
+ threadDelay (10 * one_second)
+
+one_second :: Int
+one_second = 100000
diff --git a/testsuite/tests/concurrent/should_run/conc064.stderr b/testsuite/tests/concurrent/should_run/conc064.stderr
new file mode 100644
index 0000000000..9a49972f77
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc064.stderr
@@ -0,0 +1 @@
+conc064: <<loop>>
diff --git a/testsuite/tests/concurrent/should_run/conc065.hs b/testsuite/tests/concurrent/should_run/conc065.hs
new file mode 100644
index 0000000000..db6d7cf3ba
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc065.hs
@@ -0,0 +1,13 @@
+-- Test for bug #1047
+
+import Control.Concurrent
+import Control.Exception
+
+-- This loop spends most of its time printing stuff, and very occasionally
+-- pops outside 'block'. This test ensures that an thread trying to
+-- throwTo this thread will eventually succeed.
+loop = block (print "alive") >> loop
+
+main = do tid <- forkIO loop
+ threadDelay 1
+ killThread tid
diff --git a/testsuite/tests/concurrent/should_run/conc066.hs b/testsuite/tests/concurrent/should_run/conc066.hs
new file mode 100644
index 0000000000..81638dfd10
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc066.hs
@@ -0,0 +1,13 @@
+-- Test for bug #1047
+
+import Control.Concurrent
+import Control.Exception
+
+-- This loop spends most of its time printing stuff, and very occasionally
+-- executes 'unblock (return ())'. This test ensures that a thread waiting
+-- to throwTo this thread is not blocked indefinitely.
+loop = do unblock (return ()); print "alive"; loop
+
+main = do tid <- forkIO (block loop)
+ yield
+ killThread tid
diff --git a/testsuite/tests/concurrent/should_run/conc067.hs b/testsuite/tests/concurrent/should_run/conc067.hs
new file mode 100644
index 0000000000..ef6dde3ff7
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc067.hs
@@ -0,0 +1,16 @@
+-- Test for bug #418
+
+module Main where
+
+import Control.Concurrent
+import System.IO.Unsafe (unsafeInterleaveIO)
+
+main = do
+ v <- newEmptyMVar
+ a <- unsafeInterleaveIO (readMVar v)
+ t <- forkIO (print a)
+ threadDelay (100*1000)
+ killThread t
+ forkIO $ print a
+ putMVar v ()
+
diff --git a/testsuite/tests/concurrent/should_run/conc068.hs b/testsuite/tests/concurrent/should_run/conc068.hs
new file mode 100644
index 0000000000..eb90d06591
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc068.hs
@@ -0,0 +1,14 @@
+import Control.Concurrent
+import Control.Exception
+import GHC.Conc
+
+-- test forkBlockIO
+main = do
+ main_thread <- myThreadId
+ m <- newEmptyMVar
+ sub_thread <- block $ forkIO $
+ sum [1..100000] `seq`
+ throwTo main_thread (ErrorCall "foo")
+ killThread sub_thread
+ putStrLn "oops"
+
diff --git a/testsuite/tests/concurrent/should_run/conc068.stderr b/testsuite/tests/concurrent/should_run/conc068.stderr
new file mode 100644
index 0000000000..bf40dfdd92
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc068.stderr
@@ -0,0 +1 @@
+conc068: foo
diff --git a/testsuite/tests/concurrent/should_run/conc069.hs b/testsuite/tests/concurrent/should_run/conc069.hs
new file mode 100644
index 0000000000..fd757133a5
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc069.hs
@@ -0,0 +1,19 @@
+import Control.Concurrent
+import Control.Exception
+
+main = do
+ -- stat -- main thread is not bound in GHCi
+ m <- newEmptyMVar
+ forkIO (do stat; putMVar m ())
+ takeMVar m
+ block $ forkIO (do stat; putMVar m ())
+ takeMVar m
+ forkOS (do stat; putMVar m ())
+ takeMVar m
+ block $ forkOS (do stat; putMVar m ())
+ takeMVar m
+
+stat = do
+ x <- isCurrentThreadBound
+ y <- blocked
+ print (x,y)
diff --git a/testsuite/tests/concurrent/should_run/conc069.stdout b/testsuite/tests/concurrent/should_run/conc069.stdout
new file mode 100644
index 0000000000..240e16e63f
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc069.stdout
@@ -0,0 +1,4 @@
+(False,False)
+(False,True)
+(True,False)
+(True,True)
diff --git a/testsuite/tests/concurrent/should_run/conc069a.hs b/testsuite/tests/concurrent/should_run/conc069a.hs
new file mode 100644
index 0000000000..5bf619bec1
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc069a.hs
@@ -0,0 +1,19 @@
+import Control.Concurrent
+import Control.Exception
+
+main = do
+ -- stat -- main thread is not bound in GHCi
+ m <- newEmptyMVar
+ forkIO (do stat; putMVar m ())
+ takeMVar m
+ mask_ $ forkIO (do stat; putMVar m ())
+ takeMVar m
+ forkOS (do stat; putMVar m ())
+ takeMVar m
+ mask_ $ forkOS (do stat; putMVar m ())
+ takeMVar m
+
+stat = do
+ x <- isCurrentThreadBound
+ y <- getMaskingState
+ print (x,y)
diff --git a/testsuite/tests/concurrent/should_run/conc069a.stdout b/testsuite/tests/concurrent/should_run/conc069a.stdout
new file mode 100644
index 0000000000..0883f133dc
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc069a.stdout
@@ -0,0 +1,4 @@
+(False,Unmasked)
+(False,MaskedInterruptible)
+(True,Unmasked)
+(True,MaskedInterruptible)
diff --git a/testsuite/tests/concurrent/should_run/conc070.hs b/testsuite/tests/concurrent/should_run/conc070.hs
new file mode 100644
index 0000000000..71eb415427
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc070.hs
@@ -0,0 +1,18 @@
+import Control.Concurrent
+import GHC.Conc
+import Data.List
+import Data.Maybe
+
+main = do
+ t1 <- forkIO (threadDelay 100000000)
+ m <- newEmptyMVar
+ t2 <- forkIO (takeMVar m)
+ t3 <- forkIO (let loop = do r <- tryTakeMVar m;
+ _ <- newEmptyMVar -- do some allocation :(
+ if isNothing r then loop else return ()
+ in loop)
+ t4 <- forkIO (return ())
+ yield
+ threadDelay 10000
+ print =<< mapM threadStatus [t1,t2,t3,t4]
+ putMVar m ()
diff --git a/testsuite/tests/concurrent/should_run/conc070.stdout b/testsuite/tests/concurrent/should_run/conc070.stdout
new file mode 100644
index 0000000000..30f0076668
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc070.stdout
@@ -0,0 +1 @@
+[ThreadBlocked BlockedOnMVar,ThreadBlocked BlockedOnMVar,ThreadRunning,ThreadFinished]
diff --git a/testsuite/tests/concurrent/should_run/conc071.hs b/testsuite/tests/concurrent/should_run/conc071.hs
new file mode 100644
index 0000000000..7c58efbc9f
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc071.hs
@@ -0,0 +1,11 @@
+module Main where
+
+import Control.Concurrent
+
+main = do
+ t <- forkIO (return ())
+ threadCapability t >>= print
+ t <- forkOn 0 (return ())
+ threadCapability t >>= print
+ t <- forkOn 1 (return ())
+ threadCapability t >>= print
diff --git a/testsuite/tests/concurrent/should_run/conc071.stdout b/testsuite/tests/concurrent/should_run/conc071.stdout
new file mode 100644
index 0000000000..9933b254fe
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc071.stdout
@@ -0,0 +1,3 @@
+(0,False)
+(0,True)
+(0,True)
diff --git a/testsuite/tests/concurrent/should_run/conc072.hs b/testsuite/tests/concurrent/should_run/conc072.hs
new file mode 100644
index 0000000000..8f1218084c
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc072.hs
@@ -0,0 +1,9 @@
+module Main where
+
+import Control.Concurrent
+
+main = do
+ t <- forkOn 0 (return ())
+ threadCapability t >>= print
+ t <- forkOn 1 (return ())
+ threadCapability t >>= print
diff --git a/testsuite/tests/concurrent/should_run/conc072.stdout b/testsuite/tests/concurrent/should_run/conc072.stdout
new file mode 100644
index 0000000000..739ac3797e
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/conc072.stdout
@@ -0,0 +1,2 @@
+(0,True)
+(1,True)
diff --git a/testsuite/tests/concurrent/should_run/foreignInterruptible.hs b/testsuite/tests/concurrent/should_run/foreignInterruptible.hs
new file mode 100644
index 0000000000..32252fb8db
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/foreignInterruptible.hs
@@ -0,0 +1,32 @@
+{-# LANGUAGE ForeignFunctionInterface #-}
+{-# OPTIONS -cpp #-}
+module Main where
+
+import Control.Concurrent
+import Control.Exception
+import Prelude hiding (catch)
+import Foreign
+import System.IO
+
+#ifdef mingw32_HOST_OS
+sleep n = sleepBlock (n*1000)
+foreign import stdcall interruptible "Sleep" sleepBlock :: Int -> IO ()
+#else
+sleep n = sleepBlock n
+foreign import ccall interruptible "sleep" sleepBlock :: Int -> IO ()
+#endif
+
+main :: IO ()
+main = do
+ newStablePtr stdout -- prevent stdout being finalized
+ th <- newEmptyMVar
+ tid <- forkIO $ do
+ putStrLn "newThread started"
+ (sleep 2 >> putStrLn "fail") `catch` (\ThreadKilled -> putStrLn "pass")
+ putMVar th "child"
+ yield
+ threadDelay 500000
+ killThread tid
+ x <- takeMVar th
+ putStrLn x
+ putStrLn "\nshutting down"
diff --git a/testsuite/tests/concurrent/should_run/foreignInterruptible.stdout b/testsuite/tests/concurrent/should_run/foreignInterruptible.stdout
new file mode 100644
index 0000000000..4048ae362e
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/foreignInterruptible.stdout
@@ -0,0 +1,5 @@
+newThread started
+pass
+child
+
+shutting down
diff --git a/testsuite/tests/concurrent/should_run/mask001.hs b/testsuite/tests/concurrent/should_run/mask001.hs
new file mode 100644
index 0000000000..96bbf53c73
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/mask001.hs
@@ -0,0 +1,70 @@
+import Control.Exception
+import Text.Printf
+
+-- Test all the various combinations of nesting mask/uninterruptibleMask
+
+main = do
+ stat 1 Unmasked
+ mask_ $ stat 2 MaskedInterruptible
+ mask $ \restore -> do
+ stat 3 MaskedInterruptible
+ restore $ stat 4 Unmasked
+ restore $ restore $ stat 5 Unmasked
+ stat 6 MaskedInterruptible
+ uninterruptibleMask $ \restore -> do
+ stat 7 MaskedUninterruptible
+ restore $ stat 8 MaskedInterruptible
+ restore $ restore $ stat 9 MaskedInterruptible
+ stat 10 MaskedUninterruptible
+ mask $ \restore -> do
+ stat 11 MaskedUninterruptible
+ restore $ stat 12 MaskedUninterruptible
+ restore $ restore $ stat 13 MaskedUninterruptible
+ stat 14 MaskedUninterruptible
+ stat 15 MaskedUninterruptible
+ stat 16 MaskedInterruptible
+ stat 17 Unmasked
+
+ uninterruptibleMask $ \restore -> do
+ stat 20 MaskedUninterruptible
+ restore $ stat 21 Unmasked
+ restore $ restore $ stat 22 Unmasked
+ stat 23 MaskedUninterruptible
+ mask $ \restore -> do
+ stat 24 MaskedUninterruptible
+ restore $ stat 25 MaskedUninterruptible
+ restore $ restore $ stat 26 MaskedUninterruptible
+ stat 27 MaskedUninterruptible
+ uninterruptibleMask $ \restore -> do
+ stat 28 MaskedUninterruptible
+ restore $ stat 29 MaskedUninterruptible
+ restore $ restore $ stat 30 MaskedUninterruptible
+ stat 31 MaskedUninterruptible
+ stat 32 MaskedUninterruptible
+ stat 33 MaskedUninterruptible
+ stat 34 Unmasked
+
+ -- it is possible to call a restore from a mask that is not the
+ -- innermost enclosing one, although this is not a recommended use
+ -- of the API.
+ mask $ \restore0 -> do
+ stat 41 MaskedInterruptible
+ -- it is possible to call a restore from a mask that is not the
+ uninterruptibleMask $ \restore1 -> do
+ stat 42 MaskedUninterruptible
+ restore0 $ stat 43 Unmasked
+ restore0 $ restore0 $ stat 44 Unmasked
+ restore1 $ stat 45 MaskedInterruptible
+ restore1 $ restore1 $ stat 46 MaskedInterruptible
+ restore0 $ restore1 $ stat 47 MaskedInterruptible
+ restore1 $ restore0 $ stat 48 Unmasked
+ stat 49 MaskedUninterruptible
+ stat 50 MaskedInterruptible
+ stat 51 Unmasked
+
+stat :: Int -> MaskingState -> IO ()
+stat n m = do
+ s <- getMaskingState
+ if (s /= m)
+ then error (printf "%2d: %s\n" n (show s))
+ else return ()
diff --git a/testsuite/tests/concurrent/should_run/mask002.hs b/testsuite/tests/concurrent/should_run/mask002.hs
new file mode 100644
index 0000000000..15b2e64a00
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/mask002.hs
@@ -0,0 +1,32 @@
+import Control.Exception
+import Control.Concurrent
+import Text.Printf
+import Prelude hiding(catch)
+
+-- Test combinations of nesting mask/uninterruptibleMask with
+-- forkIO/forkIOUnmask
+
+main = do
+ m <- newEmptyMVar
+ t1 <- mask_ $ forkIO $ do
+ takeMVar m `catch` \e -> do stat 1 MaskedInterruptible
+ print (e::SomeException)
+ throwIO e
+ killThread t1
+ t2 <- uninterruptibleMask_ $ forkIO $ do
+ takeMVar m `catch` \e -> do stat 2 MaskedUninterruptible
+ print (e::SomeException)
+ throwIO e
+ killThread t2
+ t3 <- mask_ $ forkIOUnmasked $ do stat 3 Unmasked; putMVar m ()
+ takeMVar m
+ t4 <- uninterruptibleMask_ $ forkIOUnmasked $ do stat 4 Unmasked; putMVar m ()
+ takeMVar m
+
+stat :: Int -> MaskingState -> IO ()
+stat n m = do
+ s <- getMaskingState
+ if (s /= m)
+ then error (printf "%2d: %s\n" n (show s))
+ else return ()
+
diff --git a/testsuite/tests/concurrent/should_run/mask002.stdout b/testsuite/tests/concurrent/should_run/mask002.stdout
new file mode 100644
index 0000000000..baa1975a5a
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/mask002.stdout
@@ -0,0 +1,2 @@
+thread killed
+thread blocked indefinitely in an MVar operation
diff --git a/testsuite/tests/concurrent/should_run/numsparks001.hs b/testsuite/tests/concurrent/should_run/numsparks001.hs
new file mode 100644
index 0000000000..f28bf87d55
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/numsparks001.hs
@@ -0,0 +1,11 @@
+
+import GHC.Conc
+
+main = do
+ let x = length [1..100]
+ numSparks >>= print
+ x `par` numSparks >>= print
+ x `par` numSparks >>= print
+ x `par` numSparks >>= print
+ x `par` numSparks >>= print
+
diff --git a/testsuite/tests/concurrent/should_run/numsparks001.stdout b/testsuite/tests/concurrent/should_run/numsparks001.stdout
new file mode 100644
index 0000000000..9dfcf39f5a
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/numsparks001.stdout
@@ -0,0 +1,5 @@
+0
+1
+2
+3
+4
diff --git a/testsuite/tests/concurrent/should_run/throwto001.hs b/testsuite/tests/concurrent/should_run/throwto001.hs
new file mode 100644
index 0000000000..999d3335d8
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/throwto001.hs
@@ -0,0 +1,38 @@
+import Control.Concurrent
+import Control.Exception
+import Data.Array
+import System.Random
+import System.Environment
+import Control.Monad
+import GHC.Conc
+
+-- A fiendish throwTo test. A bunch of threads take random MVars from
+-- a shared array; if the MVar has Nothing in it, replace it with Just
+-- of the current thread's ThreadId. If the MVar has another ThreadId
+-- in it, then killThread that thread, and replace it with the current
+-- thread's ThreadId. We keep going until only one thread is left
+-- standing.
+--
+-- On multiple CPUs this should give throwTo a good workout.
+--
+main = do
+ [m, t] <- fmap (fmap read) getArgs
+ ms <- replicateM m $ newMVar Nothing
+ let arr = listArray (1,m) ms
+ dead <- newTVarIO 0
+ ts <- replicateM t $ forkIO (thread m arr `onException`
+ (atomically $ do d <- readTVar dead
+ writeTVar dead $! d+1))
+ atomically $ do
+ d <- readTVar dead
+ when (d < t-1) $ retry
+
+thread m arr = do
+ x <- randomIO
+ id <- myThreadId
+ modifyMVar_ (arr ! ((x `mod` m) + 1)) $ \b ->
+ case b of
+ Nothing -> return (Just id)
+ Just other -> do when (other /= id) $ killThread other
+ return (Just id)
+ thread m arr
diff --git a/testsuite/tests/concurrent/should_run/throwto002.hs b/testsuite/tests/concurrent/should_run/throwto002.hs
new file mode 100644
index 0000000000..c9857f1f1e
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/throwto002.hs
@@ -0,0 +1,25 @@
+{-# LANGUAGE DoRec, ScopedTypeVariables #-}
+import Control.Concurrent
+import Control.Exception
+import Data.Array
+import System.Random
+import System.Environment
+import Control.Monad
+import GHC.Conc
+import Data.IORef
+import Prelude hiding (catch)
+
+main = do
+ r <- newIORef 0
+ rec
+ t1 <- block $ forkIO (thread r t2)
+ t2 <- block $ forkIO (thread r t1)
+ threadDelay 1000000
+ readIORef r >>= print
+
+thread r t = run
+ where
+ run = (unblock $ forever $ do killThread t
+ i <- atomicModifyIORef r (\i -> (i + 1, i))
+ evaluate i)
+ `catch` \(e::SomeException) -> run
diff --git a/testsuite/tests/concurrent/should_run/throwto003.hs b/testsuite/tests/concurrent/should_run/throwto003.hs
new file mode 100644
index 0000000000..6369c62352
--- /dev/null
+++ b/testsuite/tests/concurrent/should_run/throwto003.hs
@@ -0,0 +1,17 @@
+{-# LANGUAGE DoRec, ScopedTypeVariables #-}
+import Control.Concurrent
+import Control.Exception
+import Control.Monad
+import Prelude hiding (catch)
+
+main = do
+ m <- newMVar 1
+ t1 <- forkIO $ thread m
+ t2 <- forkIO $ forever $ killThread t1
+ threadDelay 1000000
+ takeMVar m
+
+thread m = run
+ where
+ run = (unblock $ forever $ modifyMVar_ m $ \v -> if v `mod` 2 == 1 then return (v*2) else return (v-1))
+ `catch` \(e::SomeException) -> run