Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 14 Dec 2016 12:11:46 +0000
From:      Ian Campbell <ian.campbell@docker.com>
To:        Peter Grehan <grehan@freebsd.org>
Cc:        Tycho Nightingale <tychon@freebsd.org>, freebsd-virtualization@freebsd.org, Anil Madhavapeddy <anil@recoil.org>
Subject:   Re: Query about bhyve's blockif_cancel and the signalling mechanisms
Message-ID:  <CAOc2ZU1u29c4oY8Q8BcWrTp15qftZLONuXqYsaOXNq01FuExFw@mail.gmail.com>
In-Reply-To: <631f775d-8d61-55ba-1e7b-8ce4fcadcbf3@freebsd.org>
References:  <CAOc2ZU0Hqvctv767ESu6fKwXJ3W35ReqM3=ud6G3MzKLSEY=Bw@mail.gmail.com> <631f775d-8d61-55ba-1e7b-8ce4fcadcbf3@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On 13 December 2016 at 06:32, Peter Grehan <grehan@freebsd.org> wrote:
>> I've dug around in the FreeBSD kevent and signal man pages but I
>> cannot find any part which describes anything of the semantics which
>> bhyve seems to be relying on (which seems to be that the system call
>> in the target thread will return EINTR at some point before the thread
>> which is "handling" the signal via kevent/kqueue sees that event).
>>
>> Have I missed something here or is bhyve relying on some subtle
>> underlying semantics?
>
>
>  I didn't think it too FreeBSD-specific - if a thread is blocked in a system
> call, sending a signal should force it to exit on most Unices.

Sure, the thing I was unsure about was whether that was the case when
the application has asked for signal delivery via some other mechanism
than the traditional asynchronous signal handlers such as kevent.
Especially when the signal itself if SIG_IGN'd (as SIGCONT is in bhyve
in blockif_init).

The attached test tries to mimic what bhyve is doing, it has a blocked
io thread and a thread handling kevents, with the signal set to
SIG_IGN. A signal is then sent to the io thread.

Running it on FreeBSD 11[0] it outputs:

main:          starting kevent thread
main:          starting io thread
kevent thread: opening kqueue
kevent thread: setting up SIGCONT event
kevent thread: waiting for SIGCONT event
io thread:     blocking in read
main:          sending SIGCONT io thread
main:          waiting for io thread to complete
kevent thread: received SIGCONT event

and then blocks indefinitely. The kevent thread has seen the SIGCONT
but the read in the io thread has not been interrupted.

If I #define USE_HANDLER at the same time as USE_KEVENT then instead I see:

main:          starting kevent thread
kevent thread: opening kqueue
main:          starting io thread
kevent thread: setting up SIGCONT event
io thread:     blocking in read
kevent thread: waiting for SIGCONT event
main:          sending SIGCONT io thread
sigcont:       received SIGCONT
main:          waiting for io thread to complete
io thread:     Read from pipe returned errno=4: Interrupted system call
io thread:     exiting
main:          waiting for kevent thread to complete
kevent thread: received SIGCONT event
main:          all done

i.e. the signal is seen by both the kevent thread and the async
handler in the io thread, the latter of which causes EINTR from the
read.

bhyve sets SIGCONT to SIG_IGN so falls into the first case I think. If
there is really a bhyve bug here I think it should be fixable with a
dummy SIGCONT handler alongside the kevent thread. I think it wouldn't
be reliant on a specific ordering of kevent vs async handler
invocation due to the while loop on status == BUSY in blockif_cancel
which Tycho opened my eyes to earlier.

Ian.

[0] ftp://ftp.freebsd.org/pub/FreeBSD/releases/VM-IMAGES/11.0-RELEASE/amd64/Latest/FreeBSD-11.0-RELEASE-amd64.qcow2.xz
fed to virt-manager.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAOc2ZU1u29c4oY8Q8BcWrTp15qftZLONuXqYsaOXNq01FuExFw>