{-# OPTIONS -fglasgow-exts #-}
-- Eden Project, JB

-- Base module, importing PrimOps => exporting IO actions
-----------------------------------------------

module ParPrim 
    where

import GHC.Base
import GHC.IOBase

----------------------------------------------------------
-- IO wrappers for primitive operations:
--
-- all primitives are implemented out-of-line,
-- wrappers should all be of type * -> IO (...)
--
-- (eden implementation can work with unsafePerformIO)
---------

-- system information
{-# NOINLINE noPe #-}
noPe :: IO Int
noPe = IO ( \s -> case (noPe# s) of 
	               (# s',r #) -> (# s',I# r #)
	  )
{-# NOINLINE selfPe #-}
selfPe :: IO Int
selfPe = IO ( \s -> case (selfPe# s) of 
	                 (# s',r #) -> (# s',I# r #)
	    )

-- not for export, only abstract type visible outside
data ChanName' a = Chan Int# Int# Int#
                deriving Show

-- tweaking fork primop from concurrent haskell... (not returning threadID)
{-# NOINLINE fork #-}
fork :: IO () -> IO ()
fork action = IO (\s -> case (fork# action s) of 
                          (# s' , _ #) -> (# s' , () #)
                 )

-- creation of one placeholder and one new inport
{-# NOINLINE createC #-}
createC :: IO ( ChanName' a, a )
createC = IO (\s -> case (expectData# s) of 
                     (# s',id,p, bh #) -> case selfPe# s' of
                                            (# s'', pe #) ->
                                                (# s',(Chan pe p id, bh) #)
             )

-- TODO: wrap creation of several channels in RTS? (see eden5::createDC# )
--       (would save foreign call overhead, but hard-wire more into RTS)

{-# NOINLINE connectToPort #-}
connectToPort_ :: Int# -> Int# -> Int# -> IO ()
connectToPort_ pe proc id 
    = IO (\s -> case (connectToPort# pe proc id s) of
	                   s' -> (# s', () #)
	 )

connectToPort :: ChanName' a -> IO ()
connectToPort (Chan p proc id) = connectToPort_ p proc id

{- send modes implemented: 
       1 - connect (no graph needed)
       2 - stream  (list element)
       3 - single  (single value)
       4 - rFork   (receiver creates a thread, different ports)
 and additional payload (currently for rFork only) in high bits
-}
-- send modes for sendData
data Mode = Connect 
	  | Data
	  | Stream
	  | Instantiate Int

{-# NOINLINE sendData #-}
sendData :: Mode -> a -> IO ()
sendData mode d 
    = IO (\s -> case (sendData# m d s) of 
	                   s' -> (# s', () #)
	 )
      where (I# m) = decodeMode mode
	    decodeMode :: Mode -> Int
	    decodeMode Connect         = 1
	    decodeMode Data            = 2
	    decodeMode Stream          = 3
	    decodeMode (Instantiate _) = 4
	    decodeMode _ = error "sendData: no such mode"
