Genuine Need For Persistent Global State?

Hi, I've been looking at the patches given by Tom at Beware the Jabberwolk, for building Linux kernel modules in Haskell. Once I'd got Tom's stuff building, the next thing was to build a little driver which actually does something. Step by step I was making progress, and I've now got a little function which can see all the characters which are catted to the device file. That's when I got stuck. Trouble is, my function is (ultimately) being called from the C kernel stuff. It isn't on the bottom of a call graph coming from a Haskell main. A driver really needs to know where it's at. So I seem to need some kind of global, persistent state, and Control.Monad.State seems to be out because I can't pass a State around my call graph. I've thought about trying to create some State when I initialize, pass some kind of pointer back to the C shim which actually does the calling into Haskell, and then passing it back into Haskell on the writes and reads, but that seems dangerous because the Haskell garbage collector would (understandably) get the wrong idea and delete it. Also it's ugly - having to use C for something Haskell can't do. I've been looking at the Halfs Haskell file system, which surely must have solved its own version of this problem, but whatever it does in its FSState seems very complicated and is beyond my comprehension :-( So my questions are: 1) Am I right in thinking that I have a genuine need for global, persistent state? 2) Halfs works. Am I right in thinking it has (somehow) solved this problem? 3) Is there a simple way to maintain global persistent state that I can stash between calls into a function, and access without needing to pass the state in? If so, is there an example anywhere? Thanks in advance, Alan -- ... the PA system was moaning unctuously, like a lady hippopotamus reading A. E. Housman ..." -- James Blish, "They Shall Have Stars"

alangcarter:
1) Am I right in thinking that I have a genuine need for global, persistent state? 2) Halfs works. Am I right in thinking it has (somehow) solved this problem? 3) Is there a simple way to maintain global persistent state that I can stash between calls into a function, and access without needing to pass the state in? If so, is there an example anywhere?
You don't necessarily need to have global mutable state, since you can pass a reference to the state back and forth from C. That saves you having to build a top level table on the Haskell side to store all the state while you're in C. However, you can stash state on the Haskell side via a top level IORef, or you can make a foreign pointer of the Haskell state, and pass it to C and back. I'd probably do the former. -- Don

Stable pointers might do what you want:
http://haskell.org/ghc/docs/latest/html/libraries/base/Foreign-StablePtr.htm...
Though an IORef would probably work just as well, depending on how you
needed to use it..
- Job
On Fri, Oct 16, 2009 at 2:59 PM, Alan Carter
Hi, I've been looking at the patches given by Tom at Beware the Jabberwolk, for building Linux kernel modules in Haskell. Once I'd got Tom's stuff building, the next thing was to build a little driver which actually does something. Step by step I was making progress, and I've now got a little function which can see all the characters which are catted to the device file. That's when I got stuck.
Trouble is, my function is (ultimately) being called from the C kernel stuff. It isn't on the bottom of a call graph coming from a Haskell main. A driver really needs to know where it's at. So I seem to need some kind of global, persistent state, and Control.Monad.State seems to be out because I can't pass a State around my call graph.
I've thought about trying to create some State when I initialize, pass some kind of pointer back to the C shim which actually does the calling into Haskell, and then passing it back into Haskell on the writes and reads, but that seems dangerous because the Haskell garbage collector would (understandably) get the wrong idea and delete it. Also it's ugly - having to use C for something Haskell can't do.
I've been looking at the Halfs Haskell file system, which surely must have solved its own version of this problem, but whatever it does in its FSState seems very complicated and is beyond my comprehension :-(
So my questions are:
1) Am I right in thinking that I have a genuine need for global, persistent state? 2) Halfs works. Am I right in thinking it has (somehow) solved this problem? 3) Is there a simple way to maintain global persistent state that I can stash between calls into a function, and access without needing to pass the state in? If so, is there an example anywhere?
Thanks in advance,
Alan
-- ... the PA system was moaning unctuously, like a lady hippopotamus reading A. E. Housman ..." -- James Blish, "They Shall Have Stars"
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

StablePtrs are relatively easy to use, and have precisely the guarantees you need -- the state can be passed to C and recovered. Any use of IORefs that will scale past more than one state object will essentially duplicate the stable pointer functionality. They're a reasonable choice. -- Don jvranish:
Stable pointers might do what you want: http://haskell.org/ghc/docs/latest/html/libraries/base/Foreign-StablePtr.htm...
Though an IORef would probably work just as well, depending on how you needed to use it..
- Job
On Fri, Oct 16, 2009 at 2:59 PM, Alan Carter
wrote: Hi,
I've been looking at the patches given by Tom at Beware the Jabberwolk, for building Linux kernel modules in Haskell. Once I'd got Tom's stuff building, the next thing was to build a little driver which actually does something. Step by step I was making progress, and I've now got a little function which can see all the characters which are catted to the device file. That's when I got stuck.
Trouble is, my function is (ultimately) being called from the C kernel stuff. It isn't on the bottom of a call graph coming from a Haskell main. A driver really needs to know where it's at. So I seem to need some kind of global, persistent state, and Control.Monad.State seems to be out because I can't pass a State around my call graph.
I've thought about trying to create some State when I initialize, pass some kind of pointer back to the C shim which actually does the calling into Haskell, and then passing it back into Haskell on the writes and reads, but that seems dangerous because the Haskell garbage collector would (understandably) get the wrong idea and delete it. Also it's ugly - having to use C for something Haskell can't do.
I've been looking at the Halfs Haskell file system, which surely must have solved its own version of this problem, but whatever it does in its FSState seems very complicated and is beyond my comprehension :-(
So my questions are:
1) Am I right in thinking that I have a genuine need for global, persistent state? 2) Halfs works. Am I right in thinking it has (somehow) solved this problem? 3) Is there a simple way to maintain global persistent state that I can stash between calls into a function, and access without needing to pass the state in? If so, is there an example anywhere?
Thanks in advance,
Alan
-- ... the PA system was moaning unctuously, like a lady hippopotamus reading A. E. Housman ..." -- James Blish, "They Shall Have Stars"
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Fri, Oct 16, 2009 at 11:59 AM, Alan Carter
Trouble is, my function is (ultimately) being called from the C kernel stuff. It isn't on the bottom of a call graph coming from a Haskell main. A driver really needs to know where it's at. So I seem to need some kind of global, persistent state, and Control.Monad.State seems to be out because I can't pass a State around my call graph.
You don't need anything special for this. A Linux kernel "struct device" has a "void *driver_data" member which is private for your use, and intended for precisely this purpose. Global persistent state makes no more sense for kernel drivers than for most other code: how would it work if you had two mice plugged into your system? If you want a decent reference on writing Linux driver code, see http://lwn.net/Kernel/LDD3/ Your friendly kernel and Haskell hacker, Bryan.

On Fri, Oct 16, 2009 at 9:13 PM, Bryan O'Sullivan
You don't need anything special for this. A Linux kernel "struct device" has a "void *driver_data" member which is private for your use, and intended for precisely this purpose. Global persistent state makes no more sense for kernel drivers than for most other code: how would it work if you had two mice plugged into your system?
Thanks Bryan - your thought on this is pure and true :-) Although I'm just making a toy driver, I wanted to exercise the bits a real one would need, and wrongly thought persistent state would matter. You're quite right though - generally, things that matter should go in the per device store, which can easily be kmalloc()ed/kfree()ed on open/close, picked up and passed into Haskell as a Ptr on write/read (so avoiding even the need to understand the C struct in Haskell), then peeked and poked. My driver can now accumulate data as I wanted, and I don't feel like I've cheated. Alan -- ... the PA system was moaning unctuously, like a lady hippopotamus reading A. E. Housman ..." -- James Blish, "They Shall Have Stars"

alangcarter:
On Fri, Oct 16, 2009 at 9:13 PM, Bryan O'Sullivan
wrote: You don't need anything special for this. A Linux kernel "struct device" has a "void *driver_data" member which is private for your use, and intended for precisely this purpose. Global persistent state makes no more sense for kernel drivers than for most other code: how would it work if you had two mice plugged into your system?
Thanks Bryan - your thought on this is pure and true :-)
Although I'm just making a toy driver, I wanted to exercise the bits a real one would need, and wrongly thought persistent state would matter. You're quite right though - generally, things that matter should go in the per device store, which can easily be kmalloc()ed/kfree()ed on open/close, picked up and passed into Haskell as a Ptr on write/read (so avoiding even the need to understand the C struct in Haskell), then peeked and poked.
My driver can now accumulate data as I wanted, and I don't feel like I've cheated.
So what solution did you pick in the end? Allocate on the C side, and pass a reference back and forth? -- Don
participants (4)
-
Alan Carter
-
Bryan O'Sullivan
-
Don Stewart
-
Job Vranish