From b4a291bef6a6113cbbc8c56a742c6476fe8d669f Mon Sep 17 00:00:00 2001 From: f4alt Date: Thu, 30 Mar 2023 11:17:36 -0400 Subject: [PATCH 1/2] fix nirt with a lot of output locking mged Since we were reading from stderr before stdout, when nirt wrote more than a page worth to stdout the read from mged locked indefinitely. Add a helper function in process.c to check if there is data to be read from a file descriptor Add error checking in nirt.c to check if there is any data to read before blindly trying. Add sandwiching stderr reads to avoid future locks. (cherry picked from commit 64fd6748d9843346f4bc61c5eda9c34b3f4fed34) --- include/bu/process.h | 8 ++++++++ src/libbu/process.c | 28 +++++++++++++++++++++++++++- src/libged/nirt/nirt.c | 28 ++++++++++++++++++++++++---- 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/include/bu/process.h b/include/bu/process.h index 9c16f903cff..22e14eb03d2 100644 --- a/include/bu/process.h +++ b/include/bu/process.h @@ -159,6 +159,14 @@ BU_EXPORT extern void bu_process_exec(struct bu_process **info, const char *cmd, */ BU_EXPORT extern int bu_interactive(); + +/** + * @brief determine whether there is data pending on fd + * + * 1 if there is data, else 0 + */ +BU_EXPORT extern int bu_process_pending(int fd); + /** @} */ __END_DECLS diff --git a/src/libbu/process.c b/src/libbu/process.c index ac9bd0d9a8a..1d8372ec47f 100644 --- a/src/libbu/process.c +++ b/src/libbu/process.c @@ -1,7 +1,7 @@ /* P R O C E S S . C * BRL-CAD * - * Copyright (c) 2007-2022 United States Government as represented by + * Copyright (c) 2007-2023 United States Government as represented by * the U.S. Army Research Laboratory. * * This library is free software; you can redistribute it and/or @@ -543,6 +543,32 @@ bu_process_wait( # include #endif +int +bu_process_pending(int fd) +{ + int result; + +#if defined(_WIN32) + HANDLE out_fd = (HANDLE)_get_osfhandle(fd); + DWORD bytesAvailable = 0; + /* returns 1 on success, 0 on error */ + if (PeekNamedPipe(out_fd, NULL, 0, NULL, &bytesAvailable, NULL)) { + result = bytesAvailable; + } else { + result = -1; + } +#else + fd_set read_set; + FD_ZERO(&read_set); + FD_SET(fd, &read_set); + /* returns 1 on success, 0 on timeout, -1 on error */ + result = select(fd+1, &read_set, NULL, NULL, 0); +#endif + + /* collapse return to ignore amount to read or errors */ + return result > 0 ? 1 : 0; +} + int bu_interactive() { diff --git a/src/libged/nirt/nirt.c b/src/libged/nirt/nirt.c index 0ff0ad65591..019cd14318f 100644 --- a/src/libged/nirt/nirt.c +++ b/src/libged/nirt/nirt.c @@ -45,6 +45,7 @@ #include "bu/app.h" #include "bu/cmd.h" #include "bu/file.h" +#include "bu/snooze.h" #include "bu/process.h" #include "vmath.h" @@ -307,10 +308,20 @@ ged_nirt_core(struct ged *gedp, int argc, const char *argv[]) bu_vls_free(&p_vls); /* use to form "partition" part of nirt command above */ print: - while (bu_fgets(line, RT_MAXLINE, fp_err) != (char *)NULL) { - bu_vls_strcpy(&v, line); - bu_vls_trimspace(&v); - bu_vls_printf(gedp->ged_result_str, "%s\n", bu_vls_addr(&v)); + /* ensure nirt has started and has something to read from - with 5 second timeout */ + int64_t start = bu_gettime(); + while (!bu_process_pending(fileno(fp_err)) && !bu_process_pending(fileno(fp_out))) { + if ((bu_gettime() - start) > BU_SEC2USEC(5)) + break; + } + + /* check if nirt wrote anything to error on load */ + if (bu_process_pending(fileno(fp_err))) { + while (bu_fgets(line, RT_MAXLINE, fp_err) != (char *)NULL) { + bu_vls_strcpy(&v, line); + bu_vls_trimspace(&v); + bu_vls_printf(gedp->ged_result_str, "%s\n", bu_vls_addr(&v)); + } } if (DG_QRAY_TEXT(gedp->ged_gdp)) { @@ -397,6 +408,15 @@ ged_nirt_core(struct ged *gedp, int argc, const char *argv[]) bv_vlblock_free(vbp); } + /* check if nirt wrote any errors from shots */ + if (bu_process_pending(fileno(fp_err))) { + while (bu_fgets(line, RT_MAXLINE, fp_err) != (char *)NULL) { + bu_vls_strcpy(&v, line); + bu_vls_trimspace(&v); + bu_vls_printf(gedp->ged_result_str, "%s\n", bu_vls_addr(&v)); + } + } + bu_vls_free(&v); bu_process_close(p, BU_PROCESS_STDOUT); From b343d98eb0b9a360d54c78351c67108ffece8b99 Mon Sep 17 00:00:00 2001 From: f4alt Date: Thu, 30 Mar 2023 13:00:32 -0400 Subject: [PATCH 2/2] oops. Get 64fd674 to build clean (cherry picked from commit d779aabea8bb6ecf7d32887c5e34a828d1f185d3) --- src/libged/nirt/nirt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libged/nirt/nirt.c b/src/libged/nirt/nirt.c index 019cd14318f..ea52182dbd6 100644 --- a/src/libged/nirt/nirt.c +++ b/src/libged/nirt/nirt.c @@ -46,6 +46,7 @@ #include "bu/cmd.h" #include "bu/file.h" #include "bu/snooze.h" +#include "bu/time.h" #include "bu/process.h" #include "vmath.h" @@ -84,6 +85,7 @@ ged_nirt_core(struct ged *gedp, int argc, const char *argv[]) char **gd_rt_cmd = NULL; int gd_rt_cmd_len = 0; int skip_drawn = 0; + int64_t start = 0; const char *nirt = NULL; char nirtcmd[MAXPATHLEN] = {0}; @@ -309,7 +311,7 @@ ged_nirt_core(struct ged *gedp, int argc, const char *argv[]) print: /* ensure nirt has started and has something to read from - with 5 second timeout */ - int64_t start = bu_gettime(); + start = bu_gettime(); while (!bu_process_pending(fileno(fp_err)) && !bu_process_pending(fileno(fp_out))) { if ((bu_gettime() - start) > BU_SEC2USEC(5)) break;