diff options
author | Peter Hurley <peter@hurleysoftware.com> | 2013-06-15 09:36:07 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-07-23 19:47:08 -0400 |
commit | 7391ee16950e772076d321792d9fbf030f921345 (patch) | |
tree | c0b17ff0622f801f05bb11228426bdc90e8ffdc2 /drivers/tty/tty_buffer.c | |
parent | 809850b7a5fcc0a96d023e1171a7944c60fd5a71 (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.c | 49 |
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); |