Commit 62340e7e authored by Kirill Smelkov's avatar Kirill Smelkov

wcfs: tests: Add context to tWCFS

This testing helper limits whole test time to detect FUSE-related
deadlocks via aborting FUSE connection on timeout. It is working good so
far. But soon we will need pinkill-related tests, where timeout will
need to be detected independently of FUSE connection. Expose tWCFS.ctx
for tests to be able to use this context and do things limited in time.
Adjust FUSE aborting to correlate exactly with this context
cancellation.
parent 11cc982c
# Copyright (C) 2019-2021 Nexedi SA and Contributors.
# Copyright (C) 2019-2024 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
......@@ -33,7 +33,7 @@ from posix.types cimport off_t
from cpython.exc cimport PyErr_SetFromErrno
from golang cimport chan, pychan, select, panic, topyexc, cbool
from golang cimport chan, pychan, select, panic, topyexc, cbool, structZ
from golang cimport sync, time
# _tWCFS is pyx part of tWCFS.
......@@ -53,16 +53,15 @@ cdef class _tWCFS:
# but pin handler is failing one way or another - select will wake-up
# but, if _abort_ontimeout uses GIL, won't continue to run trying to lock
# GIL -> deadlock.
def _abort_ontimeout(_tWCFS t, int fdabort, double dt, pychan nogilready not None):
cdef chan[double] timeoutch = time.after(dt)
def _abort_ontimeout(_tWCFS t, int fdabort, double dt, pychan timeoutch not None, pychan nogilready not None):
emsg1 = "\nC: test timed out after %.1fs\n" % (dt / time.second)
cdef char *_emsg1 = emsg1
with nogil:
# tell main thread that we entered nogil world
nogilready.chan_structZ().close()
t.__abort_ontimeout(dt, timeoutch, fdabort, _emsg1)
t.__abort_ontimeout(timeoutch.chan_structZ(), fdabort, _emsg1)
cdef void __abort_ontimeout(_tWCFS t, double dt, chan[double] timeoutch,
cdef void __abort_ontimeout(_tWCFS t, chan[structZ] timeoutch,
int fdabort, const char *emsg1) nogil except +topyexc:
_ = select([
timeoutch.recvs(), # 0
......
......@@ -358,6 +358,13 @@ class tWCFS(_tWCFS):
assert is_mountpoint(wc.mountpoint)
t.wc = wc
# the whole test is limited in time to detect deadlocks
# NOTE with_timeout must be << timeout
# NOTE wcfs_pin_timeout must be >> timeout
timeout = 10*time.second
t.ctx, t._ctx_cancel = context.with_timeout(context.background(), timeout)
# make sure any stuck FUSE request is aborted. To do so
# force-unmount wcfs on timeout to unstuck current test and let it fail.
# Force-unmount can be done reliably only by writing into
# /sys/fs/fuse/connections/<X>/abort. For everything else there are
......@@ -366,7 +373,7 @@ class tWCFS(_tWCFS):
# still wait for request completion even after fatal signal )
nogilready = chan(dtype='C.structZ')
t._wcfuseabort = os.dup(wc._wcsrv._fuseabort.fileno())
go(t._abort_ontimeout, t._wcfuseabort, 10*time.second, nogilready) # NOTE must be: with_timeout << · << wcfs_pin_timeout
go(t._abort_ontimeout, t._wcfuseabort, timeout, t.ctx.done(), nogilready)
nogilready.recv() # wait till _abort_ontimeout enters nogil
t._stats_prev = None
......@@ -380,6 +387,7 @@ class tWCFS(_tWCFS):
# that wcfs server exits.
@func
def close(t):
defer(t._ctx_cancel)
def _():
os.close(t._wcfuseabort)
defer(_)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment