Skip to content

Commit 01dd6bc

Browse files
committed
aexpect: Use time.monotonic() for time-diff operations
to avoid problems with NTP (or iffy clock sources) let's use time.monotonic() for time difference operations. Signed-off-by: Lukáš Doktor <ldoktor@redhat.com>
1 parent 9c66c68 commit 01dd6bc

5 files changed

Lines changed: 40 additions & 40 deletions

File tree

aexpect/client.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,8 @@ def _get_aexpect_helper(self, helper_cmd, pass_fds, echo, command):
253253
# Wait for the server to complete its initialization
254254
full_output = ""
255255
pattern = f"Server {self.a_id} ready"
256-
end_time = time.time() + 60
257-
while time.time() < end_time:
256+
end_time = time.monotonic() + 60
257+
while time.monotonic() < end_time:
258258
output = sub.stdout.readline().decode(self.encoding, "ignore")
259259
if pattern in output:
260260
break
@@ -834,7 +834,7 @@ def _read_nonblocking(self, internal_timeout=None, timeout=None):
834834
internal_timeout *= 1000
835835
end_time = None
836836
if timeout:
837-
end_time = time.time() + timeout
837+
end_time = time.monotonic() + timeout
838838
expect_pipe = self._get_fd("expect")
839839
poller = select.poll()
840840
poller.register(expect_pipe, select.POLLIN)
@@ -853,7 +853,7 @@ def _read_nonblocking(self, internal_timeout=None, timeout=None):
853853
data += raw_data.decode(self.encoding, "ignore")
854854
else:
855855
return read, data
856-
if end_time and time.time() > end_time:
856+
if end_time and time.monotonic() > end_time:
857857
return read, data
858858

859859
def read_nonblocking(self, internal_timeout=None, timeout=None):
@@ -941,10 +941,10 @@ def read_until_output_matches(self, patterns, filter_func=lambda x: x,
941941
poller = select.poll()
942942
poller.register(expect_pipe, select.POLLIN)
943943
output = ""
944-
end_time = time.time() + timeout
944+
end_time = time.monotonic() + timeout
945945
while True:
946946
try:
947-
max_ms = int((end_time - time.time()) * 1000)
947+
max_ms = int((end_time - time.monotonic()) * 1000)
948948
poll_timeout_ms = max(0, max_ms)
949949
poll_status = poller.poll(poll_timeout_ms)
950950
except select.error:
@@ -953,7 +953,7 @@ def read_until_output_matches(self, patterns, filter_func=lambda x: x,
953953
raise ExpectTimeoutError(patterns, output)
954954
# Read data from child
955955
read, data = self._read_nonblocking(internal_timeout,
956-
end_time - time.time())
956+
end_time - time.monotonic())
957957
if not read:
958958
break
959959
if not data:
@@ -1187,10 +1187,10 @@ def is_responsive(self, timeout=5.0):
11871187
# Send a newline
11881188
self.sendline()
11891189
# Wait up to timeout seconds for some output from the child
1190-
end_time = time.time() + timeout
1191-
while time.time() < end_time:
1190+
end_time = time.monotonic() + timeout
1191+
while time.monotonic() < end_time:
11921192
time.sleep(0.5)
1193-
if self.read_nonblocking(0, end_time - time.time()).strip():
1193+
if self.read_nonblocking(0, end_time - time.monotonic()).strip():
11941194
return True
11951195
# No output -- report unresponsive
11961196
return False
@@ -1299,8 +1299,8 @@ def cmd_output_safe(self, cmd, timeout=60, strip_console_codes=False):
12991299
self.sendline(cmd)
13001300
out = ""
13011301
success = False
1302-
start_time = time.time()
1303-
while (time.time() - start_time) < timeout:
1302+
start_time = time.monotonic()
1303+
while (time.monotonic() - start_time) < timeout:
13041304
try:
13051305
out += self.read_up_to_prompt(0.5)
13061306
success = True
@@ -1567,8 +1567,8 @@ def run_tail(command, termination_func=None, output_func=None,
15671567
pass_fds=pass_fds,
15681568
encoding=encoding)
15691569

1570-
end_time = time.time() + timeout
1571-
while time.time() < end_time and bg_process.is_alive():
1570+
end_time = time.monotonic() + timeout
1571+
while time.monotonic() < end_time and bg_process.is_alive():
15721572
time.sleep(0.1)
15731573

15741574
return bg_process
@@ -1610,8 +1610,8 @@ def run_bg(command, termination_func=None, output_func=None, output_prefix="",
16101610
pass_fds=pass_fds,
16111611
encoding=encoding)
16121612

1613-
end_time = time.time() + timeout
1614-
while time.time() < end_time and bg_process.is_alive():
1613+
end_time = time.monotonic() + timeout
1614+
while time.monotonic() < end_time and bg_process.is_alive():
16151615
time.sleep(0.1)
16161616

16171617
return bg_process

aexpect/remote.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,9 @@ def wait_for_login(client, host, port, username, password, prompt,
464464
"""
465465
LOG.debug("Attempting to log into %s:%s using %s (timeout %ds)",
466466
host, port, client, timeout)
467-
end_time = time.time() + timeout
467+
end_time = time.monotonic() + timeout
468468
verbose = False
469-
while time.time() < end_time:
469+
while time.monotonic() < end_time:
470470
try:
471471
return remote_login(client, host, port, username, password, prompt,
472472
linesep, log_filename, log_function,
@@ -1100,9 +1100,9 @@ def transfer(*args, **kwargs):
11001100
msg = f"Copy file from {args[0]}:{args[5]} to {args[6]}, "
11011101
else:
11021102
msg = f"Copy file from {args[5]} to {args[0]}:{args[6]}, "
1103-
start_time = time.time()
1103+
start_time = time.monotonic()
11041104
ret = func(*args, **kwargs)
1105-
elapsed_time = time.time() - start_time
1105+
elapsed_time = time.monotonic() - start_time
11061106
if kwargs.get("filesize", None) is not None:
11071107
throughput = kwargs["filesize"] / elapsed_time
11081108
msg += f"estimated throughput: {throughput:.2f} MB/s"

aexpect/rss_client.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def __init__(self, address, port, log_func=None, timeout=20):
142142
"receive magic number") from timeout_error
143143
self._send(struct.pack("=i", CHUNKSIZE))
144144
self._log_func = log_func
145-
self._last_time = time.time()
145+
self._last_time = time.monotonic()
146146
self._last_transferred = 0
147147
self.transferred = 0
148148

@@ -170,10 +170,10 @@ def _send(self, data, timeout=60):
170170

171171
def _receive(self, size, timeout=60):
172172
strs = []
173-
end_time = time.time() + timeout
173+
end_time = time.monotonic() + timeout
174174
try:
175175
while size > 0:
176-
timeout = end_time - time.time()
176+
timeout = end_time - time.monotonic()
177177
if timeout <= 0:
178178
raise socket.timeout
179179
self._socket.settimeout(timeout)
@@ -195,14 +195,14 @@ def _receive(self, size, timeout=60):
195195

196196
def _report_stats(self, data):
197197
if self._log_func:
198-
delta = time.time() - self._last_time
198+
delta = time.monotonic() - self._last_time
199199
if delta >= 1:
200200
transferred = self.transferred / 1048576.
201201
speed = (self.transferred - self._last_transferred) / delta
202202
speed /= 1048576.
203203
self._log_func(f"{data} {transferred:.3f} MB ({speed:.3f}"
204204
" MB/sec)")
205-
self._last_time = time.time()
205+
self._last_time = time.monotonic()
206206
self._last_transferred = self.transferred
207207

208208
def _send_packet(self, data, timeout=60):
@@ -224,10 +224,10 @@ def _send_file_chunks(self, filename, timeout=60):
224224
self._log_func(f"Sending file {filename}")
225225
with open(filename, "rb") as file_handle:
226226
try:
227-
end_time = time.time() + timeout
227+
end_time = time.monotonic() + timeout
228228
while True:
229229
data = file_handle.read(CHUNKSIZE)
230-
self._send_packet(data, int(end_time - time.time()))
230+
self._send_packet(data, int(end_time - time.monotonic()))
231231
if len(data) < CHUNKSIZE:
232232
break
233233
except FileTransferError as error:
@@ -239,9 +239,9 @@ def _receive_file_chunks(self, filename, timeout=60):
239239
self._log_func(f"Receiving file {filename}")
240240
with open(filename, "wb") as file_handle:
241241
try:
242-
end_time = time.time() + timeout
242+
end_time = time.monotonic() + timeout
243243
while True:
244-
data = self._receive_packet(int(end_time - time.time()))
244+
data = self._receive_packet(int(end_time - time.monotonic()))
245245
file_handle.write(data)
246246
if len(data) < CHUNKSIZE:
247247
break
@@ -299,7 +299,7 @@ def _upload_file(self, path, end_time):
299299
if os.path.isfile(path):
300300
self._send_msg(RSS_CREATE_FILE)
301301
self._send_packet(os.path.basename(path).encode())
302-
self._send_file_chunks(path, end_time - time.time())
302+
self._send_file_chunks(path, end_time - time.monotonic())
303303
elif os.path.isdir(path):
304304
self._send_msg(RSS_CREATE_DIR)
305305
self._send_packet(os.path.basename(path).encode())
@@ -342,7 +342,7 @@ def upload(self, src_pattern, dst_path, timeout=600):
342342
message to the client
343343
:note: Other exceptions can be raised.
344344
"""
345-
end_time = time.time() + timeout
345+
end_time = time.monotonic() + timeout
346346
try:
347347
try:
348348
self._send_msg(RSS_SET_PATH)
@@ -362,7 +362,7 @@ def upload(self, src_pattern, dst_path, timeout=600):
362362
"does not match any files "
363363
"or directories")
364364
# Look for RSS_OK or RSS_ERROR
365-
msg = self._receive_msg(int(end_time - time.time()))
365+
msg = self._receive_msg(int(end_time - time.monotonic()))
366366
if msg == RSS_OK:
367367
return
368368
if msg == RSS_ERROR:
@@ -438,7 +438,7 @@ def download(self, src_pattern, dst_path, timeout=600):
438438
:note: Other exceptions can be raised.
439439
"""
440440
dst_path = os.path.abspath(dst_path)
441-
end_time = time.time() + timeout
441+
end_time = time.monotonic() + timeout
442442
file_count = 0
443443
dir_count = 0
444444
try:
@@ -454,7 +454,7 @@ def download(self, src_pattern, dst_path, timeout=600):
454454
filename = self._receive_packet().decode()
455455
if os.path.isdir(dst_path):
456456
dst_path = os.path.join(dst_path, filename)
457-
self._receive_file_chunks(dst_path, int(end_time - time.time()))
457+
self._receive_file_chunks(dst_path, int(end_time - time.monotonic()))
458458
dst_path = os.path.dirname(dst_path)
459459
file_count += 1
460460
elif msg == RSS_CREATE_DIR:

aexpect/shared.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ def get_lock_fd(filename, timeout=-1):
2929
lock_flags = fcntl.LOCK_EX
3030
if timeout > 0:
3131
lock_flags |= fcntl.LOCK_NB
32-
end_time = time.time() + timeout if timeout > 0 else -1
32+
end_time = time.monotonic() + timeout if timeout > 0 else -1
3333
while True:
3434
try:
3535
fcntl.flock(lock_fd, lock_flags)
3636
break
3737
except IOError:
38-
if time.time() > end_time:
38+
if time.monotonic() > end_time:
3939
os.close(lock_fd)
4040
raise
4141
return lock_fd

aexpect/utils/wait.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ def wait_for(func, timeout, first=0.0, step=1.0, text=None):
3030
:param step: Time to sleep between attempts in seconds
3131
:param text: Text to print while waiting, for debug purposes
3232
"""
33-
start_time = time.time()
34-
end_time = time.time() + timeout
33+
start_time = time.monotonic()
34+
end_time = time.monotonic() + timeout
3535

3636
time.sleep(first)
3737

38-
while time.time() < end_time:
38+
while time.monotonic() < end_time:
3939
if text:
40-
_LOG.debug("%s (%f secs)", text, (time.time() - start_time))
40+
_LOG.debug("%s (%f secs)", text, (time.monotonic() - start_time))
4141

4242
output = func()
4343
if output:

0 commit comments

Comments
 (0)