klogd
Rev.3を表示中。最新版はこちら。
ログファイルとロギングの仕組み/システムログ2の焼き直しみたいなものです。klogdとカーネルのログデーモンと言う事で、カーネルスレッドと思ってしまいそうですが、ログファイルとロギングの仕組みの図解のように、ユーザランドから起動されるもので、もちろんユーザプロセスです。(なお、図解ではdmesgも/proc/kmsgから取得するようになっていますが、私の調べたレベルではdmesgは直接リングバッファから取得しているようです。)
/proc/kmsgから読み出すと、do_syslog()をtype=2でコールしていました。その処理はlog_start - log_end=0なら、log_waitキューでウエイトさせていました。
DECLARE_WAIT_QUEUE_HEAD(log_wait); int do_syslog(int type, char __user *buf, int len) { : switch (type) { : case 2: /* Read from log */ : error = wait_event_interruptible(log_wait, (log_start - log_end)); : default: error = -EINVAL; break; } out: return error; }
#define wait_event_interruptible(wq, condition) \ ({ \ int __ret = 0; \ if (!(condition)) \ __wait_event_interruptible(wq, condition, __ret); \ __ret; \ })そしてそのウエイトを起床させるのが、printk()の下位関数であるvprintk()で、コンソール出力時の呼び出されるrelease_console_sem()です。release_console_sem()ではwake_klogd |= log_start - log_endととし、それが0でないならwake_up_klogd()としてklogdを起床させるものです。
(forループの中で論理和としている意味はよくわかりません。)
asmlinkage int vprintk(const char *fmt, va_list args) { : if (acquire_console_semaphore_for_printk(this_cpu)) release_console_sem(); : } void release_console_sem(void) { : unsigned wake_klogd = 0; : for ( ; ; ) { spin_lock_irqsave(&logbuf_lock, flags); wake_klogd |= log_start - log_end; : } : if (wake_klogd) wake_up_klogd(); }wake_up_klogd()と、いかにもklogdスレッドを起床させるかのようですが、要はlog_waitキューでウエイトしているプロセスを起動させているに過ぎません。いうなればcat /proc/kmsgでウエイトしているなら、カーネルからみたらこれがklogプロセスというわけです。
void wake_up_klogd(void) { if (!oops_in_progress && waitqueue_active(&log_wait)) wake_up_interruptible(&log_wait); }本実装はcat /proc/kmsgで表示するためのもでなく、カーネルからprinkされることでユーザプロセスを起動させる仕組みだったのかと妙に納得したところです。なお、klogdが起動していて、cat /proc/kmsgを実行させると、ウエイト順にその時のシスログを処理することになるかと思います。