Re: GIOChannel & Intercepting stdout
- From: richard boaz <ivor boaz gmail com>
- To: Hrvoje Niksic <hrvoje niksic avl com>
- Cc: gtk-list gnome org
- Subject: Re: GIOChannel & Intercepting stdout
- Date: Thu, 26 Aug 2010 12:53:04 +0200
On Thu, Aug 26, 2010 at 11:01 AM, Hrvoje Niksic
<hrvoje niksic avl com> wrote:
The good news is that libraries shouldn't require a terminal for stdout because then they wouldn't work with stdout being redirected to a file (highly unlikely).
The bad news is that this is harder to do correctly than it sounds. If you connect stdout to a pipe, then a thread (or a subprocess) should exist to collect output from the pipe, or the program deadlocks whenever a library prints a chunk of output larger than the pipe buffer.
The other bad news is that the dup2/pipe solution is very Unix-specific. It is not clear if this is a problem to Richard.
Hi guys,
Thanks for the feedback, I'm now sorted.
You are correct, the libraries don't expect a terminal, no problem there.
The actual program I intend to use this in is a background process where the actual processing executes in a separate thread while the main thread sits in the main loop. With the watch on the read-end of the pipe, the callback is fired and executes within the main loop, while all writing occurs on the execution thread; i.e, backwards from what you suggest, but both processing entities (write to, read from) are separate and so can't collide with or block each other (he says, crossing fingers furiously).
I re-post the modified code, very pared down, using GIOChannel watching that now works as expected/required.
thanks again,
richard
==== BEGIN CODE =====
// save to: io.c
// compile as: gcc io.c `pkg-config --cflags --libs glib-2.0`
#include <glib.h>
#include <stdio.h>
#include <string.h>
enum {READFD, WRITEFD, TTLPIPEFDS};
int fd[TTLPIPEFDS];
gboolean my_callback(GIOChannel *source, GIOCondition condition, gpointer data)
{
GMainLoop *loop = (GMainLoop *) data;
switch (condition)
{
case G_IO_IN: {
gchar buf2[100];
memset(buf2, 0, sizeof(buf2)); read(fd[READFD], buf2, sizeof(buf2)); // read the data from the read-end of the pipe
if (buf2[0])
{ // output to text file and to stderr
FILE *fp = fopen("/tmp/test.out", "w+");
fprintf(fp, "%s", buf2);
fclose(fp);
fprintf(stderr, "written to file: '%s'\n", buf2);
} g_main_loop_quit(loop);
g_io_channel_shutdown(source,TRUE,NULL);
}
break;
}
return FALSE;
}
gboolean idle_function(gpointer nil)
{
printf("printf() test" );
fflush(stdout);
return FALSE; // remove
}
int main()
{
GMainLoop *loop = g_main_loop_new(NULL,FALSE);
GIOChannel *channel;
if (pipe(fd) < 0) return(-1); // make a new pipe
if (dup2(fd[WRITEFD], fileno(stdout)) < 0) return(-1); // copy stdout to write-end
close(fd[WRITEFD]);
g_idle_add((GSourceFunc) idle_function, NULL); // write message to stdout
channel = g_io_channel_unix_new(fd[READFD]); // watch read-end of pipe
g_io_add_watch(channel, G_IO_IN,(GIOFunc) my_callback, loop);
g_main_loop_run(loop);
return 0;
}
==== END CODE =====
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]