Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7391ee16 authored by Peter Hurley's avatar Peter Hurley Committed by Greg Kroah-Hartman
Browse files

tty: Simplify flip buffer list with 0-sized sentinel



Use a 0-sized sentinel to avoid assigning the head ptr from
the driver side thread. This also eliminates testing head/tail
for NULL.

When the sentinel is first 'consumed' by the buffer work
(or by tty_buffer_flush()), it is detached from the list but not
freed nor added to the free list. Both buffer work and
tty_buffer_flush() continue to preserve at least 1 flip buffer
to which head & tail is pointed.

Signed-off-by: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 809850b7
Loading
Loading
Loading
Loading
+18 −31
Original line number Original line Diff line number Diff line
@@ -49,13 +49,16 @@ void tty_buffer_free_all(struct tty_port *port)


	while ((p = buf->head) != NULL) {
	while ((p = buf->head) != NULL) {
		buf->head = p->next;
		buf->head = p->next;
		if (p->size > 0)
			kfree(p);
			kfree(p);
	}
	}
	llist = llist_del_all(&buf->free);
	llist = llist_del_all(&buf->free);
	llist_for_each_entry_safe(p, next, llist, free)
	llist_for_each_entry_safe(p, next, llist, free)
		kfree(p);
		kfree(p);


	buf->tail = NULL;
	tty_buffer_reset(&buf->sentinel, 0);
	buf->head = &buf->sentinel;
	buf->tail = &buf->sentinel;
	buf->memory_used = 0;
	buf->memory_used = 0;
}
}


@@ -120,7 +123,7 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)


	if (b->size > MIN_TTYB_SIZE)
	if (b->size > MIN_TTYB_SIZE)
		kfree(b);
		kfree(b);
	else
	else if (b->size > 0)
		llist_add(&b->free, &buf->free);
		llist_add(&b->free, &buf->free);
}
}


@@ -140,8 +143,6 @@ static void __tty_buffer_flush(struct tty_port *port)
	struct tty_bufhead *buf = &port->buf;
	struct tty_bufhead *buf = &port->buf;
	struct tty_buffer *next;
	struct tty_buffer *next;


	if (unlikely(buf->head == NULL))
		return;
	while ((next = buf->head->next) != NULL) {
	while ((next = buf->head->next) != NULL) {
		tty_buffer_free(port, buf->head);
		tty_buffer_free(port, buf->head);
		buf->head = next;
		buf->head = next;
@@ -200,23 +201,14 @@ int tty_buffer_request_room(struct tty_port *port, size_t size)
	int left;
	int left;
	unsigned long flags;
	unsigned long flags;
	spin_lock_irqsave(&buf->lock, flags);
	spin_lock_irqsave(&buf->lock, flags);
	/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
	   remove this conditional if its worth it. This would be invisible
	   to the callers */
	b = buf->tail;
	b = buf->tail;
	if (b != NULL)
	left = b->size - b->used;
	left = b->size - b->used;
	else
		left = 0;


	if (left < size) {
	if (left < size) {
		/* This is the slow path - looking for new buffers to use */
		/* This is the slow path - looking for new buffers to use */
		if ((n = tty_buffer_alloc(port, size)) != NULL) {
		if ((n = tty_buffer_alloc(port, size)) != NULL) {
			if (b != NULL) {
			b->next = n;
			b->next = n;
			b->commit = b->used;
			b->commit = b->used;
			} else
				buf->head = n;
			buf->tail = n;
			buf->tail = n;
		} else
		} else
			size = left;
			size = left;
@@ -247,10 +239,8 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port,
		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
		int space = tty_buffer_request_room(port, goal);
		int space = tty_buffer_request_room(port, goal);
		struct tty_buffer *tb = port->buf.tail;
		struct tty_buffer *tb = port->buf.tail;
		/* If there is no space then tb may be NULL */
		if (unlikely(space == 0))
		if (unlikely(space == 0)) {
			break;
			break;
		}
		memcpy(char_buf_ptr(tb, tb->used), chars, space);
		memcpy(char_buf_ptr(tb, tb->used), chars, space);
		memset(flag_buf_ptr(tb, tb->used), flag, space);
		memset(flag_buf_ptr(tb, tb->used), flag, space);
		tb->used += space;
		tb->used += space;
@@ -285,10 +275,8 @@ int tty_insert_flip_string_flags(struct tty_port *port,
		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
		int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
		int space = tty_buffer_request_room(port, goal);
		int space = tty_buffer_request_room(port, goal);
		struct tty_buffer *tb = port->buf.tail;
		struct tty_buffer *tb = port->buf.tail;
		/* If there is no space then tb may be NULL */
		if (unlikely(space == 0))
		if (unlikely(space == 0)) {
			break;
			break;
		}
		memcpy(char_buf_ptr(tb, tb->used), chars, space);
		memcpy(char_buf_ptr(tb, tb->used), chars, space);
		memcpy(flag_buf_ptr(tb, tb->used), flags, space);
		memcpy(flag_buf_ptr(tb, tb->used), flags, space);
		tb->used += space;
		tb->used += space;
@@ -322,7 +310,6 @@ void tty_schedule_flip(struct tty_port *port)
	WARN_ON(port->low_latency);
	WARN_ON(port->low_latency);


	spin_lock_irqsave(&buf->lock, flags);
	spin_lock_irqsave(&buf->lock, flags);
	if (buf->tail != NULL)
	buf->tail->commit = buf->tail->used;
	buf->tail->commit = buf->tail->used;
	spin_unlock_irqrestore(&buf->lock, flags);
	spin_unlock_irqrestore(&buf->lock, flags);
	schedule_work(&buf->work);
	schedule_work(&buf->work);
@@ -438,8 +425,8 @@ static void flush_to_ldisc(struct work_struct *work)
	spin_lock_irqsave(&buf->lock, flags);
	spin_lock_irqsave(&buf->lock, flags);


	if (!test_and_set_bit(TTYP_FLUSHING, &port->iflags)) {
	if (!test_and_set_bit(TTYP_FLUSHING, &port->iflags)) {
		struct tty_buffer *head;
		while (1) {
		while ((head = buf->head) != NULL) {
			struct tty_buffer *head = buf->head;
			int count;
			int count;


			count = head->commit - head->read;
			count = head->commit - head->read;
@@ -509,7 +496,6 @@ void tty_flip_buffer_push(struct tty_port *port)
	unsigned long flags;
	unsigned long flags;


	spin_lock_irqsave(&buf->lock, flags);
	spin_lock_irqsave(&buf->lock, flags);
	if (buf->tail != NULL)
	buf->tail->commit = buf->tail->used;
	buf->tail->commit = buf->tail->used;
	spin_unlock_irqrestore(&buf->lock, flags);
	spin_unlock_irqrestore(&buf->lock, flags);


@@ -535,8 +521,9 @@ void tty_buffer_init(struct tty_port *port)
	struct tty_bufhead *buf = &port->buf;
	struct tty_bufhead *buf = &port->buf;


	spin_lock_init(&buf->lock);
	spin_lock_init(&buf->lock);
	buf->head = NULL;
	tty_buffer_reset(&buf->sentinel, 0);
	buf->tail = NULL;
	buf->head = &buf->sentinel;
	buf->tail = &buf->sentinel;
	init_llist_head(&buf->free);
	init_llist_head(&buf->free);
	buf->memory_used = 0;
	buf->memory_used = 0;
	INIT_WORK(&buf->work, flush_to_ldisc);
	INIT_WORK(&buf->work, flush_to_ldisc);
+1 −0
Original line number Original line Diff line number Diff line
@@ -67,6 +67,7 @@ static inline char *flag_buf_ptr(struct tty_buffer *b, int ofs)
struct tty_bufhead {
struct tty_bufhead {
	struct work_struct work;
	struct work_struct work;
	spinlock_t lock;
	spinlock_t lock;
	struct tty_buffer sentinel;
	struct tty_buffer *head;	/* Queue head */
	struct tty_buffer *head;	/* Queue head */
	struct tty_buffer *tail;	/* Active buffer */
	struct tty_buffer *tail;	/* Active buffer */
	struct llist_head free;		/* Free queue head */
	struct llist_head free;		/* Free queue head */