lkml.org 
[lkml]   [2000]   [Mar]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectLow 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/

\
 
 \ /
  Last update: 2005-03-22 13:57    [W:0.029 / U:0.336 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site