Interrupt Context vs Process Context
When writing device drivers, you will often hear about two important execution environments in the kernel: interrupt context and process context. These contexts define what code can and cannot do at any given moment, especially in terms of timing, safety, and allowed kernel operations. Interrupt context refers to code running as a result of hardware interrupt handling, usually outside the normal flow of process scheduling. Process context, on the other hand, is code running on behalf of a user process or kernel thread, where normal scheduling and sleeping are allowed.
interrupt_context_example.c
12345678910111213141516171819202122232425262728293031#include <linux/module.h> #include <linux/interrupt.h> #include <linux/kernel.h> static irqreturn_t my_interrupt_handler(int irq, void *dev_id) { printk(KERN_INFO "Running in interrupt context!\n"); // Do not sleep or schedule here! return IRQ_HANDLED; } static int __init my_module_init(void) { int irq = 1; // Example IRQ number int ret = request_irq(irq, my_interrupt_handler, IRQF_SHARED, "my_irq_handler", (void *)(my_interrupt_handler)); if (ret) printk(KERN_ERR "Failed to request IRQ\n"); return ret; } static void __exit my_module_exit(void) { int irq = 1; free_irq(irq, (void *)(my_interrupt_handler)); printk(KERN_INFO "Module unloaded\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL");
In the code above, the my_interrupt_handler function is executed in interrupt context. This means it is called directly by the kernel's interrupt handling mechanism and is not associated with any user process. In this context, you must not perform actions that might sleep, such as acquiring mutexes, calling schedule(), or accessing user space memory. The handler must run quickly and return as soon as possible to avoid blocking other interrupts or system activities. The main restrictions in interrupt context are:
- Cannot perform operations that might sleep;
- Cannot access user space memory directly;
- Must keep execution time short;
- Can safely use spinlocks (but not mutexes or semaphores);
- Cannot perform blocking I/O operations.
process_context_example.c
12345678910111213141516171819202122232425262728293031323334353637383940414243#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { char data[] = "Data from process context\n"; int ret; // Simulate sleeping operation (e.g., waiting for data) set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); // Sleep for 1 second ret = copy_to_user(buf, data, sizeof(data)); if (ret) return -EFAULT; return sizeof(data); } static struct file_operations fops = { .read = my_read, }; static int major; static int __init my_module_init(void) { major = register_chrdev(0, "my_proc_context_dev", &fops); if (major < 0) printk(KERN_ERR "Failed to register char device\n"); return 0; } static void __exit my_module_exit(void) { unregister_chrdev(major, "my_proc_context_dev"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL");
¡Gracias por tus comentarios!
Pregunte a AI
Pregunte a AI
Pregunte lo que quiera o pruebe una de las preguntas sugeridas para comenzar nuestra charla
Genial!
Completion tasa mejorada a 3.85
Interrupt Context vs Process Context
Desliza para mostrar el menú
When writing device drivers, you will often hear about two important execution environments in the kernel: interrupt context and process context. These contexts define what code can and cannot do at any given moment, especially in terms of timing, safety, and allowed kernel operations. Interrupt context refers to code running as a result of hardware interrupt handling, usually outside the normal flow of process scheduling. Process context, on the other hand, is code running on behalf of a user process or kernel thread, where normal scheduling and sleeping are allowed.
interrupt_context_example.c
12345678910111213141516171819202122232425262728293031#include <linux/module.h> #include <linux/interrupt.h> #include <linux/kernel.h> static irqreturn_t my_interrupt_handler(int irq, void *dev_id) { printk(KERN_INFO "Running in interrupt context!\n"); // Do not sleep or schedule here! return IRQ_HANDLED; } static int __init my_module_init(void) { int irq = 1; // Example IRQ number int ret = request_irq(irq, my_interrupt_handler, IRQF_SHARED, "my_irq_handler", (void *)(my_interrupt_handler)); if (ret) printk(KERN_ERR "Failed to request IRQ\n"); return ret; } static void __exit my_module_exit(void) { int irq = 1; free_irq(irq, (void *)(my_interrupt_handler)); printk(KERN_INFO "Module unloaded\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL");
In the code above, the my_interrupt_handler function is executed in interrupt context. This means it is called directly by the kernel's interrupt handling mechanism and is not associated with any user process. In this context, you must not perform actions that might sleep, such as acquiring mutexes, calling schedule(), or accessing user space memory. The handler must run quickly and return as soon as possible to avoid blocking other interrupts or system activities. The main restrictions in interrupt context are:
- Cannot perform operations that might sleep;
- Cannot access user space memory directly;
- Must keep execution time short;
- Can safely use spinlocks (but not mutexes or semaphores);
- Cannot perform blocking I/O operations.
process_context_example.c
12345678910111213141516171819202122232425262728293031323334353637383940414243#include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> static ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { char data[] = "Data from process context\n"; int ret; // Simulate sleeping operation (e.g., waiting for data) set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(HZ); // Sleep for 1 second ret = copy_to_user(buf, data, sizeof(data)); if (ret) return -EFAULT; return sizeof(data); } static struct file_operations fops = { .read = my_read, }; static int major; static int __init my_module_init(void) { major = register_chrdev(0, "my_proc_context_dev", &fops); if (major < 0) printk(KERN_ERR "Failed to register char device\n"); return 0; } static void __exit my_module_exit(void) { unregister_chrdev(major, "my_proc_context_dev"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL");
¡Gracias por tus comentarios!