Function creates new child
and redirects stdin, stdout and stderr. |
---|
#include <glib-2.0/glib.h> #define READ 0 #define WRITE 1 /* this function creates a child process using the argument list argv, * and returns process handler of newly created child and write-end of * pipe. The latter can be used to send child process data on stdin. * * @arg argv [in] program name and command line parameters * @arg to_child [out] stream to stdin of child process. * @arg from_child [out] stream from stdout of child process. * @arg err [out] in case of errors, returns error code and message. * * @return 0 if failing, otherwise process handle of child, do not * assume process handle is equal to PID of child process. Only use * g_process operations for process synchronization. */ gproc create_child (char* argv[], gint* in, gint *out, GError** err) { gproc child = 0; gint to_child[2] = {-1, -1}; gint from_child[2] = {-1, -1}; g_assert (*err==NULL); /* create pipe, both ends are inheritable */ if (g_pipe (to_child, err)==-1) goto raise_error; if (g_pipe (from_child, err)==-1) goto raise_error: /* create non-inheritable ends of pipes, that shall be private to * parent process only */ if ((*in=g_dup (to_child[WRITE], FALSE, err))==-1) goto raise_error; if ((*out=g_dup (to_child[WRITE], FALSE, err))==-1) goto raise_error; /* close ends of pipe that shall not be inherited to child process */ if (g_close (to_child[WRITE], err)==-1) goto raise_error; if (g_close (from_child[READ], err)==-1) goto raise_error; /* create new process using argv string vector. Set newly created * pipes as stdin and stdout of child process. Stderr output shall * be same as of parent process */ if ((child=g_process_new (argv, to_child[READ], from_child[WRITE], G_STDERR, 0, err))==-1) goto raise_error; /* close ends of pipe that have been inherited * and shall be resources of child process only */ if (g_close (to_child[READ], err)==-1) goto raise_error; if (g_close (from_child[WRITE], err)==-1) goto raise_error; return child; raise_error: if (to_child[WRITE]!=-1) g_close (to_child[WRITE], NULL); if (to_child[READ]!=-1) g_close (to_child[READ], NULL); if (from_child[WRITE]!=-1) g_close (from_child[WRITE], NULL); if (from_child[READ]!=-1) g_close (from_child[READ], NULL); if (*in!=-1) { g_close (*in, NULL); *in=-1; } if (*out!=-1) { g_close (*out, NULL); *out=-1; } return -1; } |
Main function
creating child and waiting for its termination |
---|
#include <glib-2.0/glib.h> int main (int argc, char* argv[]) { if (argc>1) { GError* err; gint timeout=100*1000; /* milliseconds */ gint status; gint in; gint out; gproc child = 0; if (g_ios_init (&err)==-1) { g_warning ("%s", err->message); g_error_free (err); exit (1); } /* create child process given as command line parameters */ if ((child=create_child (&argv[1], &in, &out, &err))==0) { g_warning ("%s", err->message); g_error_free (err); exit (1); } { gchar c; for (c=0; c<127; ++c) { if (g_write (in, &c, sizeof (c), &err)==-1) { g_process_kill (child, G_SIGQUIT, NULL); g_process_free (child, NULL); g_warning ("%s", err->message); g_error_free (err); exit (1); } if (g_read (out, &c, sizeof (c), &err)==-1) { g_process_kill (child, G_SIGQUIT, NULL); g_process_free (child, NULL); g_warning ("%s", err->message); g_error_free (err); exit (1); } g_print ("received child %3d\n", c); } } switch (g_process_wait (child, &status, timeout, &err)) { case -1: g_warning ("%s", err->message); g_error_free (err); g_process_kill (child, G_SIGQUIT, NULL); g_process_free (child, NULL); exit (1); case 0: g_warning ("reached timeout"); g_process_kill (child, G_SIGQUIT, NULL); g_process_free (child, NULL); exit (1); default: g_print ("child terminated with status: %d\n", status); g_process_free (child, NULL); } } else { g_print ("uage: %s <command> \n", argv[0]); exit (1); } } |
|
child process
reading from STDIN and writing to STDOUT |
int main (int argc, char* argv[]) { gint c; if (g_ios_init (&err)==-1) { g_warning ("%s", err->message); g_error_free (err); exit (1); } while (1) { if (g_read (G_STDIN, &c, sizeof(c), NULL)==-1) exit (1); c+=128; if (g_write (G_STDOUT, &c, sizeof(c), NULL)==-1) exit (1); if (c==255) exit (0); } } |
portable
asynchronous IO |
#define CHK_ERR(err) if (err!=NULL) {\ g_warning (" chk_err: %s(%d)/%d/%s\n", __FUNCTION__, __LINE__, \ err->code, err->message);\ cUnit_assert (err==NULL);\ } #define POLL_CHUNK_SIZE (2<<20) gchar* tst_poll__parent (gpointer data) { GError* err = NULL; gint child = -1; gint to_child_pipe[2] = {-1, -1}; gint to_parent_pipe[2] = {-1, -1}; gint to_child = -1; gint from_child = -1; char arg_cmd [MAX_ARG_LEN+1]; char* args[]={NULL,NULL,NULL,NULL,NULL,NULL,NULL}; g_pipe (to_child_pipe, &err); CHK_ERR (err); g_pipe (to_parent_pipe, &err); CHK_ERR (err); to_child = g_dup (to_child_pipe[WRITE], FALSE, &err); CHK_ERR (err); from_child = g_dup (to_parent_pipe[READ], FALSE, &err); CHK_ERR (err); g_close (to_child_pipe[WRITE], &err); CHK_ERR (err); g_close (to_parent_pipe[READ], &err); CHK_ERR (err); g_snprintf (arg_cmd, MAX_ARG_LEN, "%d", TST_POLL); args[0] = _argv[0]; args[1] = arg_cmd; args[2] = NULL; child=g_process_new (args, to_child_pipe[READ], to_parent_pipe[WRITE], G_STDERR, 0, &err); CHK_ERR (err); cUnit_assert (child>0); g_close (to_child_pipe[READ], &err); CHK_ERR (err); g_close (to_parent_pipe[WRITE], &err); CHK_ERR (err); G_IO_NONBLOCKING (to_child, &err); CHK_ERR (err); G_IO_NONBLOCKING (from_child, &err); CHK_ERR (err); { GPollFD ufds[2]; char buf[POLL_CHUNK_SIZE]; gint i; gint sent=0; gint recv=0; for (i=0; i<POLL_CHUNK_SIZE; ++i) buf[i] = 'A'; ufds[0].fd = to_child; ufds[0].events = G_IO_OUT; ufds[0].revents = 0; ufds[1].fd = from_child; ufds[1].events = G_IO_IN; ufds[1].revents = 0; while (sent!=sizeof(buf) && recv!=sizeof(buf)) { gint n=0; // wait infinite time, until ready for read or write gint nevents=g_poll (ufds, 2, -1, &err); cUnit_assert (nevents>0); CHK_ERR (err); cUnit_assert ( ! (ufds[0].revents & G_IO_IN) ); cUnit_assert ( ! (ufds[0].revents & G_IO_ERR) ); cUnit_assert ( ! (ufds[0].revents & G_IO_HUP) ); cUnit_assert ( ! (ufds[0].revents & G_IO_NVAL) ); cUnit_assert ( ! (ufds[0].revents & G_IO_PRI) ); if (ufds[0].revents & G_IO_OUT) { sent+=g_write (to_child, &buf[sent], sizeof(buf)-sent, &err); CHK_ERR (err); } cUnit_assert ( ! (ufds[1].revents & G_IO_OUT)); cUnit_assert ( ! (ufds[1].revents & G_IO_PRI)); cUnit_assert ( ! (ufds[1].revents & G_IO_ERR)); cUnit_assert ( ! (ufds[1].revents & G_IO_HUP)); cUnit_assert ( ! (ufds[1].revents & G_IO_NVAL)); if (ufds[1].revents & G_IO_IN) { recv+=g_read (from_child, &buf[recv], sizeof(buf)-recv, &err); CHK_ERR (err); } } // verify characters for (i=0; i<sizeof(buf); ++i) cUnit_assert (buf[i]=='A'); } { char c=0; g_write (to_child, &c, sizeof(c), &err); CHK_ERR (err); } G_IO_BLOCKING (to_child, &err); CHK_ERR (err); G_IO_BLOCKING (from_child, &err); CHK_ERR (err); g_close (to_child, &err); CHK_ERR (err); g_close (from_child, &err); CHK_ERR (err); // child must terminate with 0 { gint stat=0; gint ret=g_process_wait (child, &stat, 10*1000, NULL); cUnit_assert (stat==0); } g_process_free (child, NULL); return NULL; } |