diff options
author | Ron Yorston <rmy@pobox.com> | 2024-07-30 10:28:29 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2024-07-30 10:28:29 +0100 |
commit | dde99c5ae2511f8509dae85ce33b22d554ce157c (patch) | |
tree | 83dc4c25f647e4d93bf321a2c82b88f7c43fb897 /shell/ash.c | |
parent | bb8f6b688a6a8c7ac66b5c656d2544f9167a1abe (diff) | |
download | busybox-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.c | 51 |
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 | |||
4925 | waitpid_child(int *status, int wait_flags) | 4925 | waitpid_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) |