Eliminate the fd_to_idx array in --watchfd, so that file descriptors aren't constrained to FD_SETSIZE and so we don't have to track another array.

This commit is contained in:
Andrew Wood
2025-09-26 23:40:39 +01:00
parent 7fdb6716e1
commit c49fc4aa57
3 changed files with 62 additions and 39 deletions
+1 -1
View File
@@ -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
+12 -24
View File
@@ -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) {
+49 -14
View File
@@ -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;
}