[Haskell-cafe] Yet another top-level IO proposal
Robert Dockins
robdockins at fastmail.fm
Tue Jan 17 20:44:39 EST 2006
> Hello,
>
> Well it seems like you haven't started another flame war (yet :-).
Indeed; I am a little surprised to hear the silence.
> I'm afraid I haven't properly understood your proposal, because I
> don't have much time right now. It seems to be a bit like George
> Russels proposal (aka "execution contexts").
Somewhat. However, execution contexts don't have the initializer concept.
> Personally I have never felt the need for thread local state, but
> I have often needed to use the unsafePerformIO hack to create
> *unique state* for API's that are both sane from a users point of
> view and are also invulnerable to accidental or malicious state
> "spoofing". So thread local state isn't really what I want (it's
> a sure way to guarantee that spoofing will occur :-)
>
> You seem to indicate that this is still possible with your scheme,
> but I'm not sure of the details.
If you declare a thread-local in a module but don't export it, then you have
exclusive control over what happens to that thread-local. You set the
initializer and no one else can touch it. If you set an initializer that
copies parent values and never write to the cell, you effectively have a
variable that is set exactly once at program start.
The only way to alter this from outside the module is to use the "clearBank"
primitive, which resets all thread-locals to empty. It may be that this
primitive is too dangerous to include.
On the other hand, I'm not convinced that absolutely unique state is that
great. Suppose I want to run multiple copies of my Haskell OS in an emulator
so I can test the TCP/IP stack I just wrote? I'll need some way to keep the
"unique" state for each OS separate.
> Maybe you should put all this
> on the wiki page. I'd like to see how/if you could implement
> the hypothetical device driver API I put there, or even just
> use the "oneShot" function or similar at the top level.
I've attached a hypothetical implementation in the proposed syntax.
> Regards
> --
> Adrian Hey
Robert Dockins
-------------- next part --------------
module FictionalDevice
( device1
, device2
, DeviceHandle
, initDevice
, someDeviceAction
)
import Control.Concurrent
import Control.Concurrent.MVar
type BaseAddress = ...
data DeviceState =
DeviceState
{ isFirstAccess :: Bool
, baseAddress :: BaseAddress
, ...
}
initialDeviceState :: BaseAddress -> DeviceState
initialDeviceState addr = DeviceState
{ isFirstAccess = True
, baseAddress = addr
, ...
}
device1baseAddresss :: BaseAddress
device1baseAddress = ...
device2baseAddresss :: BaseAddress
device2baseAddress = ...
threadlocal device1state (MVar DeviceState)
(initTL (newMVarTL (initialDeviceState device1baseAddress)))
threadlocal device2state (MVar DeviceState)
(initTL (newMVarTL (initialDeviceState device2baseAddress)))
newtype DeviceHandle = DH (TLRef (MVar DeviceState))
device1 = DH device1state
device2 = DH device2state
doInitDevice :: BaseAddress -> IO ()
doInitDevice addr = ...
initDevice :: DeviceHandle -> IO ()
initDevice (DH ref) = do
stMvar <- readThreadLocal ref
modifyMVar_ stMVar (\st -> do
when (isFirstAccess st) (doInitDevice (baseAddress st))
return st{ isFirstAccess = False })
someDeviceAction :: DeviceHandle -> IO ()
someDeviceAdction h@(DH ref) = do
initDevice h
...
More information about the Haskell-Cafe
mailing list