content: import Control.Concurrent.QSem as OldQ
  
  import Control.Concurrent.Chan
  import Control.Concurrent (forkIO, threadDelay, killThread, yield)
  import Control.Concurrent.MVar
  import Control.Exception
  import Control.Monad
  
  new = newQSem
  wait = waitQSem
  signal = signalQSem
  
  --------
  -- dummy test-framework
  
  type Assertion = IO ()
  
  x @?= y = when (x /= y) $ error (show x ++ " /= " ++ show y)
  
  testCase :: String -> IO () -> IO ()
  testCase n io = putStrLn ("test " ++ n) >> io
  
  defaultMain = sequence
  ------
  
  main = defaultMain tests
  
  tests = [
      testCase "sem1" sem1,
      testCase "sem2" sem2,
      testCase "sem_kill" sem_kill,
      testCase "sem_fifo" sem_fifo,
      testCase "sem_bracket" sem_bracket
   ]
  
  sem1 :: Assertion
  sem1 = do
    q <- new 0
    signal q
    wait q
  
  sem2 :: Assertion
  sem2 = do
    q <- new 0
    signal q
    signal q
    wait q
    wait q
  
  sem_fifo :: Assertion
  sem_fifo = do
    c <- newChan
    q <- new 0
    t1 <- forkIO $ do wait q; writeChan c 'a'
    threadDelay 10000
    t2 <- forkIO $ do wait q; writeChan c 'b'
    threadDelay 10000
    t3 <- forkIO $ do wait q; writeChan c 'c'
    threadDelay 10000
    signal q
    a <- readChan c
    signal q
    b <- readChan c
    signal q
    c <- readChan c
    [a,b,c] @?= "abc"
  
  sem_kill :: Assertion
  sem_kill  = do
    q <- new 0
    t <- forkIO $ wait q
    threadDelay 100000
    killThread t
    m <- newEmptyMVar
    t <- forkIO $ do wait q; putMVar m ()
    signal q
    takeMVar m
  
  
  sem_bracket :: Assertion
  sem_bracket = do
    q <- new 1
    ts <- forM [1..100000] $ \n ->
       forkIO $ bracket_ (wait q) (signal q) (return ())
    mapM_ killThread ts
    wait q
  
  