aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2024-07-30 10:28:29 +0100
committerRon Yorston <rmy@pobox.com>2024-07-30 10:28:29 +0100
commitdde99c5ae2511f8509dae85ce33b22d554ce157c (patch)
tree83dc4c25f647e4d93bf321a2c82b88f7c43fb897 /shell/ash.c
parentbb8f6b688a6a8c7ac66b5c656d2544f9167a1abe (diff)
downloadbusybox-w32-dde99c5ae2511f8509dae85ce33b22d554ce157c.tar.gz
busybox-w32-dde99c5ae2511f8509dae85ce33b22d554ce157c.tar.bz2
busybox-w32-dde99c5ae2511f8509dae85ce33b22d554ce157c.zip
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)
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c51
1 files 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
4925waitpid_child(int *status, int wait_flags) 4925waitpid_child(int *status, int wait_flags)
4926{ 4926{
4927 struct job *jb; 4927 struct job *jb;
4928 struct procstat *ps;
4929 int pid_nr = 0; 4928 int pid_nr = 0;
4930 pid_t *pidlist; 4929 static HANDLE *proclist = NULL;
4931 HANDLE *proclist; 4930 static int pid_max = 0;
4932 pid_t pid = -1; 4931 pid_t pid = -1;
4933 DWORD win_status, idx; 4932 DWORD win_status, idx;
4934 int i; 4933 int i;
4935 4934
4936 for (jb = curjob; jb; jb = jb->prev_job) { 4935 for (jb = curjob; jb; jb = jb->prev_job) {
4937 if (jb->state != JOBDONE) 4936 if (jb->state != JOBDONE) {
4938 pid_nr += jb->nprocs; 4937 if (pid_nr + jb->nprocs > pid_max) {
4939 } 4938 pid_max = pid_nr + jb->nprocs;
4940 if (pid_nr == 0) 4939 proclist = ckrealloc(proclist, sizeof(*proclist) * pid_max);
4941 return -1; 4940 }
4942
4943 pidlist = ckmalloc(sizeof(*pidlist)*pid_nr);
4944 proclist = ckmalloc(sizeof(*proclist)*pid_nr);
4945 4941
4946 pid_nr = 0; 4942 for (i = 0; i < jb->nprocs; ++i) {
4947 for (jb = curjob; jb; jb = jb->prev_job) { 4943 if (jb->ps[i].ps_proc) {
4948 if (jb->state == JOBDONE) 4944 proclist[pid_nr++] = jb->ps[i].ps_proc;
4949 continue; 4945 }
4950 ps = jb->ps;
4951 for (i = 0; i < jb->nprocs; ++i) {
4952 if (ps[i].ps_proc) {
4953 pidlist[pid_nr] = ps[i].ps_pid;
4954 proclist[pid_nr++] = ps[i].ps_proc;
4955 } 4946 }
4956 } 4947 }
4957 } 4948 }
4958 4949
4959 if (pid_nr == 0) 4950 if (pid_nr) {
4960 goto done; 4951 idx = WaitForMultipleObjects(pid_nr, proclist, FALSE,
4961 4952 wait_flags & WNOHANG ? 0 : INFINITE);
4962 idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, 4953 if (idx < pid_nr) {
4963 wait_flags & WNOHANG ? 0 : INFINITE); 4954 GetExitCodeProcess(proclist[idx], &win_status);
4964 if (idx < pid_nr) { 4955 *status = exit_code_to_wait_status(win_status);
4965 GetExitCodeProcess(proclist[idx], &win_status); 4956 pid = GetProcessId(proclist[idx]);
4966 *status = exit_code_to_wait_status(win_status); 4957 }
4967 pid = pidlist[idx];
4968 } 4958 }
4969 done:
4970 free(pidlist);
4971 free(proclist);
4972 return pid; 4959 return pid;
4973} 4960}
4974#define waitpid(p, s, f) waitpid_child(s, f) 4961#define waitpid(p, s, f) waitpid_child(s, f)