How to redirect a handle within a thread (GHC 6.4.1 runtime)?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

How to redirect a handle within a thread (GHC 6.4.1 runtime)?

Dimitry Golubovsky
Is it possible to redirect a Handle (say stdout) somewhere only within
a running thread (started with forkIO) not touching the same handle
for the main and other threads?

I have a lot of code written with putStr(Ln) which was used in a
program acting as a filter, i. e. stdout was redirected by the
invoking shell. Now I want to run this code within a thread in other
program, but output must go to a file (or a pipe, or anywhere else a
file descriptor may be opened for). So fdToHandle is not good because
I need to modify the `stdout' only for that thread, not to create a
new Handle. Rewriting the code is not a convenient way (but will be
done if nothing else helps) because then I will need to pass that
handle around.

Running that code in a separate executable is just a bit more
convenient because I need to pass many parameters via command line (a
thread inherits values of them), and therefore is also desired to be
avioded.

Functions in System.Process deal with external executables. Does there
exist anything like runInteractiveProcess, but just forking a new
process (the whole memory is copied, so everything will be inherited),
but executes a particular function within the parent program?

I'm afraid that if I just make a foreign call to `fork', the RTS may
not understand this correctly.

--
Dimitry Golubovsky

Anywhere on the Web

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: How to redirect a handle within a thread (GHC 6.4.1 runtime)?

Bulat Ziganshin
Hello Dimitry,

Wednesday, January 18, 2006, 9:01:28 PM, you wrote:

DG> new Handle. Rewriting the code is not a convenient way (but will be
DG> done if nothing else helps) because then I will need to pass that
DG> handle around.

implicit parameter or global IORef may save father of russian
democracy ;)

--
Best regards,
 Bulat                            mailto:[hidden email]



_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: How to redirect a handle within a thread (GHC 6.4.1 runtime)?

Donn Cave-2
In reply to this post by Dimitry Golubovsky
On Wed, 18 Jan 2006, Dimitry Golubovsky wrote:

> Is it possible to redirect a Handle (say stdout) somewhere only within
> a running thread (started with forkIO) not touching the same handle
> for the main and other threads?

I think it's fairly simple, if I have understood your requirement.
I assume we are talking about UNIX or similar platform.  You don't
need to really modify stdout at all, it's more effective to accomplish
the redirection at a lower lever, with file descriptors.

>          ...  fdToHandle is not good because
> I need to modify the `stdout' only for that thread, not to create a
> new Handle.

Indeed, so instead of fdToHandle, you want dupTo, which will redirect
unit 1 in the process' OS level table.  Standard input, output and
error are really 0, 1, and 2 at the UNIX system level;  stdout etc.
are just process level language library constructs that add buffers.

Note the flushes in my example.  The first may be necessary to avoid
copying buffered data into the fork, which would cause it to appear
twice.  The second is a work-around for a bug that was mentioned here
only a day or two ago.

        Donn Cave, [hidden email]

module Main (main) where
import System.IO (hFlush, stdout)
import System.Posix.IO
import System.Posix.Process

redirect :: FilePath -> IO () -> IO ()
redirect file fn = do
        fd <- openFd file WriteOnly (Just 420) defaultFileFlags
        x <- dupTo fd 1
        closeFd fd
        fn
        hFlush stdout

main = do
        hFlush stdout
        pid <- forkProcess $ redirect "test.out" $ putStrLn "howdy"
        st <- getProcessStatus True False pid
        putStrLn ("status " ++ (show st))


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: How to redirect a handle within a thread (GHC 6.4.1 runtime)?

Ben Franksen-2
In reply to this post by Dimitry Golubovsky
On Wednesday 18 January 2006 19:01, Dimitry Golubovsky wrote:

> Is it possible to redirect a Handle (say stdout) somewhere only
> within a running thread (started with forkIO) not touching the same
> handle for the main and other threads?
>
> I have a lot of code written with putStr(Ln) which was used in a
> program acting as a filter, i. e. stdout was redirected by the
> invoking shell. Now I want to run this code within a thread in other
> program, but output must go to a file (or a pipe, or anywhere else a
> file descriptor may be opened for). So fdToHandle is not good because
> I need to modify the `stdout' only for that thread, not to create a
> new Handle. Rewriting the code is not a convenient way (but will be
> done if nothing else helps) because then I will need to pass that
> handle around.

Isn't this _the_ real-world example perfectly matching Robert Dockins'
'threadlocal' proposal?

Anyway, I think you could hack your way around the problem:

  {-# NOINLINE special_tid_var #-}
  special_tid_var :: MVar ThreadId
  special_tid_var = unsafePeformIO newEmptyMVar

  {-# NOINLINE special_stdout_var #-}
  special_stdout_var :: MVar Handle
  special_stdout_var = unsafePeformIO newEmptyMVar

  main = do
    ...
    open File ... >>= putMVar special_stdout_var
    forkIO ... >>= putMVar special_tid_var
    ...

  -- replacement for the usual putStrLn
  putStrLn :: String -> IO ()
  putStrLn str = do
    mytid <- myThreadId
    special_tid <- readMVar special_tid_var
    specia_stdout <- readMVar special_stdout_var
    if mytid == special_tid
      then System.IO.hPutStrLn special_stdout str
      else System.IO.putStrLn str

Not tested, but you should get the idea. Caveat: you must change all
your import declarations to hide System.IO.putStrLn and instead import
the version above.

Ben
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: How to redirect a handle within a thread (GHC 6.4.1 runtime)?

Bugzilla from robdockins@fastmail.fm

On Jan 18, 2006, at 2:59 PM, Benjamin Franksen wrote:

> On Wednesday 18 January 2006 19:01, Dimitry Golubovsky wrote:
>> Is it possible to redirect a Handle (say stdout) somewhere only
>> within a running thread (started with forkIO) not touching the same
>> handle for the main and other threads?
>>
>> I have a lot of code written with putStr(Ln) which was used in a
>> program acting as a filter, i. e. stdout was redirected by the
>> invoking shell. Now I want to run this code within a thread in other
>> program, but output must go to a file (or a pipe, or anywhere else a
>> file descriptor may be opened for). So fdToHandle is not good because
>> I need to modify the `stdout' only for that thread, not to create a
>> new Handle. Rewriting the code is not a convenient way (but will be
>> done if nothing else helps) because then I will need to pass that
>> handle around.
>
> Isn't this _the_ real-world example perfectly matching Robert Dockins'
> 'threadlocal' proposal?

Yes, actually.  This is precisely the use case that got me thinking  
about threadlocal storage in the first place.  I'm working on Shellac  
(http://www.mail-archive.com/haskell@.../msg17871.html) and  
it turns out that redirecting the standard output handle for a  
specific thread would be really nice.  The obvious alternative is to  
pass in a function of type (String -> IO ()) and pass it around, and  
make sure to use it instead of putStr and friends.  The non-obvious  
alternative is some unsafePerformIO hackery, as just posted.  Either  
way, its ugly.

[snip]


Rob Dockins

Speak softly and drive a Sherman tank.
Laugh hard; it's a long way to the bank.
           -- TMBG



_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe