Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/rb/lib/selenium/webdriver/common/child_process.rb
1865 views
1
# frozen_string_literal: true
2
3
# Licensed to the Software Freedom Conservancy (SFC) under one
4
# or more contributor license agreements. See the NOTICE file
5
# distributed with this work for additional information
6
# regarding copyright ownership. The SFC licenses this file
7
# to you under the Apache License, Version 2.0 (the
8
# "License"); you may not use this file except in compliance
9
# with the License. You may obtain a copy of the License at
10
#
11
# http://www.apache.org/licenses/LICENSE-2.0
12
#
13
# Unless required by applicable law or agreed to in writing,
14
# software distributed under the License is distributed on an
15
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
# KIND, either express or implied. See the License for the
17
# specific language governing permissions and limitations
18
# under the License.
19
20
module Selenium
21
module WebDriver
22
#
23
# @api private
24
#
25
26
class ChildProcess
27
TimeoutError = Class.new(StandardError)
28
29
SIGTERM = 'TERM'
30
SIGKILL = 'KILL'
31
32
POLL_INTERVAL = 0.1
33
34
attr_accessor :detach
35
attr_writer :io
36
37
def self.build(*command)
38
new(*command)
39
end
40
41
def initialize(*command)
42
@command = command
43
@detach = false
44
@pid = nil
45
@status = nil
46
end
47
48
def io
49
@io ||= Platform.null_device
50
end
51
52
def start
53
options = {%i[out err] => io}
54
options[:pgroup] = true unless Platform.windows? # NOTE: this is a bug only in Windows 7
55
56
WebDriver.logger.debug("Starting process: #{@command} with #{options}", id: :process)
57
@pid = Process.spawn(*@command, options)
58
WebDriver.logger.debug(" -> pid: #{@pid}", id: :process)
59
60
Process.detach(@pid) if detach
61
end
62
63
def stop(timeout = 3)
64
return unless @pid
65
return if exited?
66
67
terminate_and_wait_else_kill(timeout)
68
rescue Errno::ECHILD, Errno::ESRCH => e
69
# Process exited earlier than terminate/kill could catch
70
WebDriver.logger.debug(" -> process: #{@pid} does not exist (#{e.class.name})", id: :process)
71
end
72
73
def alive?
74
@pid && !exited?
75
end
76
77
def exited?
78
return false unless @pid
79
80
WebDriver.logger.debug("Checking if #{@pid} is exited:", id: :process)
81
_, @status = waitpid2(@pid, Process::WNOHANG | Process::WUNTRACED) if @status.nil?
82
return false if @status.nil?
83
84
exit_code = @status.exitstatus || @status.termsig
85
WebDriver.logger.debug(" -> exit code is #{exit_code.inspect}", id: :process)
86
87
!!exit_code
88
rescue Errno::ECHILD, Errno::ESRCH
89
WebDriver.logger.debug(" -> process: #{@pid} already finished", id: :process)
90
true
91
end
92
93
def poll_for_exit(timeout)
94
WebDriver.logger.debug("Polling #{timeout} seconds for exit of #{@pid}", id: :process)
95
96
end_time = Time.now + timeout
97
sleep POLL_INTERVAL until exited? || Time.now > end_time
98
99
raise TimeoutError, " -> #{@pid} still alive after #{timeout} seconds" unless exited?
100
end
101
102
def wait
103
return if exited?
104
105
_, @status = waitpid2(@pid)
106
end
107
108
private
109
110
def terminate_and_wait_else_kill(timeout)
111
WebDriver.logger.debug("Sending TERM to process: #{@pid}", id: :process)
112
terminate(@pid)
113
poll_for_exit(timeout)
114
115
WebDriver.logger.debug(" -> stopped #{@pid}", id: :process)
116
rescue TimeoutError, Errno::EINVAL
117
WebDriver.logger.debug(" -> sending KILL to process: #{@pid}", id: :process)
118
kill(@pid)
119
wait
120
WebDriver.logger.debug(" -> killed #{@pid}", id: :process)
121
end
122
123
def terminate(pid)
124
Process.kill(SIGTERM, pid)
125
rescue Errno::ECHILD, Errno::ESRCH
126
# Process does not exist, nothing to terminate
127
end
128
129
def kill(pid)
130
Process.kill(SIGKILL, pid)
131
rescue Errno::ECHILD, Errno::ESRCH
132
# Process does not exist, nothing to kill
133
end
134
135
def waitpid2(pid, flags = 0)
136
Process.waitpid2(pid, flags)
137
end
138
end # ChildProcess
139
end # WebDriver
140
end # Selenium
141
142