Skip to content

Commit 90720bd

Browse files
(maint) Merge up 0a3ced0 to main
Generated by CI * commit '0a3ced008b653b9b6ab0d602a6c9179a8f26ca2b': (packaging) Updating manpage file for 7.x (PUP-11934) Use String#each_codepoint instead of deprecated String#codepoints (PUP-11897) Simplifyy wait_flags setting (PUP-11897) Add additional mocking to the execution spec (PUP-11897) Add integration test for excessive cpu time for EOF in exec (PUP-11897) Handle EOF in order to avoid busy-loop
2 parents 312ab25 + 0a3ced0 commit 90720bd

File tree

4 files changed

+22
-3
lines changed

4 files changed

+22
-3
lines changed

lib/puppet/pops/time/timespan.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ def internal_parse(str)
634634
position = -1
635635
fstart = 0
636636

637-
str.codepoints do |codepoint|
637+
str.each_codepoint do |codepoint|
638638
position += 1
639639
if state == STATE_LITERAL
640640
if codepoint == 0x25 # '%'

lib/puppet/util/execution.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,12 @@ def self.execute(command, options = NoOptionsSpecified)
223223
# Use non-blocking read to check for data. After each attempt,
224224
# check whether the child is done. This is done in case the child
225225
# forks and inherits stdout, as happens in `foo &`.
226-
227-
until results = Process.waitpid2(child_pid, Process::WNOHANG) #rubocop:disable Lint/AssignmentInCondition
226+
# If we encounter EOF, though, then switch to a blocking wait for
227+
# the child; after EOF, IO.select will never block and the loop
228+
# below will use maximum CPU available.
229+
230+
wait_flags = Process::WNOHANG
231+
until results = Process.waitpid2(child_pid, wait_flags) #rubocop:disable Lint/AssignmentInCondition
228232

229233
# If not done, wait for data to read with a timeout
230234
# This timeout is selected to keep activity low while waiting on
@@ -235,6 +239,7 @@ def self.execute(command, options = NoOptionsSpecified)
235239
output << reader.read_nonblock(4096) if ready
236240
rescue Errno::EAGAIN
237241
rescue EOFError
242+
wait_flags = 0
238243
end
239244
end
240245

spec/integration/type/exec_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,19 @@
7575
end
7676
end
7777

78+
context 'when an exec sends an EOF' do
79+
let(:command) { ["/bin/bash", "-c", "exec /bin/sleep 1 >/dev/null 2>&1"] }
80+
81+
it 'should not take significant user time' do
82+
exec = described_class.new :command => command, :path => ENV['PATH']
83+
catalog.add_resource exec
84+
timed_apply = Benchmark.measure { catalog.apply }
85+
# In testing I found the user time before the patch in 4f35fd262e to be above
86+
# 0.3, after the patch it was consistently below 0.1 seconds.
87+
expect(timed_apply.utime).to be < 0.3
88+
end
89+
end
90+
7891
context 'when command is a string' do
7992
let(:command) { "ruby -e 'File.open(\"#{path}\", \"w\") { |f| f.print \"foo\" }'" }
8093

spec/unit/util/execution_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def stub_process_wait(exitstatus)
2929
allow(FFI::WIN32).to receive(:CloseHandle).with(thread_handle)
3030
else
3131
allow(Process).to receive(:waitpid2).with(pid, Process::WNOHANG).and_return(nil, [pid, double('child_status', :exitstatus => exitstatus)])
32+
allow(Process).to receive(:waitpid2).with(pid, 0).and_return(nil, [pid, double('child_status', :exitstatus => exitstatus)])
3233
allow(Process).to receive(:waitpid2).with(pid).and_return([pid, double('child_status', :exitstatus => exitstatus)])
3334
end
3435
end

0 commit comments

Comments
 (0)