[squeak-dev] Is there any way of reopening OSProcess thisOSProcess stdOut to a given FileStream?

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

[squeak-dev] Is there any way of reopening OSProcess thisOSProcess stdOut to a given FileStream?

CdAB63
Hello,

OSProcess thisOSProcess stdOut nextPutAll: 'This is a test'. will print
"This is a test" in the shell that started squeak.
OSProcess thisOSProcess stdOut close. successfully closes stdOut.

Under linux, if I open a new file after closing stdout it will have the
FD #1 (given stdin is not closed too) and I would successfully have
redirected stdOut to that file. But in squeak if I do something like:

fd := FileStream fileNamed: 'aGenericPipeline'.
fd readWrite.
OSProcess thisOSProcess setStdOut.
OSProcess thisOSProcess stdOut nextPutAll: 'This is a test',Character lf
asString.

Things get weird... (to the point that squeak VM crashes).

I also tried to do:

mkfifo fifo
squeak > fifo

But squeak just won't start...

Any suggestions on how reopen stdOut to a desired point other than the
default?




signature.asc (268 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Is there any way of reopening OSProcess thisOSProcess stdOut to a given FileStream?

David T. Lewis
On Mon, May 18, 2009 at 11:35:56AM -0300, Casimiro de Almeida Barreto wrote:
>
> Any suggestions on how reopen stdOut to a desired point other than the
> default?

Hi Casimiro,

I was looking into this just last night, and have gotten far enough so that
the following works, and I can verify that the Unix file descriptors are
properly duplicated for child processes to inherit correctly.

  OSProcess command: 'mkfifo myPipe'.
  fd := FileStream fileNamed: 'myPipe'.
  OSProcess thisOSProcess redirectStdOutTo: fd.
  OSProcess thisOSProcess redirectStdErrTo: fd.
  OSProcess thisOSProcess stdOut nextPutAll: 'hello '; flush.
  OSProcess thisOSProcess stdErr nextPutAll: 'world!'; flush.
  fd next: 11 ==> 'hello world'

This requires some updates to OSProcessPlugin (a primitive for the dup2()
system call) and to OSProcess. I'm not done yet, but I'll try to get this
cleaned up and posted by this weekend.

Dave


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Is there any way of reopening OSProcess thisOSProcess stdOut to a given FileStream?

Gerardo Richarte

> This requires some updates to OSProcessPlugin (a primitive for the dup2()
> system call) and to OSProcess. I'm not done yet, but I'll try to get this
> cleaned up and posted by this weekend.
>  
you don't really need a plugin if you have FFI:

dup: srcfd
    <cdecl: long 'dup' (long) module: 'libc'>
    ^ self externalCallFailed

dup: srcfd to: dstfd
    <cdecl: long 'dup2' (long long) module: 'libc'>
    ^ self externalCallFailed

    richie

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Is there any way of reopening OSProcess thisOSProcess stdOut to a given FileStream?

David T. Lewis
In reply to this post by David T. Lewis
On Sun, May 24, 2009 at 02:06:49PM -0300, Casimiro de Almeida Barreto wrote:

> David T. Lewis escreveu:
> > (...)
> > Hi Casimiro,
> >
> > I was looking into this just last night, and have gotten far enough so that
> > the following works, and I can verify that the Unix file descriptors are
> > properly duplicated for child processes to inherit correctly.
> >
> >   OSProcess command: 'mkfifo myPipe'.
> >   fd := FileStream fileNamed: 'myPipe'.
> >   OSProcess thisOSProcess redirectStdOutTo: fd.
> >   OSProcess thisOSProcess redirectStdErrTo: fd.
> >   OSProcess thisOSProcess stdOut nextPutAll: 'hello '; flush.
> >   OSProcess thisOSProcess stdErr nextPutAll: 'world!'; flush.
> >   fd next: 11 ==> 'hello world'
> >
> > This requires some updates to OSProcessPlugin (a primitive for the dup2()
> > system call) and to OSProcess. I'm not done yet, but I'll try to get this
> > cleaned up and posted by this weekend.
> >
> > Dave
> >
> Will it be available at Universes, SMPackageLoader or from specific URL?
>

All of the updates are now on SqueakSource in the projects OSProcessPlugin,
OSProcess, and CommandShell. You will need to build your own OSPP plugin
to make use of this.

I also think that I have a solution to your overall problem. You want to
call a long-running function using FFI, and be able to see the stdout output
from that function within Squeak. You also want to run the FFI call without
blocking the VM (otherwise your Squeak image will be blocked for the duration
of the FFI call).

I have made updates to OSProcessPlugin, OSProcess, and CommandShell that
permit this to be done. The changes add support for the dup2() system call
to OSPP, for redirection of the standard IO streams for a running Squeak image,
and for a PipeableOSProcess proxy that forks a headless background Squeak
connected to your Squeak image through OS pipes. The basic idea is to call
this to run the FFI function:

  PipeableOSProcess forkHeadlessSqueakAndDoThenQuit: aLongRunningCallToFFI.

Here is a complete example:

  "Put your FFI call into a block. This is just an example, so replace it with
  your actual method that calls FFI."
  aLongRunningCallToFFI := [
      "self myFFIFunctionCall"
      (1 to: 5) do:
      [:i | (Delay forSeconds: 2) wait.
      OSProcess thisOSProcess stdOut
      nextPutAll: 'loop ', i printString,
      ' with output from FFI on stdout'; nextPut: Character cr; flush]].
 
  "Fork a child Squeak to evaluate the block without hanging up your Squeak image"
  child := PipeableOSProcess forkHeadlessSqueakAndDoThenQuit: aLongRunningCallToFFI.
     
  "Read the output of the child Squeak. This will be reading data from the
  standard output stream that your FFI function is using."
  watcherProcess := [20 timesRepeat: [(Delay forSeconds: 1) wait.
      someResponseCharactersFromChild := child upToEnd.
      Transcript show: someResponseCharactersFromChild]] fork.
               
If you need to obtain the result of your FFI function call in the form
of objects (as opposed to just reading text from the stdout stream),
there are examples of how to do this with (using ReferenceStream to
pass the objects) in the unit tests for CommandShell. See
PipeableOSProcessTestCase>>testForkSqueakReadAndWriteReferenceStream
for one example.

Hope this helps,

Dave