printk is a function that prints messages and is used in the C Programming Language exclusively for the Linux Kernel. It accepts a string parameter called the format string, which specifies a method for rendering an arbitrary number of varied data type parameter(s) into a string. The string is then printed to the kernel log.
It provides a printf-like abstraction and its parsing of the format string and arguments behave exactly the same way. It acts as a debugging tool for kernel programmers who need this function for logging messages from the kernel.
printk function prototype is:
int printk(const char *fmt, ...);
In kernel mode, you can't use the standard C library, so printf is not available, hence printk.
Difference with printf
printk has an optional first parameter: Loglevel.
Loglevel specifies the type of message being sent to the kernel message log. The syntax with loglevel is:
int printk(KERN_DEBUG "Debug message shown!");
Different Loglevels are shown here:
|KERN_EMERG||Emergency condition, system is probably dead|
|KERN_ALERT||Some problem has occurred, immediate attention is needed|
|KERN_CRIT||A critical condition|
|KERN_ERR||An error has occurred|
|KERN_NOTICE||Normal message to take note of|
|KERN_DEBUG||Debug information related to the program|
When a log level is not specified, the default log level is KERN_WARNING.
Loglevels are defined in <linux/kern_levels.h>
The function tries to grab the console semaphore (console_sem). If it succeeds, the output is logged and the console drivers are called. If is not possible to grab the semaphore the output is placed into the log buffer. The current holder of the console semaphore (console_sem) will notice the new output in release_console_sem and will send it to the consoles before releasing the semaphore.
One effect of this deferred printing is that code which calls printk and then changes console_loglevel may break. This is because console_loglevel is inspected when the actual printing occurs.
printk() can be called from anywhere in the Kernel at any time. It can be called from interrupt or process context. It can be called while a lock is held. It can be called simultaneously on multiple processors, yet it does not require the caller to hold a lock.