diff --git a/src/include/pv-internal.h b/src/include/pv-internal.h index c08de2f..7bc7acc 100644 --- a/src/include/pv-internal.h +++ b/src/include/pv-internal.h @@ -619,7 +619,7 @@ int pv_remote_set(pvstate_t); int pv_watchfd_info(pvstate_t, pvwatchfd_t, bool); bool pv_watchfd_changed(pvwatchfd_t); off_t pv_watchfd_position(pvwatchfd_t); -int pv_watchpid_scanfds(pvstate_t, pid_t, int *, pvwatchfd_t *, int *); +int pv_watchpid_scanfds(pvstate_t, pid_t, int *, pvwatchfd_t *); void pv_watchpid_setname(pvstate_t, pvwatchfd_t); #ifdef __cplusplus diff --git a/src/pv/loop.c b/src/pv/loop.c index f608e78..ee8e137 100644 --- a/src/pv/loop.c +++ b/src/pv/loop.c @@ -779,7 +779,6 @@ int pv_watchpid_loop(pvstate_t state) char new_format_string[512]; /* flawfinder: ignore */ struct pvwatchfd_s *info_array = NULL; int array_length = 0; - int fd_to_idx[FD_SETSIZE]; struct timespec next_update, cur_time; int idx; int prev_displayed_lines, blank_lines; @@ -845,14 +844,10 @@ int pv_watchpid_loop(pvstate_t state) pv_elapsedtime_copy(&next_update, &cur_time); pv_elapsedtime_add_nsec(&next_update, (long long) (1000000000.0 * state->control.interval)); - for (idx = 0; idx < FD_SETSIZE; idx++) { - fd_to_idx[idx] = -1; - } - prev_displayed_lines = 0; while (true) { - int rc, fd, displayed_lines; + int rc, displayed_lines; if (1 == state->flags.trigger_exit) break; @@ -909,7 +904,7 @@ int pv_watchpid_loop(pvstate_t state) } } - rc = pv_watchpid_scanfds(state, state->watchfd.pid[0], &array_length, &info_array, fd_to_idx); + rc = pv_watchpid_scanfds(state, state->watchfd.pid[0], &array_length, &info_array); if (rc != 0) { if (first_pass) { pv_error("%s %u: %s", _("pid"), state->watchfd.pid[0], strerror(errno)); @@ -924,40 +919,34 @@ int pv_watchpid_loop(pvstate_t state) first_pass = false; displayed_lines = 0; - for (fd = 0; fd < FD_SETSIZE && NULL != info_array; fd++) { + for (idx = 0; NULL != info_array && idx < array_length; idx++) { off_t position_now; struct timespec init_time, transfer_elapsed; + /* Skip unused array entries. */ + if (info_array[idx].unused) + continue; + + /* No more lines if we've filled the display. */ if (displayed_lines >= (int) (state->control.height)) break; - idx = fd_to_idx[fd]; - - if (idx < 0) - continue; - - if (info_array[idx].unused) { - debug("%s %d: %s", "fd", fd, "unused array entry - skipping"); - continue; - } - if (!info_array[idx].displayable) { /* * Non-displayable fd - just remove if * changed */ if (pv_watchfd_changed(&(info_array[idx]))) { - fd_to_idx[fd] = -1; + debug("%s %d: %s", "fd", info_array[idx].watch_fd, "removing"); info_array[idx].unused = true; info_array[idx].displayable = false; pv_freecontents_watchfd(&(info_array[idx])); - debug("%s %d: %s", "fd", fd, "removing"); } continue; } if (info_array[idx].watch_fd < 0) { - debug("%s %d: %s", "fd", fd, "negative fd - skipping"); + debug("%s %d: %s", "fd", info_array[idx].watch_fd, "negative fd - skipping"); continue; } @@ -968,11 +957,10 @@ int pv_watchpid_loop(pvstate_t state) position_now = pv_watchfd_position(&(info_array[idx])); if (position_now < 0) { - fd_to_idx[fd] = -1; + debug("%s %d: %s", "fd", info_array[idx].watch_fd, "removing"); info_array[idx].unused = true; info_array[idx].displayable = false; pv_freecontents_watchfd(&(info_array[idx])); - debug("%s %d: %s", "fd", fd, "removing"); continue; } @@ -1000,7 +988,7 @@ int pv_watchpid_loop(pvstate_t state) pv_tty_write(&(state->flags), "\n", 1); } - debug("%s %d [%d]: %Lf / %Ld", "fd", fd, idx, + debug("%s %d [%d]: %Lf / %Ld", "fd", info_array[idx].watch_fd, idx, info_array[idx].transfer.elapsed_seconds, position_now); if (info_array[idx].watch_fd >= 0) { diff --git a/src/pv/watchpid.c b/src/pv/watchpid.c index 275febb..5605575 100644 --- a/src/pv/watchpid.c +++ b/src/pv/watchpid.c @@ -394,6 +394,28 @@ void pv_freecontents_watchfd(pvwatchfd_t info) } +/* + * Comparison function for qsort, to compare two pvwatchfd_s structures. + */ +static int pv_compare_watchfd(const void *a, const void *b) +{ + int fd_a, fd_b; + + fd_a = 0; + fd_b = 0; + if (NULL != a) + fd_a = ((pvwatchfd_t) a)->watch_fd; + if (NULL != b) + fd_b = ((pvwatchfd_t) b)->watch_fd; + + if (fd_a < fd_b) + return -1; + if (fd_a > fd_b) + return 1; + return 0; +} + + /* * Scan the given process and update the arrays with any new file * descriptors. @@ -401,8 +423,7 @@ void pv_freecontents_watchfd(pvwatchfd_t info) * Returns 0 on success, 1 if the process no longer exists or could not be * read, or 2 for a memory allocation error. */ -int pv_watchpid_scanfds(pvstate_t state, - pid_t watch_pid, int *array_length_ptr, pvwatchfd_t * info_array_ptr, int *fd_to_idx) +int pv_watchpid_scanfds(pvstate_t state, pid_t watch_pid, int *array_length_ptr, pvwatchfd_t * info_array_ptr) { int array_length = 0; struct pvwatchfd_s *info_array = NULL; @@ -419,6 +440,7 @@ int pv_watchpid_scanfds(pvstate_t state, char fd_dir[512]; /* flawfinder: ignore - zeroed, bounded with pv_snprintf(). */ DIR *dptr; struct dirent *d; + bool changes_made; memset(fd_dir, 0, sizeof(fd_dir)); (void) pv_snprintf(fd_dir, sizeof(fd_dir), "/proc/%u/fd", watch_pid); @@ -431,6 +453,8 @@ int pv_watchpid_scanfds(pvstate_t state, array_length = *array_length_ptr; info_array = *info_array_ptr; + changes_made = false; + #ifdef __APPLE__ if (fd_infos_count < 1) { pv_error("%s: no fds found", _("pid")); @@ -440,7 +464,7 @@ int pv_watchpid_scanfds(pvstate_t state, #else while ((d = readdir(dptr)) != NULL) { #endif - int fd, check_idx, use_idx, rc; + int fd, check_idx, found_idx, use_idx, rc; off_t position_now; fd = -1; @@ -451,21 +475,24 @@ int pv_watchpid_scanfds(pvstate_t state, continue; #endif - /* - * TODO: determine whether fd_to_idx really helps here, - * since it constrains us to fds < FD_SETSIZE. - */ - - /* Skip if the fd is outside the array. */ - if ((fd < 0) || (fd >= FD_SETSIZE)) + /* Skip if the fd is negative. */ + if (fd < 0) continue; /* * Skip if this fd is already known to us. */ - if (fd_to_idx[fd] != -1) { - continue; + found_idx = -1; + for (check_idx = 0; check_idx < array_length; check_idx++) { + if (info_array[check_idx].unused) + continue; + if (info_array[check_idx].watch_fd != fd) + continue; + found_idx = check_idx; + break; } + if (found_idx >= 0) + continue; /* * See if there's an empty slot we can re-use. @@ -491,6 +518,8 @@ int pv_watchpid_scanfds(pvstate_t state, debug("%s: %d => index %d", "found new fd", fd, use_idx); + changes_made = true; + /* * Initialise the details of this new entry. */ @@ -528,8 +557,6 @@ int pv_watchpid_scanfds(pvstate_t state, continue; } - fd_to_idx[fd] = use_idx; - /* * Not displayable - mark it as such so the main loop * doesn't show it. @@ -568,6 +595,14 @@ int pv_watchpid_scanfds(pvstate_t state, (void) closedir(dptr); #endif + /* + * If any changes were made (i.e. new file descriptors were found), + * sort the array so that file descriptors are always displayed in + * ascending numerical order. + */ + if (changes_made && NULL != info_array && array_length > 1) + qsort(info_array, (size_t) array_length, sizeof(info_array[0]), pv_compare_watchfd); + return 0; }