Messages in this thread Patch in this message | | | Date | Wed, 15 Mar 2000 23:43:43 +0100 | From | Pavel Machek <> | Subject | Low latency for fbcon (fwd) |
| |
Hi!
USB audio was unusable on my computers: both use fbcon and usb is _very_ sensitive to interrupt latencies. Fbcon happily disables interrupts for half a second.
I hopefully fixed that. It brings slight problems with printk's (they tend to do even more garbage on screen than they used to if there's concurent output), but at least I can listen to mp3's on my usb audio.
Try it. Take a look at down_trylock -- I hope I did not put the logic backward. Pavel
PS: Would it be possible to declare that fbcon is re-entrant, but may mess the screen up in such case?
--- clean//drivers/char/console.c Wed Mar 15 14:06:50 2000 +++ linux/drivers/char/console.c Wed Mar 15 23:34:49 2000 @@ -1786,18 +1786,17 @@ } } -/* This is a temporary buffer used to prepare a tty console write - * so that we can easily avoid touching user space while holding the - * console spinlock. It is allocated in con_init and is shared by - * this code and the vc_screen read/write tty calls. +/* This is a temporary buffer used to prepare a tty console write so + * that we can easily avoid touching user space while holding the + * console spinlock. It is shared by this code and the vc_screen + * read/write tty calls. * - * We have to allocate this statically in the kernel data section - * since console_init (and thus con_init) are called before any - * kernel memory allocation is available. + * Bigger buffer means better console writing performance, but worse + * latency of console switches. */ -char con_buf[PAGE_SIZE]; -#define CON_BUF_SIZE PAGE_SIZE -DECLARE_MUTEX(con_buf_sem); +#define CON_BUF_SIZE (PAGE_SIZE/10) +char con_buf[CON_BUF_SIZE]; +DECLARE_MUTEX(console_sem); static int do_con_write(struct tty_struct * tty, int from_user, const unsigned char *buf, int count) @@ -1834,7 +1833,7 @@ orig_count = count; if (from_user) { - down(&con_buf_sem); + down(&console_sem); again: if (count > CON_BUF_SIZE) @@ -1845,17 +1844,17 @@ } buf = con_buf; - } + } else + if (down_trylock(&console_sem)) /* Lock failed */ + return -EINVAL; /* At this point 'buf' is guarenteed to be a kernel buffer * and therefore no access to userspace (and therefore sleeping) - * will be needed. The con_buf_sem serializes all tty based + * will be needed. The console_sem serializes all tty based * console rendering and vcs write/read operations. We hold * the console spinlock during the entire write. */ - spin_lock_irq(&console_lock); - himask = hi_font_mask; charmask = himask ? 0x1ff : 0xff; @@ -1972,7 +1971,6 @@ do_con_trol(tty, currcons, c); } FLUSH - spin_unlock_irq(&console_lock); out: if (from_user) { @@ -1988,32 +1986,21 @@ goto again; } - up(&con_buf_sem); } + up_console_sem(); return n; #undef FLUSH } -/* - * This is the console switching tasklet. - * - * Doing console switching in a tasklet allows - * us to do the switches asynchronously (needed when we want - * to switch due to a keyboard interrupt). Synchronization - * with other console code and prevention of re-entrancy is - * ensured with console_lock. +static int softint_missed = 0; + +/* + * Must be called with console_sem hold. */ -static void console_softint(unsigned long ignored) +static void do_console_softint(void) { - /* Runs the task queue outside of the console lock. These - * callbacks can come back into the console code and thus - * will perform their own locking. - */ - run_task_queue(&con_task_queue); - - spin_lock_irq(&console_lock); - + softint_missed = 0; if (want_console >= 0) { if (want_console != fg_console && vc_cons_allocated(want_console)) { hide_cursor(fg_console); @@ -2035,8 +2022,38 @@ sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta); scrollback_delta = 0; } +} - spin_unlock_irq(&console_lock); +void up_console_sem(void) +{ + if (softint_missed) + do_console_softint(); + up(&console_sem); +} + +/* + * This is the console switching tasklet. + * + * Doing console switching in a tasklet allows + * us to do the switches asynchronously (needed when we want + * to switch due to a keyboard interrupt). Synchronization + * with other console code and prevention of re-entrancy is + * ensured with console_lock. + */ +static void console_softint(unsigned long ignored) +{ + /* Runs the task queue outside of the console lock. These + * callbacks can come back into the console code and thus + * will perform their own locking. + */ + run_task_queue(&con_task_queue); + + softint_missed = 1; + if (down_trylock(&console_sem)) { + printk( "console_softint request dropped\n" ); + return; + } + up_console_sem(); } #ifdef CONFIG_VT_CONSOLE @@ -2827,9 +2844,9 @@ op->data = temp; } - spin_lock_irq(&console_lock); + down(&console_sem); rc = sw->con_font_op(vc_cons[currcons].d, op); - spin_unlock_irq(&console_lock); + up_console_sem(); op->data = old_op.data; if (!rc && !set) { --- clean//drivers/char/vt.c Fri Mar 3 22:52:01 2000 +++ linux/drivers/char/vt.c Wed Mar 15 23:18:04 2000 @@ -807,9 +807,9 @@ * make sure we are atomic with respect to * other console switches.. */ - spin_lock_irq(&console_lock); + down(&console_sem); complete_change_console(newvt); - spin_unlock_irq(&console_lock); + up_console_sem(); } } --- clean//drivers/char/vc_screen.c Fri Mar 3 22:52:01 2000 +++ linux/drivers/char/vc_screen.c Wed Mar 15 23:18:22 2000 @@ -91,7 +91,6 @@ */ extern char con_buf[PAGE_SIZE]; #define CON_BUF_SIZE PAGE_SIZE -extern struct semaphore con_buf_sem; static ssize_t vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos) @@ -104,12 +103,11 @@ unsigned short *org = NULL; ssize_t ret; - down(&con_buf_sem); + down(&console_sem); /* Select the proper current console and verify * sanity of the situation under the console lock. */ - spin_lock_irq(&console_lock); attr = (currcons & 128); currcons = (currcons & 127); @@ -236,9 +234,7 @@ * all the data to userspace from our temporary buffer. */ - spin_unlock_irq(&console_lock); ret = copy_to_user(buf, con_buf_start, orig_count); - spin_lock_irq(&console_lock); if (ret) { read += (orig_count - ret); @@ -254,8 +250,7 @@ if (read) ret = read; unlock_out: - spin_unlock_irq(&console_lock); - up(&con_buf_sem); + up_console_sem(); return ret; } @@ -271,12 +266,11 @@ u16 *org0 = NULL, *org = NULL; size_t ret; - down(&con_buf_sem); + down(&console_sem); /* Select the proper current console and verify * sanity of the situation under the console lock. */ - spin_lock_irq(&console_lock); attr = (currcons & 128); currcons = (currcons & 127); @@ -310,9 +304,7 @@ /* Temporarily drop the console lock so that we can read * in the write data from userspace safely. */ - spin_unlock_irq(&console_lock); ret = copy_from_user(con_buf, buf, this_round); - spin_lock_irq(&console_lock); if (ret) { this_round -= ret; @@ -436,9 +428,8 @@ ret = written; unlock_out: - spin_unlock_irq(&console_lock); - up(&con_buf_sem); + up_console_sem(); return ret; } --- clean//include/linux/console.h Sat Feb 19 19:52:22 2000 +++ linux/include/linux/console.h Wed Mar 15 22:04:17 2000 @@ -91,7 +91,8 @@ #define CON_CONSDEV (2) /* Last on the command line */ #define CON_ENABLED (4) -extern spinlock_t console_lock; +//extern spinlock_t console_lock; +extern struct semaphore console_sem; struct console { -- I'm pavel@ucw.cz. "In my country we have almost anarchy and I don't care." Panos Katsaloulis describing me w.r.t. patents me at discuss@linmodems.org
----- End forwarded message ----- -- I'm pavel@ucw.cz. "In my country we have almost anarchy and I don't care." Panos Katsaloulis describing me w.r.t. patents me at discuss@linmodems.org
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |