static void subprocess_free (struct subprocess *p) { assert (p != NULL); if (p->sm) zlist_remove (p->sm->processes, (void *) p); zhash_destroy (&p->zhash); hooks_table_free (p); fda_closeall (p->child_fda); if (p->argz) free (p->argz); if (p->envz) free (p->envz); if (p->cwd) free (p->cwd); zio_destroy (p->zio_in); zio_destroy (p->zio_out); zio_destroy (p->zio_err); if (p->parentfd != -1) close (p->parentfd); if (p->childfd != -1) close (p->childfd); flux_watcher_destroy (p->child_watcher); memset (p, 0, sizeof (*p)); free (p); }
static zio_t *zio_allocate (const char *name, int reader, void *arg) { zio_t *z; if (!name) { errno = EINVAL; return (NULL); } if (!(z = malloc (sizeof (*z)))) return NULL; memset (z, 0, sizeof (*z)); assert (z->magic = ZIO_MAGIC); if (!(z->name = strdup (name))) { zio_destroy (z); return (NULL); } z->arg = arg; z->io_type = reader ? ZIO_READER : ZIO_WRITER; z->flags = ZIO_BUFFERED | ZIO_LINE_BUFFERED; z->buffersize = 4096; z->srcfd = z->dstfd = -1; z->prefix = NULL; zio_init_buffer (z); return (z); }
int main (int argc, char **argv) { zio_t *zio; int init_fds; const char *name; struct counts c; int fd; flux_reactor_t *r; flux_watcher_t *w; memset (&c, 0, sizeof (c)); plan (NO_PLAN); test_encode (); ok ((r = flux_reactor_create (0)) != NULL, "flux reactor created"); init_fds = fdcount (); diag ("initial fd count: %d", init_fds); /* simple reader tests */ ok ((zio = zio_pipe_reader_create ("test1", &c)) != NULL, "reader: zio_pipe_reader_create works"); ok ((name = zio_name (zio)) != NULL && !strcmp (name, "test1"), "reader: zio_name returns correct name"); ok (zio_set_close_cb (zio, close_reader) == 0, "reader: zio_set_close_cb works"); ok (zio_set_send_cb (zio, send_reader) == 0, "reader: zio_set_send_cb works"); ok (zio_reactor_attach (zio, r) == 0, "reader: zio_reactor_attach works"); ok ((fd = zio_dst_fd (zio)) >= 0, "reader: zio_dst_fd returned valid file descriptor"); ok (write (fd, "narf!", 5) == 5, "reader: wrote narf! to reader pipe"); ok (zio_close_dst_fd (zio) == 0, "reader: zio_close_dst_fd succeeded"); ok (flux_reactor_run (r, 0) == 0, "reader: reactor completed successfully"); ok (c.send_reader == 1, "reader: send function called once for EOF + incomplete line"); errno = 0; zio_destroy (zio); ok (init_fds == fdcount (), "reader: zio_destroy leaks no file descriptors"); /* simple writer tests */ ok ((zio = zio_pipe_writer_create ("test2", &c)) != NULL, "writer: zio_pipe_writer_create works"); ok ((name = zio_name (zio)) != NULL && !strcmp (name, "test2"), "writer: zio_name returns correct name"); ok (zio_set_close_cb (zio, close_writer) == 0, "writer: zio_set_close_cb works"); ok ((fd = zio_src_fd (zio)) >= 0, "writer: zio_src_fd returned valid file descriptor"); w = flux_fd_watcher_create (r, fd, FLUX_POLLIN, fd_read, &c); ok (w != NULL, "writer: created fd watcher"); flux_watcher_start (w); ok (zio_write (zio, "narf!", 5) == 5, "writer: zio_write narf! works"); ok (zio_write_eof (zio) == 0, "writer: zio_write_eof works"); ok (flux_reactor_run (r, 0) == 0, "writer: reactor completed successfully"); ok (c.fd_read_errors == 0 && c.fd_read_data == 5 && c.fd_read_eof == 1, "writer: read narf + EOF on read end of pipe"); ok (c.close_writer == 1, "writer: close callback invoked"); zio_destroy (zio); ok (init_fds == fdcount (), "writer: zio_destroy leaks no file descriptors"); flux_watcher_destroy (w); flux_reactor_destroy (r); done_testing (); }
static void forkzio_pipe_thd (void *args, zctx_t *zctx, void *zs) { forkzio_t ctx = args; zmq_pollitem_t zp = { .fd = -1, .socket = zs, .events = ZMQ_POLLIN }; zloop_t *zloop; pid_t pid; if (!(zloop = zloop_new ())) oom (); /* child stdin <= zs */ zloop_poller (zloop, &zp, (zloop_fn *)forkzio_zsock_cb, ctx); ctx->zio[0] = zio_pipe_writer_create ("stdin", NULL); if (zio_zloop_attach (ctx->zio[0], zloop) < 0) err_exit ("zio_zloop_attach %s", zio_name (ctx->zio[0])); /* child stdout => zs */ ctx->zio[1] = zio_pipe_reader_create ("stdout", zs, ctx); zio_set_close_cb (ctx->zio[1], forkzio_close_cb); if (zio_zloop_attach (ctx->zio[1], zloop) < 0) err_exit ("zio_zloop_attach %s", zio_name (ctx->zio[1])); ctx->readers++; /* child stderr => zs */ ctx->zio[2] = zio_pipe_reader_create ("stderr", zs, ctx); zio_set_close_cb (ctx->zio[2], forkzio_close_cb); if (zio_zloop_attach (ctx->zio[2], zloop) < 0) err_exit ("zio_zloop_attach %s", zio_name (ctx->zio[2])); ctx->readers++; pid = forkzio_fork (ctx); (void)zloop_start (zloop); forkzio_wait (pid); zio_destroy (ctx->zio[0]); zio_destroy (ctx->zio[1]); zio_destroy (ctx->zio[2]); zstr_send (zs, ""); /* signify EOF by sending an empty message */ } static void forkzio_pty_thd (void *args, zctx_t *zctx, void *zs) { forkzio_t ctx = args; zmq_pollitem_t zp = { .fd = -1, .socket = zs, .events = ZMQ_POLLIN }; zloop_t *zloop; pid_t pid; int ptyfd; if (!(zloop = zloop_new ())) oom (); switch ((pid = forkpty (&ptyfd, NULL, NULL, NULL))) { case -1: /* error */ err_exit ("forkpty"); case 0: /* child */ (void)execvp (ctx->av[0], ctx->av); err_exit ("%s", ctx->av[0]); default: /* parent */ break; } /* Data read from zs is written to pty master */ zloop_poller (zloop, &zp, (zloop_fn *)forkzio_zsock_cb, ctx); ctx->zio[0] = zio_writer_create ("stdin", ptyfd, NULL); zio_set_unbuffered (ctx->zio[0]); if (zio_zloop_attach (ctx->zio[0], zloop) < 0) err_exit ("zio_zloop_attach %s", zio_name (ctx->zio[0])); /* Data read from pty master is written to zs */ ctx->zio[1] = zio_reader_create ("stdout", ptyfd, zs, ctx); zio_set_unbuffered (ctx->zio[1]); zio_set_close_cb (ctx->zio[1], forkzio_close_cb); if (zio_zloop_attach (ctx->zio[1], zloop) < 0) err_exit ("zio_zloop_attach %s", zio_name (ctx->zio[1])); ctx->readers++; (void)zloop_start (zloop); forkzio_wait (pid); zio_destroy (ctx->zio[0]); zio_destroy (ctx->zio[1]); zstr_send (zs, ""); /* signify EOF by sending an empty message */ } forkzio_t forkzio_open (zctx_t *zctx, int ac, char **av, int flags) { zthread_attached_fn *thd = forkzio_pipe_thd; forkzio_t ctx = xzmalloc (sizeof (*ctx)); ctx->ac = ac; ctx->av = av; ctx->zctx = zctx; ctx->flags = flags; if ((ctx->flags & FORKZIO_FLAG_PTY)) thd = forkzio_pty_thd; if (!(ctx->zs = zthread_fork (zctx, thd, ctx))) { free (ctx); ctx = NULL; } return ctx; }
static inline void zio_handler_end (zio_t *zio) { zio->flags &= ~ZIO_IN_HANDLER; if (zio_is_destroyed (zio)) zio_destroy (zio); }