Revision: 76613 http://sourceforge.net/p/brlcad/code/76613 Author: starseeker Date: 2020-07-31 19:18:16 +0000 (Fri, 31 Jul 2020) Log Message: ----------- Further restructuring of the callback mechanisms for subprocess I/O.
Modified Paths: -------------- brlcad/branches/bioh/include/ged/defines.h brlcad/branches/bioh/include/tclcad.h brlcad/branches/bioh/src/libged/ged_util.c brlcad/branches/bioh/src/libged/rtcheck/rtcheck.c brlcad/branches/bioh/src/libged/rtwizard/rtwizard.c brlcad/branches/bioh/src/libtclcad/tclcad_obj.c brlcad/branches/bioh/src/mged/setup.c Modified: brlcad/branches/bioh/include/ged/defines.h =================================================================== --- brlcad/branches/bioh/include/ged/defines.h 2020-07-31 16:00:56 UTC (rev 76612) +++ brlcad/branches/bioh/include/ged/defines.h 2020-07-31 19:18:16 UTC (rev 76613) @@ -250,11 +250,21 @@ void (*ged_create_vlist_callback)(struct display_list *); /**< @brief function to call after all vlist created that loops through creating display list for each solid */ void (*ged_free_vlist_callback)(unsigned int, int); /**< @brief function to call after freeing a vlist */ - /* Handler functions for I/O communication with asynchronous subprocess commands */ + /* Handler functions for I/O communication with asynchronous subprocess commands. There + * are two opaque data structures at play here, with different scopes. One is the "data" + * pointer passed to ged_create_io_handler, which is used to store command-specific + * information internal to the library (the simplest thing to do is pass ged_subprocess + * in as the data pointer, but if that's not enough - see for example rtcheck - this + * mechanism allows for more elaborate measures. + * + * The second is ged_io_data, which is set in gedp by the calling application. This is where + * information specific to the parent's I/O environment (which by definition the library + * can't know about as it is application specific) lives. It should be assigned in the + * applications gedp before any calls to ged_create_io_handler are made. + * */ + void (*ged_create_io_handler)(struct ged_subprocess *gp, int fd, ged_io_handler_callback_t callback, void *data); + void (*ged_delete_io_handler)(struct ged_subprocess *gp, int fd); void *ged_io_data; /**< brief caller supplied data */ - int io_mode; - void (*ged_create_io_handler)(void **chan, struct bu_process *p, int fd, int mode, void *data, ged_io_handler_callback_t callback); - void (*ged_delete_io_handler)(void *interp, void *chan, struct bu_process *p, int fd); // Other callbacks... // Tcl command strings - these are libtclcad level callbacks that execute user supplied Tcl commands if set: Modified: brlcad/branches/bioh/include/tclcad.h =================================================================== --- brlcad/branches/bioh/include/tclcad.h 2020-07-31 16:00:56 UTC (rev 76612) +++ brlcad/branches/bioh/include/tclcad.h 2020-07-31 19:18:16 UTC (rev 76613) @@ -514,16 +514,17 @@ TCLCAD_EXPORT extern int tclcad_init(Tcl_Interp *interp, int init_gui, struct bu_vls *tlog); /** - * Create Tcl specific I/O handlers + * Tcl specific I/O handlers */ +struct tclcad_io_data { + Tcl_Channel chan; + Tcl_Interp *interp; + int io_mode; +}; TCLCAD_EXPORT void -tclcad_create_io_handler(void **chan, struct bu_process *p, int fd, int mode, void *data, ged_io_handler_callback_t callback); - -/** - * Delete Tcl specific I/O handlers - */ +tclcad_create_io_handler(struct ged_subprocess *p, int fd, ged_io_handler_callback_t callback, void *data); TCLCAD_EXPORT void -tclcad_delete_io_handler(void *interp, void *chan, struct bu_process *p, int fd); +tclcad_delete_io_handler(struct ged_subprocess *p, int fd); /* dm_tcl.c */ Modified: brlcad/branches/bioh/src/libged/ged_util.c =================================================================== --- brlcad/branches/bioh/src/libged/ged_util.c 2020-07-31 16:00:56 UTC (rev 76612) +++ brlcad/branches/bioh/src/libged/ged_util.c 2020-07-31 19:18:16 UTC (rev 76613) @@ -1297,27 +1297,19 @@ } } -struct _ged_rt_client_data { - struct ged_subprocess *rrtp; - void *u_data; -}; - void _ged_rt_output_handler(void *clientData, int UNUSED(mask)) { - struct _ged_rt_client_data *drcdp = (struct _ged_rt_client_data *)clientData; + struct ged_subprocess *rrtp = (struct ged_subprocess *)clientData; int count = 0; int retcode = 0; int read_failed = 0; char line[RT_MAXLINE+1] = {0}; - if ((drcdp == (struct _ged_rt_client_data *)NULL) || - (drcdp->rrtp == (struct ged_subprocess *)NULL) || - (drcdp->rrtp->gedp == (struct ged *)NULL)) + if ((rrtp == (struct ged_subprocess *)NULL) || (rrtp->gedp == (struct ged *)NULL)) return; - struct ged *gedp = drcdp->rrtp->gedp; - struct ged_subprocess *rrtp = drcdp->rrtp; + struct ged *gedp = rrtp->gedp; /* Get data from rt */ if (bu_process_read((char *)line, &count, rrtp->p, BU_PROCESS_STDERR, RT_MAXLINE) <= 0) { @@ -1329,7 +1321,7 @@ /* Done watching for output, undo subprocess I/O hooks. */ if (gedp->ged_delete_io_handler) { - (*gedp->ged_delete_io_handler)(gedp->ged_interp, rrtp->chan, rrtp->p, BU_PROCESS_STDERR); + (*gedp->ged_delete_io_handler)(rrtp, BU_PROCESS_STDERR); } @@ -1350,7 +1342,6 @@ /* free rrtp */ BU_LIST_DEQUEUE(&rrtp->l); BU_PUT(rrtp, struct ged_subprocess); - BU_PUT(drcdp, struct _ged_rt_client_data); return; } @@ -1432,7 +1423,6 @@ FILE *fp_in; vect_t eye_model; struct ged_subprocess *run_rtp; - struct _ged_rt_client_data *drcdp; struct bu_process *p = NULL; bu_process_exec(&p, gd_rt_cmd[0], cmd_len, gd_rt_cmd, 0, 0); @@ -1460,13 +1450,9 @@ run_rtp->aborted = 0; run_rtp->gedp = gedp; - BU_GET(drcdp, struct _ged_rt_client_data); - drcdp->rrtp = run_rtp; - drcdp->u_data = gedp->ged_io_data; - /* If we know how, set up hooks so the parent process knows to watch for output. */ if (gedp->ged_create_io_handler) { - (*gedp->ged_create_io_handler)(&(run_rtp->chan), p, BU_PROCESS_STDERR, gedp->io_mode, (void *)drcdp, _ged_rt_output_handler); + (*gedp->ged_create_io_handler)(run_rtp, BU_PROCESS_STDERR, _ged_rt_output_handler, (void *)run_rtp); } return GED_OK; } Modified: brlcad/branches/bioh/src/libged/rtcheck/rtcheck.c =================================================================== --- brlcad/branches/bioh/src/libged/rtcheck/rtcheck.c 2020-07-31 16:00:56 UTC (rev 76612) +++ brlcad/branches/bioh/src/libged/rtcheck/rtcheck.c 2020-07-31 19:18:16 UTC (rev 76613) @@ -39,13 +39,11 @@ struct ged_rtcheck { struct ged_subprocess *rrtp; - struct ged *gedp; FILE *fp; struct bn_vlblock *vbp; struct bu_list *vhead; double csize; void *chan; - struct bu_process *p; int read_failed; int draw_read_failed; }; @@ -54,24 +52,24 @@ rtcheck_handler_cleanup(struct ged_rtcheck *rtcp) { int retcode; + struct ged_subprocess *rrtp = rtcp->rrtp; + struct ged *gedp = rrtp->gedp; - if (rtcp->gedp->ged_delete_io_handler) { - (*rtcp->gedp->ged_delete_io_handler)(rtcp->gedp->ged_interp, rtcp->rrtp->chan, - rtcp->rrtp->p, BU_PROCESS_STDOUT); - (*rtcp->gedp->ged_delete_io_handler)(rtcp->gedp->ged_interp, rtcp->chan, - rtcp->p, BU_PROCESS_STDERR); + if (gedp->ged_delete_io_handler) { + (*gedp->ged_delete_io_handler)(rrtp, BU_PROCESS_STDOUT); + (*gedp->ged_delete_io_handler)(rrtp, BU_PROCESS_STDERR); } - bu_process_close(rtcp->rrtp->p, BU_PROCESS_STDOUT); + bu_process_close(rrtp->p, BU_PROCESS_STDOUT); /* wait for the forked process */ - retcode = bu_process_wait(NULL, rtcp->rrtp->p, 0); + retcode = bu_process_wait(NULL, rrtp->p, 0); if (retcode != 0) { - _ged_wait_status(rtcp->gedp->ged_result_str, retcode); + _ged_wait_status(gedp->ged_result_str, retcode); } - BU_LIST_DEQUEUE(&rtcp->rrtp->l); - BU_PUT(rtcp->rrtp, struct ged_subprocess); + BU_LIST_DEQUEUE(&rrtp->l); + BU_PUT(rrtp, struct ged_subprocess); BU_PUT(rtcp, struct ged_rtcheck); } @@ -80,6 +78,8 @@ { int value = 0; struct ged_rtcheck *rtcp = (struct ged_rtcheck *)clientData; + struct ged_subprocess *rrtp = rtcp->rrtp; + struct ged *gedp = rrtp->gedp; /* Get vector output from rtcheck */ if (!rtcp->draw_read_failed && (feof(rtcp->fp) || (value = getc(rtcp->fp)) == EOF)) { @@ -89,7 +89,7 @@ rtcp->draw_read_failed = 1; - dl_set_flag(rtcp->gedp->ged_gdp->gd_headDisplay, DOWN); + dl_set_flag(gedp->ged_gdp->gd_headDisplay, DOWN); /* Add overlay (or, if nothing to draw, clear any stale overlay) */ if (rtcp->vbp) { @@ -102,7 +102,7 @@ } if (have_visual) { - _ged_cvt_vlblock_to_solids(rtcp->gedp, rtcp->vbp, sname, 0); + _ged_cvt_vlblock_to_solids(gedp, rtcp->vbp, sname, 0); bn_vlblock_free(rtcp->vbp); } else { /* TODO - yuck. This name is a product of the internals of the @@ -112,8 +112,8 @@ * current phony object drawing system.*/ const char *sname_obj = "OVERLAPSffff00"; struct directory *dp; - if ((dp = db_lookup(rtcp->gedp->ged_wdbp->dbip, sname_obj, LOOKUP_QUIET)) != RT_DIR_NULL) { - dl_erasePathFromDisplay(rtcp->gedp, sname_obj, 0); + if ((dp = db_lookup(gedp->ged_wdbp->dbip, sname_obj, LOOKUP_QUIET)) != RT_DIR_NULL) { + dl_erasePathFromDisplay(gedp, sname_obj, 0); } } @@ -131,7 +131,7 @@ rtcp->fp, value, rtcp->csize, - rtcp->gedp->ged_gdp->gd_uplotOutputMode); + gedp->ged_gdp->gd_uplotOutputMode); } } @@ -141,12 +141,14 @@ int count; char line[RT_MAXLINE] = {0}; struct ged_rtcheck *rtcp = (struct ged_rtcheck *)clientData; + struct ged_subprocess *rrtp = rtcp->rrtp; + struct ged *gedp = rrtp->gedp; /* Get textual output from rtcheck */ - if (bu_process_read((char *)line, &count, rtcp->p, BU_PROCESS_STDERR, RT_MAXLINE) <= 0) { + if (bu_process_read((char *)line, &count, rrtp->p, BU_PROCESS_STDERR, RT_MAXLINE) <= 0) { rtcp->read_failed = 1; - if (rtcp->gedp->ged_gdp->gd_rtCmdNotify != (void (*)(int))0) - rtcp->gedp->ged_gdp->gd_rtCmdNotify(0); + if (gedp->ged_gdp->gd_rtCmdNotify != (void (*)(int))0) + gedp->ged_gdp->gd_rtCmdNotify(0); } @@ -156,10 +158,10 @@ } line[count] = '\0'; - if (rtcp->gedp->ged_output_handler != (void (*)(struct ged *, char *))0) { - ged_output_handler_cb(rtcp->gedp, line); + if (gedp->ged_output_handler != (void (*)(struct ged *, char *))0) { + ged_output_handler_cb(gedp, line); } else { - bu_vls_printf(rtcp->gedp->ged_result_str, "%s", line); + bu_vls_printf(gedp->ged_result_str, "%s", line); } } @@ -253,7 +255,6 @@ /* create the rtcheck struct */ BU_GET(rtcp, struct ged_rtcheck); - rtcp->gedp = gedp; rtcp->fp = bu_process_open(p, BU_PROCESS_STDOUT); /* Needed on Windows for successful rtcheck drawing data communication */ setmode(fileno(rtcp->fp), O_BINARY); @@ -260,7 +261,6 @@ rtcp->vbp = rt_vlblock_init(); rtcp->vhead = bn_vlblock_find(rtcp->vbp, 0xFF, 0xFF, 0x00); rtcp->csize = gedp->ged_gvp->gv_scale * 0.01; - rtcp->p = p; rtcp->read_failed = 0; rtcp->draw_read_failed = 0; @@ -270,13 +270,13 @@ rtcp->rrtp->aborted = 0; rtcp->rrtp->gedp = gedp; if (gedp->ged_create_io_handler) { - (*gedp->ged_create_io_handler)(&(rtcp->rrtp->chan), p, BU_PROCESS_STDOUT, gedp->io_mode, (void *)rtcp, rtcheck_vector_handler); + (*gedp->ged_create_io_handler)(rtcp->rrtp, BU_PROCESS_STDOUT, rtcheck_vector_handler, (void *)rtcp); } BU_LIST_INIT(&rtcp->rrtp->l); BU_LIST_APPEND(&gedp->gd_headSubprocess.l, &rtcp->rrtp->l); if (gedp->ged_create_io_handler) { - (*gedp->ged_create_io_handler)(&(rtcp->chan), p, BU_PROCESS_STDERR, gedp->io_mode, (void *)rtcp, rtcheck_output_handler); + (*gedp->ged_create_io_handler)(rtcp->rrtp, BU_PROCESS_STDERR, rtcheck_output_handler, (void *)rtcp); } bu_free(gd_rt_cmd, "free gd_rt_cmd"); Modified: brlcad/branches/bioh/src/libged/rtwizard/rtwizard.c =================================================================== --- brlcad/branches/bioh/src/libged/rtwizard/rtwizard.c 2020-07-31 16:00:56 UTC (rev 76612) +++ brlcad/branches/bioh/src/libged/rtwizard/rtwizard.c 2020-07-31 19:18:16 UTC (rev 76613) @@ -38,17 +38,10 @@ #include "../ged_private.h" -struct _ged_rt_client_data { - struct ged_subprocess *rrtp; - void *u_data; -}; - - int _ged_run_rtwizard(struct ged *gedp, int cmd_len, const char **gd_rt_cmd) { struct ged_subprocess *run_rtp; - struct _ged_rt_client_data *drcdp; struct bu_process *p; bu_process_exec(&p, gd_rt_cmd[0], cmd_len, (const char **)gd_rt_cmd, 0, 0); @@ -70,13 +63,8 @@ run_rtp->aborted = 0; run_rtp->gedp = gedp; - /* must be BU_GET() to match release in _ged_rt_output_handler */ - BU_GET(drcdp, struct _ged_rt_client_data); - drcdp->rrtp = run_rtp; - drcdp->u_data = gedp->ged_io_data; - if (gedp->ged_create_io_handler) { - (*gedp->ged_create_io_handler)(&(run_rtp->chan), p, BU_PROCESS_STDERR, gedp->io_mode, (void *)drcdp, _ged_rt_output_handler); + (*gedp->ged_create_io_handler)(run_rtp, BU_PROCESS_STDERR, _ged_rt_output_handler, (void *)run_rtp); } return GED_OK; Modified: brlcad/branches/bioh/src/libtclcad/tclcad_obj.c =================================================================== --- brlcad/branches/bioh/src/libtclcad/tclcad_obj.c 2020-07-31 16:00:56 UTC (rev 76612) +++ brlcad/branches/bioh/src/libtclcad/tclcad_obj.c 2020-07-31 19:18:16 UTC (rev 76613) @@ -1135,6 +1135,10 @@ BU_PUT(tgd, struct tclcad_ged_data); top->to_gedp->u_data = NULL; } + if (top->to_gedp->ged_io_data) { + struct tclcad_io_data *t_iod = (struct tclcad_io_data *)top->to_gedp->ged_io_data; + BU_PUT(t_iod, struct tclcad_io_data); + } // Got the libtclcad cleanup done, have libged do its up. ged_close(top->to_gedp); @@ -1176,20 +1180,19 @@ /* Wrappers for setting up/tearing down IO handler */ #ifndef _WIN32 void -tclcad_create_io_handler(void **UNUSED(chan), struct bu_process *p, int fd, int mode, void *data, ged_io_handler_callback_t callback) +tclcad_create_io_handler(struct ged_subprocess *p, int fd, ged_io_handler_callback_t callback, void *data) { - int *fdp; - if (!p) return; - fdp = (int *)bu_process_fd(p, fd); - Tcl_CreateFileHandler(*fdp, mode, callback, (ClientData)data); + if (!p || !p->p || !p->gedp || !p->gedp->ged_io_data) return; + int *fdp = (int *)bu_process_fd(p->p, fd); + struct tclcad_io_data *t_iod = (struct tclcad_io_data *)p->gedp->ged_io_data; + Tcl_CreateFileHandler(*fdp, t_iod->io_mode, callback, (ClientData)data); } void -tclcad_delete_io_handler(void *UNUSED(interp), void *UNUSED(chan), struct bu_process *p, int fd) +tclcad_delete_io_handler(struct ged_subprocess *p, int fd) { - int *fdp; if (!p) return; - fdp = (int *)bu_process_fd(p, fd); + int *fdp = (int *)bu_process_fd(p->p, fd); Tcl_DeleteFileHandler(*fdp); close(*fdp); } @@ -1196,25 +1199,23 @@ #else void -tclcad_create_io_handler(void **chan, struct bu_process *p, int fd, int mode, void *data, ged_io_handler_callback_t callback) +tclcad_create_io_handler(struct ged_subprocess *p, int fd, ged_io_handler_callback_t callback, void *data) { - HANDLE *fdp; - if (!chan || !p) return; - fdp = (HANDLE *)bu_process_fd(p, fd); - (*chan) = (void *)Tcl_MakeFileChannel(*fdp, mode); - Tcl_CreateChannelHandler((Tcl_Channel)(*chan), mode, callback, (ClientData)data); + if (!p || !p->p || !p->gedp || !p->gedp->ged_io_data) return; + struct tclcad_io_data *t_iod = (struct tclcad_io_data *)p->gedp->ged_io_data; + HANDLE *fdp = (HANDLE *)bu_process_fd(p->p, fd); + (*t_iod->chan) = (void *)Tcl_MakeFileChannel(*fdp, t_iod->io_mode); + Tcl_CreateChannelHandler(*t_iod->chan, t_iod->io_mode, callback, (ClientData)data); } void -tclcad_delete_io_handler(void *interp, void *chan, struct bu_process *p, int fd) +tclcad_delete_io_handler(struct ged_subprocess *p, int fd) { - HANDLE *fdp; - Tcl_Interp *tcl_interp; - if (!chan || !p) return; - tcl_interp = (Tcl_Interp *)interp; - fdp = (HANDLE *)bu_process_fd(p, fd); - Tcl_DeleteChannelHandler((Tcl_Channel)chan, NULL, (ClientData)NULL); - Tcl_Close(tcl_interp, (Tcl_Channel)chan); + if (!p || !p->p || !p->p->gedp || !p->p->gedp->ged_io_data) return; + struct tclcad_io_data *t_iod = (struct tclcad_io_data *)p->gedp->ged_io_data; + HANDLE *fdp = (HANDLE *)bu_process_fd(p->p, fd); + Tcl_DeleteChannelHandler(t_oid->chan, NULL, (ClientData)NULL); + Tcl_Close(t_oid->interp, t_oid->chan); } #endif @@ -1295,9 +1296,13 @@ gedp->ged_interp = (void *)interp; /* Set the Tcl specific I/O handlers for asynchronous subprocess I/O */ + struct tclcad_io_data *t_iod; + BU_GET(t_iod, struct tclcad_io_data); + t_iod->io_mode = TCL_READABLE; + t_iod->interp = interp; + gedp->ged_io_data = (void *)t_iod; gedp->ged_create_io_handler = &tclcad_create_io_handler; gedp->ged_delete_io_handler = &tclcad_delete_io_handler; - gedp->io_mode = TCL_READABLE; /* initialize tclcad_obj */ BU_ALLOC(top, struct tclcad_obj); Modified: brlcad/branches/bioh/src/mged/setup.c =================================================================== --- brlcad/branches/bioh/src/mged/setup.c 2020-07-31 16:00:56 UTC (rev 76612) +++ brlcad/branches/bioh/src/mged/setup.c 2020-07-31 19:18:16 UTC (rev 76613) @@ -476,10 +476,15 @@ mged_global_variable_setup(*interpreter); mged_variable_setup(*interpreter); GEDP->ged_interp = (void *)*interpreter; + GEDP->ged_interp_eval = &mged_db_search_callback; + + struct tclcad_io_data *t_iod; + BU_GET(t_iod, struct tclcad_io_data); + t_iod->io_mode = TCL_READABLE; + t_iod->interp = *interpreter; + GEDP->ged_io_data = t_iod; GEDP->ged_create_io_handler = &tclcad_create_io_handler; GEDP->ged_delete_io_handler = &tclcad_delete_io_handler; - GEDP->io_mode = TCL_READABLE; - GEDP->ged_interp_eval = &mged_db_search_callback; /* Tcl needs to write nulls onto subscripted variable names */ bu_vls_printf(&str, "%s(state)", MGED_DISPLAY_VAR); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. _______________________________________________ BRL-CAD Source Commits mailing list brlcad-commits@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/brlcad-commits