From dde99c5ae2511f8509dae85ce33b22d554ce157c Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 30 Jul 2024 10:28:29 +0100 Subject: ash: rewrite waitpid_child() to improve performance After the previous commit there was still a slight disparity between shell performance with and without background jobs. Reduce this disparity by the following changes: - Remove the pidlist array. The PID of the exiting process can be obtained from its handle. - Save the proclist array between calls. It will always grow to support the required number of PIDs. - Combine the loops to compute the required size of proclist and to fill it. This saves a few bytes with no measurable impact on performance. Saves 8 bytes in a 32-bit build, adds 32 in 64-bit. (GitHub issue #434) --- shell/ash.c | 51 +++++++++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index ba29e3ea0..340c7ce2f 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -4925,50 +4925,37 @@ static pid_t waitpid_child(int *status, int wait_flags) { struct job *jb; - struct procstat *ps; int pid_nr = 0; - pid_t *pidlist; - HANDLE *proclist; + static HANDLE *proclist = NULL; + static int pid_max = 0; pid_t pid = -1; DWORD win_status, idx; int i; for (jb = curjob; jb; jb = jb->prev_job) { - if (jb->state != JOBDONE) - pid_nr += jb->nprocs; - } - if (pid_nr == 0) - return -1; - - pidlist = ckmalloc(sizeof(*pidlist)*pid_nr); - proclist = ckmalloc(sizeof(*proclist)*pid_nr); + if (jb->state != JOBDONE) { + if (pid_nr + jb->nprocs > pid_max) { + pid_max = pid_nr + jb->nprocs; + proclist = ckrealloc(proclist, sizeof(*proclist) * pid_max); + } - pid_nr = 0; - for (jb = curjob; jb; jb = jb->prev_job) { - if (jb->state == JOBDONE) - continue; - ps = jb->ps; - for (i = 0; i < jb->nprocs; ++i) { - if (ps[i].ps_proc) { - pidlist[pid_nr] = ps[i].ps_pid; - proclist[pid_nr++] = ps[i].ps_proc; + for (i = 0; i < jb->nprocs; ++i) { + if (jb->ps[i].ps_proc) { + proclist[pid_nr++] = jb->ps[i].ps_proc; + } } } } - if (pid_nr == 0) - goto done; - - idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, - wait_flags & WNOHANG ? 0 : INFINITE); - if (idx < pid_nr) { - GetExitCodeProcess(proclist[idx], &win_status); - *status = exit_code_to_wait_status(win_status); - pid = pidlist[idx]; + if (pid_nr) { + idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, + wait_flags & WNOHANG ? 0 : INFINITE); + if (idx < pid_nr) { + GetExitCodeProcess(proclist[idx], &win_status); + *status = exit_code_to_wait_status(win_status); + pid = GetProcessId(proclist[idx]); + } } - done: - free(pidlist); - free(proclist); return pid; } #define waitpid(p, s, f) waitpid_child(s, f) -- cgit v1.2.3-55-g6feb