I want to redirect output from a child process to my own little colorful console listbrowser. My main eventloop is driven by signals and a IExec->Wait statement. Now, the most straightforward method to redirect process output, I guess, is to create two PIPE: filehandles and hand over the write end to the process when it is created. Now the question is, how do I know, when stuff has been written to my pipe? I have tried to allocate a dos notify request (with AllocDosObject), but it doesn't seem to work. I was thinking of bsdsocket WaitSelect, but I don't think it works with pipes. What am I to do??
Sat, 2012-11-10 04:09
#1
How to get a signal from PIPE:?
The simplest way to get a piece of text from one process to another is an exec.library message. In the beginning the receiver creates a MsgPort and tells the sender about it. When the sender wants to send some text, it just allocates the message and PutMsg() it to the port. The receiver receives a signal from the port (1L << port->mp_SigBit) and can then GetMsg() the message.
If you want synchronous processing, the sender needs to create a port, too, and store the pointer in message->mn_ReplyPort. If this is done, after sending the message it can WaitPort() on the replyport and the receiver must ReplyMsg() the message. If you don't use a reply port, the receiver should free the message.
@thomas
I cannot use messages for this, because the child process could be any process whatsoever (this is for my debugger). I have to somehow get the output by redirecting the stdout of the child process when it is created.
Ok, then you could start DOS I/O asynchronously and Wait() for the result.
Example: http://thomas-rapp.homepage.t-online.de/examples/async.c
But be aware that there is no way to abort a DOS I/O operation. Once you have started an operation, before you can quit your program, you must wait for the operation to complete.
In case of a pipe this might mean that you have to write some artificial data to the write end of the pipe so that the read end can stop waiting.
Thank you thomas, that did the trick :). I have included your code in my project with a notice, that it is originally written by you, and that I have modified it slightly. Hurray! :-D
Damn, I was too early at celebrating... For some strange reason, I don't get a signal from the packet until the program terminates. This is not very helpful, because you really want to have the output when it happens. When I just redirect the output to the stdout, all the output comes at the right time. Either this is some kind of problem with the pipe-handler, or some of my other signals are blocking the dos signal. Help??
There is definitely something wrong with the queue-handler. It seems to be a general problem, that when redirecting std streams from a child executable, the data only arrives at the read end of the pipe when the child exits. I guess nobody else than me is crazy enough to fool around with pipes in AmigaOS (I also used it in the CMake port), but it would be nice if they actually worked...
I did something similar similar a while back. There were a number of problems with PIPE: starting with AOS 4.0, but they have mostly been fixed by 4.1 Upd 3 or 4.
Now both WaitForChar and WaitForData work well with PIPE:, and you can use them with timeouts. Or you can use NON-Blocking mode in the PIPE: if you have have something else to do if you want an immediate return with an empty pipe on Read (or an full PIPE on write).
Make sure you read the documentation on the queue-handler that is supplied with the OS in SYS:Documentation/ (?), as I think it has information not in the SDK AutoDocs.
The source code for pipe handling modules and the logging program are on OS4 Depot:
LoggerWindow on OS4Depot
This is written in Modula-2, but may still be of some use to you since it is using all DOS calls.
I also used pipes to send data back and forth between a game engine and two competing software programs in the CaptureContest on OS4Depot. With the right size buffer the pipe communication can be pretty fast.
This one also includes a little example C program to talk to the game engine.
CaptureContest on OS4Depot
Tom
For closure:
This discussion was taken to mailing list and responses from the AOS developers seemed to indicate that Standard output is always buffered (by C libraries and/or DOS), unless StdOut is to a console:, resulting in the symptom seen of the read pipe getting the output in a big batch when the writer program ends.
And that currently there is no way for the program that starts up the writer program with std output redirected to a PIPE: to change that. Though the need to was acknowledged.
So PIPE: communication between AOS programs does work, but best if the programs know they are writing/reading a pipe, and don't use buffered IO if they need conversational communication.
Maybe Alfkil has more info I did not see.
Tom
I have asked on the mailinglist for a tag like this:
IDOS->Open("PIPE:someid/ISINTERACTIVE/NOBLOCK", MODE_NEWFILE);
This I think would solve the problem. But also it seems that the core developers are too busy to look into it at the moment...
Is this still the status of this issue, after almost 4 years?? I am trying to update db101 and have found, that the issue persists, that is, there is no interactive pipe option (the tag '/ISINTERACTIVE' was explicitly removed from the documentation instead of the code being fixed), and the output from the child process in db101 will only arrive after the child has finished. Please help me out here, I have been away for a while, and to sort out controversial issues with pipes is not my favorite thing to do anymore....
Looks like it. What happens if you use IDOS->SetMode to set single character mode. Does it make any difference or reject it?
Stdout is buffered too when it's connected to a terminal. The difference is that then it's line buffered which means that the buffer is always flushed when a newline is written.
To disable buffering the setvbuf() function can be used.
BTW this problem of redirecting stdout to a pipe and stdout then being fully buffered exists on linux as well:
https://www.turnkeylinux.org/blog/unix-buffering
There they have implemented a program, which is kind of a hack, called stdbuf to solve the issue:
https://www.gnu.org/software/coreutils/manual/html_node/stdbuf-invocation.html
@alfkil
This is the first I hear of an ISINTERACTIVE option. I tried googling it but couldn't find anything.
Even if it was implemented it wouldn't be enough though. AFAICT for newlib to recognise a file as a terminal right now ExamineFH() has to fail with ERROR_ACTION_NOT_KNOWN (like it does for con-handler) in addition to IsInteractive() returning not FALSE.
And if it did work you would get the line buffering mode which might be fine for text data but not for binary data.
Well, all I want is line buffered data. The purpose of the excercise is to dump application output to the console inside db101 instead of having lingering console windows for separate output.
It doesn't matter, I am just going to kill the pipe output and have debugging apps output to a normal console. I see no point in continuing this endeavor.
I was a little quick to dismiss all of this. In fact, hypex's suggestion with IDOS->SetMode works like a charm. I guess setting the pipe to raw mode enables the reception of single characters as they are produced at the origin, which is exactly what I needed. Thanks!
Glad my suggestion worked. Somehow reading through the discussion SetMode() came to mind since I needed it for something once. I'm happy to see an update of DB101 as it's a very useful tool and I enjoy using it. I had to use GDB on Linux recently and was lost without DB101. :-D
An update to db101 is right around the corner. Not too much new, but a few really useful things, like nicelooking stacktraces and the ability to continue execution after a trap or dsi. :)
That's pretty good to trap a DSI. How is it done? Through GDB or system API?