Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
printk: extend console_lock for proper kthread support
Currently threaded console printers synchronize against each other using console_lock(). However, different console drivers are unrelated and do not require any synchronization between each other. Removing the synchronization between the threaded console printers will allow each console to print at its own speed. But the threaded consoles printers do still need to synchronize against console_lock() callers. Introduce a per-console mutex and a new console flag CON_THD_BLOCKED to provide this synchronization. console_lock() is modified so that it must acquire the mutex of each console in order to set the CON_THD_BLOCKED flag. Console printing threads will acquire their mutex while printing a record. If CON_THD_BLOCKED was set, the thread will go back to sleep instead of printing. The reason for the CON_THD_BLOCKED flag is so that console_lock() callers do not need to acquire multiple console mutexes simultaneously, which would introduce unnecessary complexity due to nested mutex locking. The per-console mutex is also used to synchronize setting and checking the CON_ENABLED flag. A new console_lock() variant is introduced, console_lock_single_hold(), that allows acquiring @console_sem but only locking (and holding) the mutex of a single console. This allows safely enabling and disabling consoles without disturbing the other kthread printers. The mutex and @console_sem are released with console_unlock_single_release(). Console unregistering now uses console_lock_single_hold() to stop the kthread. Thus con->thread is now synchronized by the per-console mutex. This allows consoles to be unregistered without disturbing the other kthread printers. Threaded console printers also need to synchronize against console_trylock() callers. Since console_trylock() may be called from any context, the per-console mutex cannot be used for this synchronization. (mutex_trylock() cannot be called from atomic contexts.) Introduce a global atomic counter to identify if any threaded printers are active. The threaded printers will also check the atomic counter to identify if the console has been locked by another task via console_trylock(). Note that @console_sem is still used to provide synchronization between console_lock() and console_trylock() callers. A locking overview for console_lock(), console_trylock(), and the threaded printers is as follows (pseudo code): console_lock() { down(&console_sem); for_each_console(con) { mutex_lock(&con->lock); con->flags |= CON_THD_BLOCKED; mutex_unlock(&con->lock); } /* console_lock acquired */ } console_trylock() { if (down_trylock(&console_sem) == 0) { if (atomic_cmpxchg(&console_kthreads_active, 0, -1) == 0) { /* console_lock acquired */ } } } threaded_printer() { mutex_lock(&con->lock); if (!(con->flags & CON_THD_BLOCKED)) { /* console_lock() callers blocked */ if (atomic_inc_unless_negative(&console_kthreads_active)) { /* console_trylock() callers blocked */ con->write(); atomic_dec(&console_lock_count); } } mutex_unlock(&con->lock); } The console owner and waiter logic now only applies between contexts that have taken the console_lock via console_trylock(). Threaded printers never take the console_lock, so they do not have a console_lock to handover. Tasks that have used console_lock() will block the threaded printers using a mutex and if the console_lock is handed over to an atomic context, it would be unable to unblock the threaded printers. However, the console_trylock() case is really the only scenario that is interesting for handovers anyway. @panic_console_dropped must change to atomic_t since it is no longer protected exclusively by the console_lock. Since threaded printers remain asleep if they see that the console is locked, they now must be explicitly woken in __console_unlock(). This means wake_up_klogd() calls following a console_unlock() are no longer necessary and are removed. Also note that threaded printers no longer need to check @console_suspended. The check for the CON_THD_BLOCKED flag implicitly covers the suspended console case. Signed-off-by: John Ogness <john.ogness@linutronix.de>
- Loading branch information