Low latency for fbcon (fwd)

From: Pavel Machek (pavel@suse.cz)
Date: Wed Mar 15 2000 - 17:43:43 EST


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/



This archive was generated by hypermail 2b29 : Thu Mar 23 2000 - 21:00:22 EST