From: Peter Hurley <peter@hurleysoftware.com>
To: One Thousand Gnomes <gnomes@lxorguk.ukuu.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Jiri Slaby <jslaby@suse.cz>,
linux-kernel@vger.kernel.org, linux-serial@vger.kernel.org
Subject: Re: [PATCH tty-next 0/4] tty: Fix ^C echo
Date: Wed, 04 Dec 2013 12:42:36 -0500 [thread overview]
Message-ID: <529F698C.6040603@hurleysoftware.com> (raw)
In-Reply-To: <20131203142011.371067ea@alan.etchedpixels.co.uk>
On 12/03/2013 09:20 AM, One Thousand Gnomes wrote:
>> These types of nested lock problems are common when different layers use
>> the same interface (the fb subsystem's use of the vt driver is another
>> example).
>
> They are, and they end up nasty and eventually become impossible to fix.
> Better to fix the underlying fundamental error as and when we can. The
> current state of vt and fb and drm and handling accelerated scrolling of
> a quota warning on drm on fb on vt is a testimony to what happens if you
> don't go back and fix it properly now and then.
>
> In this case I would argue there is a fundamental error. That is trying to
> combine locking of the structures for buffers and locking the receive
> path. It's a mistake and I don't see how you can properly clean up the
> tty layer with that mix of high and low level lock in one. It's already
> turned into a hackfest with buf->priority.
>
> The old code wasn't the right answer either but did isolate the locks
> better.
>
>
> We've got three confused locks IMHO all stuck in as one
>
> - integrity of the buffer queue
> - lifetime of a buffer (don't free a buffer as someone else is
> processing it)
> - serialization of flush_to_ldisc
Not so much confused as simply merged. Input processing is inherently
single-threaded; it makes sense to rely on that at the highest level
possible.
On smp, locked instructions and cache-line contention on the tty_buffer
list ptrs and read_buf indices account for more than 90% of the time cost
in the read path for real hardware (and over 95% for ptys).
Firewire, which is capable of sustained throughput in excess of 40MB/sec,
struggles to get over 5MB/sec through the tty layer. [And drm output
is orders-of-magnitude slower than that, which is just sad...]
buf->priority isn't a hackfest; it's a zero-cost-in-read-path mechanism
for interrupting input processing, similar to the clock (or generation)
approach.
Although using locks is satisfyingly symmetrical, input processing vs.
buffer flush is an asymmetric problem.
> (as an aside it was historically always required that a low_latency
> caller correctly implemented its own serialization because you can't
> really get that locking totally clean except in the driver either)
>
>
> It's a bit of a drastic rethink of the idiom but the networking layer
> basically does this, and has to solve exactly the same problem space
>
>
> while((buf = tty_buffer_dequeue(port)) != NULL) {
> if (receive_buf(tty, buf) < 0) {
> tty_buffer_requeue_head(port, buf);
> break;
> }
> }
>
> tty_buffer_dequeue is trivial enough, tty_buffer_requeue_head is also
> trivial because we are single threading flush_to_ldisc. Flushing just
> requires ensuring we don't requeue the buffer so we have
>
> tty_buffer_requeue_head(port, buf)
> {
> lock(&port->buf.lock);
> if (port->buf.clock == buf->clock)
> requeue;
> else
> kfree
> }
>
> tty_buffer_flush(port)
> {
> port->buf.clock++;
> free buffers in queue
> }
>
> Flush is trivial - increment clock, empty queue. The lifetime handling
> will ensure the current buffer is either processed or returned but not
> requeued.
>
> Queuing data is also trivial - we just add to the buffer that is at the
> end of the queue, or start a new buffer if empty. The requeue_head will
> deal with the rest of it automagically
>
> Downsides - slightly more locking, probably several things I've missed.
>
> Upsides - tty buffer locking is clear and self contained, we invoke
> flush_to_ldisc without holding what are really low level locks, queue
> manipulation in flush_to_ldisc works just like anywhere else. The buffer
> is owned by the tty which means the tty must free it, which means the tty
> can 'borrow' a buffer for ldisc internal queueing without having to copy
> all the bytes and we get the backpressure on the queue for free as the
> network layer does.
>
> It does mean touching every ldisc but as far as I can see with the
> exception of n_tty the change in each case is (as usual) trivial.
While that would work, it's expensive extra locking in a path that 99.999%
of the time doesn't need it. I'd rather explore other solutions.
The clock/generation method seems like it might yield a lockless solution
for this problem, but maybe creates another one because the driver-side
would need to stamp the buffer (in essence, a flush could affect data
that has not yet been copied from the driver).
Still, it might be worth seeing if a solution lies in scheduling only
one flush_to_ldisc() per tty_buffer (per port) and letting it sleep
if receive_buf() can't accept more data [N_TTY would awaken the worker
instead of queueing it].
Regards,
Peter Hurley
next prev parent reply other threads:[~2013-12-04 17:42 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-12-02 21:12 [PATCH tty-next 0/4] tty: Fix ^C echo Peter Hurley
2013-12-02 21:12 ` [PATCH tty-next 1/4] tty: Fix stale tty_buffer_flush() comment Peter Hurley
2013-12-02 21:12 ` [PATCH tty-next 2/4] tty: Add flush_nested() tty driver method and accessor Peter Hurley
2013-12-02 21:12 ` [PATCH tty-next 3/4] tty: Fix pty flush Peter Hurley
2013-12-02 21:12 ` [PATCH tty-next 4/4] n_tty: Flush echoes for signal chars Peter Hurley
2013-12-02 21:12 ` Peter Hurley
2013-12-03 0:01 ` [PATCH tty-next 0/4] tty: Fix ^C echo One Thousand Gnomes
2013-12-03 3:22 ` Peter Hurley
2013-12-03 14:20 ` One Thousand Gnomes
2013-12-03 17:23 ` Convert termios to RCU (was Re: [PATCH tty-next 0/4] tty: Fix ^C echo) Peter Hurley
2013-12-04 0:14 ` Peter Hurley
2013-12-04 17:42 ` Peter Hurley [this message]
2013-12-05 0:13 ` [PATCH tty-next 0/4] tty: Fix ^C echo One Thousand Gnomes
2013-12-12 3:59 ` Peter Hurley
2013-12-12 15:44 ` One Thousand Gnomes
2013-12-09 1:12 ` Greg Kroah-Hartman
2013-12-09 13:19 ` Peter Hurley
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=529F698C.6040603@hurleysoftware.com \
--to=peter@hurleysoftware.com \
--cc=gnomes@lxorguk.ukuu.org.uk \
--cc=gregkh@linuxfoundation.org \
--cc=jslaby@suse.cz \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-serial@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.