aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty/tty_buffer.c
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2013-06-15 09:36:07 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-23 19:47:08 -0400
commit7391ee16950e772076d321792d9fbf030f921345 (patch)
treec0b17ff0622f801f05bb11228426bdc90e8ffdc2 /drivers/tty/tty_buffer.c
parent809850b7a5fcc0a96d023e1171a7944c60fd5a71 (diff)
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: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/tty_buffer.c')
-rw-r--r--drivers/tty/tty_buffer.c49
1 files changed, 18 insertions, 31 deletions
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 069640e5b9c0..231b7a8710f1 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -49,13 +49,16 @@ void tty_buffer_free_all(struct tty_port *port)
49 49
50 while ((p = buf->head) != NULL) { 50 while ((p = buf->head) != NULL) {
51 buf->head = p->next; 51 buf->head = p->next;
52 kfree(p); 52 if (p->size > 0)
53 kfree(p);
53 } 54 }
54 llist = llist_del_all(&buf->free); 55 llist = llist_del_all(&buf->free);
55 llist_for_each_entry_safe(p, next, llist, free) 56 llist_for_each_entry_safe(p, next, llist, free)
56 kfree(p); 57 kfree(p);
57 58
58 buf->tail = NULL; 59 tty_buffer_reset(&buf->sentinel, 0);
60 buf->head = &buf->sentinel;
61 buf->tail = &buf->sentinel;
59 buf->memory_used = 0; 62 buf->memory_used = 0;
60} 63}
61 64
@@ -120,7 +123,7 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b)
120 123
121 if (b->size > MIN_TTYB_SIZE) 124 if (b->size > MIN_TTYB_SIZE)
122 kfree(b); 125 kfree(b);
123 else 126 else if (b->size > 0)
124 llist_add(&b->free, &buf->free); 127 llist_add(&b->free, &buf->free);
125} 128}
126 129
@@ -140,8 +143,6 @@ static void __tty_buffer_flush(struct tty_port *port)
140 struct tty_bufhead *buf = &port->buf; 143 struct tty_bufhead *buf = &port->buf;
141 struct tty_buffer *next; 144 struct tty_buffer *next;
142 145
143 if (unlikely(buf->head == NULL))
144 return;
145 while ((next = buf->head->next) != NULL) { 146 while ((next = buf->head->next) != NULL) {
146 tty_buffer_free(port, buf->head); 147 tty_buffer_free(port, buf->head);
147 buf->head = next; 148 buf->head = next;
@@ -200,23 +201,14 @@ int tty_buffer_request_room(struct tty_port *port, size_t size)
200 int left; 201 int left;
201 unsigned long flags; 202 unsigned long flags;
202 spin_lock_irqsave(&buf->lock, flags); 203 spin_lock_irqsave(&buf->lock, flags);
203 /* OPTIMISATION: We could keep a per tty "zero" sized buffer to
204 remove this conditional if its worth it. This would be invisible
205 to the callers */
206 b = buf->tail; 204 b = buf->tail;
207 if (b != NULL) 205 left = b->size - b->used;
208 left = b->size - b->used;
209 else
210 left = 0;
211 206
212 if (left < size) { 207 if (left < size) {
213 /* This is the slow path - looking for new buffers to use */ 208 /* This is the slow path - looking for new buffers to use */
214 if ((n = tty_buffer_alloc(port, size)) != NULL) { 209 if ((n = tty_buffer_alloc(port, size)) != NULL) {
215 if (b != NULL) { 210 b->next = n;
216 b->next = n; 211 b->commit = b->used;
217 b->commit = b->used;
218 } else
219 buf->head = n;
220 buf->tail = n; 212 buf->tail = n;
221 } else 213 } else
222 size = left; 214 size = left;
@@ -247,10 +239,8 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port,
247 int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); 239 int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
248 int space = tty_buffer_request_room(port, goal); 240 int space = tty_buffer_request_room(port, goal);
249 struct tty_buffer *tb = port->buf.tail; 241 struct tty_buffer *tb = port->buf.tail;
250 /* If there is no space then tb may be NULL */ 242 if (unlikely(space == 0))
251 if (unlikely(space == 0)) {
252 break; 243 break;
253 }
254 memcpy(char_buf_ptr(tb, tb->used), chars, space); 244 memcpy(char_buf_ptr(tb, tb->used), chars, space);
255 memset(flag_buf_ptr(tb, tb->used), flag, space); 245 memset(flag_buf_ptr(tb, tb->used), flag, space);
256 tb->used += space; 246 tb->used += space;
@@ -285,10 +275,8 @@ int tty_insert_flip_string_flags(struct tty_port *port,
285 int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); 275 int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE);
286 int space = tty_buffer_request_room(port, goal); 276 int space = tty_buffer_request_room(port, goal);
287 struct tty_buffer *tb = port->buf.tail; 277 struct tty_buffer *tb = port->buf.tail;
288 /* If there is no space then tb may be NULL */ 278 if (unlikely(space == 0))
289 if (unlikely(space == 0)) {
290 break; 279 break;
291 }
292 memcpy(char_buf_ptr(tb, tb->used), chars, space); 280 memcpy(char_buf_ptr(tb, tb->used), chars, space);
293 memcpy(flag_buf_ptr(tb, tb->used), flags, space); 281 memcpy(flag_buf_ptr(tb, tb->used), flags, space);
294 tb->used += space; 282 tb->used += space;
@@ -322,8 +310,7 @@ void tty_schedule_flip(struct tty_port *port)
322 WARN_ON(port->low_latency); 310 WARN_ON(port->low_latency);
323 311
324 spin_lock_irqsave(&buf->lock, flags); 312 spin_lock_irqsave(&buf->lock, flags);
325 if (buf->tail != NULL) 313 buf->tail->commit = buf->tail->used;
326 buf->tail->commit = buf->tail->used;
327 spin_unlock_irqrestore(&buf->lock, flags); 314 spin_unlock_irqrestore(&buf->lock, flags);
328 schedule_work(&buf->work); 315 schedule_work(&buf->work);
329} 316}
@@ -438,8 +425,8 @@ static void flush_to_ldisc(struct work_struct *work)
438 spin_lock_irqsave(&buf->lock, flags); 425 spin_lock_irqsave(&buf->lock, flags);
439 426
440 if (!test_and_set_bit(TTYP_FLUSHING, &port->iflags)) { 427 if (!test_and_set_bit(TTYP_FLUSHING, &port->iflags)) {
441 struct tty_buffer *head; 428 while (1) {
442 while ((head = buf->head) != NULL) { 429 struct tty_buffer *head = buf->head;
443 int count; 430 int count;
444 431
445 count = head->commit - head->read; 432 count = head->commit - head->read;
@@ -509,8 +496,7 @@ void tty_flip_buffer_push(struct tty_port *port)
509 unsigned long flags; 496 unsigned long flags;
510 497
511 spin_lock_irqsave(&buf->lock, flags); 498 spin_lock_irqsave(&buf->lock, flags);
512 if (buf->tail != NULL) 499 buf->tail->commit = buf->tail->used;
513 buf->tail->commit = buf->tail->used;
514 spin_unlock_irqrestore(&buf->lock, flags); 500 spin_unlock_irqrestore(&buf->lock, flags);
515 501
516 if (port->low_latency) 502 if (port->low_latency)
@@ -535,8 +521,9 @@ void tty_buffer_init(struct tty_port *port)
535 struct tty_bufhead *buf = &port->buf; 521 struct tty_bufhead *buf = &port->buf;
536 522
537 spin_lock_init(&buf->lock); 523 spin_lock_init(&buf->lock);
538 buf->head = NULL; 524 tty_buffer_reset(&buf->sentinel, 0);
539 buf->tail = NULL; 525 buf->head = &buf->sentinel;
526 buf->tail = &buf->sentinel;
540 init_llist_head(&buf->free); 527 init_llist_head(&buf->free);
541 buf->memory_used = 0; 528 buf->memory_used = 0;
542 INIT_WORK(&buf->work, flush_to_ldisc); 529 INIT_WORK(&buf->work, flush_to_ldisc);