一、中断相关结构体

1.irq_desc中断描述符

  1. struct irq_desc {
  2. #ifdef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
  3. struct irq_data irq_data;
  4. #else
  5. union {
  6. struct irq_data irq_data;   //中断数据
  7. struct {
  8. unsigned int    irq;    //中断号
  9. unsigned int    node;   //节点号
  10. struct irq_chip *chip;  //irq_chip
  11. void    *handler_data;
  12. void    *chip_data;
  13. struct msi_desc *msi_desc;
  14. #ifdef CONFIG_SMP
  15. cpumask_var_t   affinity;
  16. #endif
  17. };
  18. };
  19. #endif
  20. struct timer_rand_state *timer_rand_state;
  21. unsigned int    *kstat_irqs;
  22. irq_flow_handler_t  handle_irq; //中断处理句柄
  23. struct irqaction    *action;    /* 中断动作列表 */
  24. unsigned int    status;     /* 中断状态 */
  25. unsigned int    depth;      /* nested irq disables */
  26. unsigned int    wake_depth; /* nested wake enables */
  27. unsigned int    irq_count;  /* For detecting broken IRQs */
  28. unsigned long   last_unhandled; /* Aging timer for unhandled count */
  29. unsigned int    irqs_unhandled;
  30. raw_spinlock_t  lock;
  31. #ifdef CONFIG_SMP
  32. const struct cpumask    *affinity_hint;
  33. #ifdef CONFIG_GENERIC_PENDING_IRQ
  34. cpumask_var_t   pending_mask;
  35. #endif
  36. #endif
  37. atomic_t    threads_active;
  38. wait_queue_head_t   wait_for_threads;
  39. #ifdef CONFIG_PROC_FS
  40. struct proc_dir_entry   *dir;   //proc接口目录
  41. #endif
  42. const char  *name;  //名字
  43. } ____cacheline_internodealigned_in_smp;

2.irq_chip 芯片相关的处理函数集合

  1. struct irq_chip {   //芯片相关的处理函数集合
  2. const char  *name;  //"proc/interrupts/name"
  3. #ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
  4. unsigned int    (*startup)(unsigned int irq);
  5. void    (*shutdown)(unsigned int irq);
  6. void    (*enable)(unsigned int irq);
  7. void    (*disable)(unsigned int irq);
  8. void    (*ack)(unsigned int irq);
  9. void    (*mask)(unsigned int irq);
  10. void    (*mask_ack)(unsigned int irq);
  11. void    (*unmask)(unsigned int irq);
  12. void    (*eoi)(unsigned int irq);
  13. void    (*end)(unsigned int irq);
  14. int     (*set_affinity)(unsigned int irq,const struct cpumask *dest);
  15. int     (*retrigger)(unsigned int irq);
  16. int     (*set_type)(unsigned int irq, unsigned int flow_type);
  17. int     (*set_wake)(unsigned int irq, unsigned int on);
  18. void    (*bus_lock)(unsigned int irq);
  19. void    (*bus_sync_unlock)(unsigned int irq);
  20. #endif
  21. unsigned int    (*irq_startup)(struct irq_data *data);  //中断开始
  22. void    (*irq_shutdown)(struct irq_data *data); //中断关闭
  23. void    (*irq_enable)(struct irq_data *data);   //中断使能
  24. void    (*irq_disable)(struct irq_data *data);  //中断禁用
  25. void    (*irq_ack)(struct irq_data *data);
  26. void    (*irq_mask)(struct irq_data *data);
  27. void    (*irq_mask_ack)(struct irq_data *data);
  28. void    (*irq_unmask)(struct irq_data *data);
  29. void    (*irq_eoi)(struct irq_data *data);
  30. int     (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);
  31. int     (*irq_retrigger)(struct irq_data *data);
  32. int     (*irq_set_type)(struct irq_data *data, unsigned int flow_type);
  33. int     (*irq_set_wake)(struct irq_data *data, unsigned int on);
  34. void    (*irq_bus_lock)(struct irq_data *data);
  35. void    (*irq_bus_sync_unlock)(struct irq_data *data);
  36. #ifdef CONFIG_IRQ_RELEASE_METHOD
  37. void    (*release)(unsigned int irq, void *dev_id);
  38. #endif
  39. };

3.irqaction中断行动结构体

  1. struct irqaction {
  2. irq_handler_t handler;  //中断处理函数
  3. unsigned long flags;    //中断标志
  4. const char *name;       //中断名
  5. void *dev_id;       //设备id号,共享中断用
  6. struct irqaction *next; //共享中断类型指向下一个irqaction
  7. int irq;            //中断号
  8. struct proc_dir_entry *dir; //proc接口目录
  9. irq_handler_t thread_fn;    //中断处理函数(线程)
  10. struct task_struct *thread; //线程任务
  11. unsigned long thread_flags; //线程标志
  12. };

在整个中断系统中将勾勒出以下的关系框图

二、中断初始化工作

从start_kernel看起,大致按以下的分支顺序初始化

  1. start_kernel
  2. setup_arch          //设置全局init_arch_irq函数
  3. early_trap_init //搬移向量表
  4. early_irq_init();   //初始化全局irq_desc数组
  5. init_IRQ();         //调用init_arch_irq函数
  6. [   //板级中断初始化常用到的API
  7. set_irq_chip
  8. set_irq_handler
  9. set_irq_chained_handler
  10. set_irq_flags
  11. set_irq_type
  12. set_irq_chip_data
  13. set_irq_data
  14. ]

1.在setup_arch中主要是设置全局init_arch_irq函数

  1. void __init setup_arch(char **cmdline_p)
  2. {
  3. struct tag *tags = (struct tag *)&init_tags;
  4. struct machine_desc *mdesc;
  5. char *from = default_command_line;
  6. init_tags.mem.start = PHYS_OFFSET;
  7. unwind_init();
  8. setup_processor();
  9. mdesc = setup_machine(machine_arch_type);
  10. machine_name = mdesc->name;
  11. if (mdesc->soft_reboot)
  12. reboot_setup("s");
  13. if (__atags_pointer)
  14. tags = phys_to_virt(__atags_pointer);
  15. else if (mdesc->boot_params) {
  16. #ifdef CONFIG_MMU
  17. if (mdesc->boot_params < PHYS_OFFSET ||mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {
  18. printk(KERN_WARNING"Default boot params at physical 0x%08lx out of reach\n",mdesc->boot_params);
  19. }
  20. else
  21. #endif
  22. {
  23. tags = phys_to_virt(mdesc->boot_params);
  24. }
  25. }
  26. #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
  27. if (tags->hdr.tag != ATAG_CORE)
  28. convert_to_tag_list(tags);
  29. #endif
  30. if (tags->hdr.tag != ATAG_CORE)
  31. tags = (struct tag *)&init_tags;
  32. if (mdesc->fixup)
  33. mdesc->fixup(mdesc, tags, &from, &meminfo);
  34. if (tags->hdr.tag == ATAG_CORE) {
  35. if (meminfo.nr_banks != 0)
  36. squash_mem_tags(tags);
  37. save_atags(tags);
  38. parse_tags(tags);
  39. }
  40. init_mm.start_code = (unsigned long) _text;
  41. init_mm.end_code   = (unsigned long) _etext;
  42. init_mm.end_data   = (unsigned long) _edata;
  43. init_mm.brk    = (unsigned long) _end;
  44. strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
  45. strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
  46. *cmdline_p = cmd_line;
  47. parse_early_param();
  48. arm_memblock_init(&meminfo, mdesc);
  49. paging_init(mdesc);
  50. request_standard_resources(&meminfo, mdesc);
  51. #ifdef CONFIG_SMP
  52. if (is_smp())
  53. smp_init_cpus();
  54. #endif
  55. reserve_crashkernel();
  56. cpu_init();
  57. tcm_init();
  58. arch_nr_irqs = mdesc->nr_irqs;
  59. init_arch_irq = mdesc->init_irq; //设置全局init_arch_irq函数
  60. //void (*init_arch_irq)(void) __initdata = NULL;
  61. system_timer = mdesc->timer;
  62. init_machine = mdesc->init_machine;
  63. #ifdef CONFIG_VT
  64. #if defined(CONFIG_VGA_CONSOLE)
  65. conswitchp = &vga_con;
  66. #elif defined(CONFIG_DUMMY_CONSOLE)
  67. conswitchp = &dummy_con;
  68. #endif
  69. #endif
  70. early_trap_init();//调用early_trap_init函数
  71. }

1.1.early_trap_init主要挪移了中断向量表到特定位置

  1. void __init early_trap_init(void)
  2. {
  3. unsigned long vectors = CONFIG_VECTORS_BASE;    //0xffff0000
  4. extern char __stubs_start[], __stubs_end[];
  5. extern char __vectors_start[], __vectors_end[];
  6. extern char __kuser_helper_start[], __kuser_helper_end[];
  7. int kuser_sz = __kuser_helper_end - __kuser_helper_start;
  8. memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);  //移动中断向量表
  9. memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);    //移动__stubs_start段
  10. memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
  11. kuser_get_tls_init(vectors);
  12. memcpy((void *)KERN_SIGRETURN_CODE, sigreturn_codes,sizeof(sigreturn_codes));
  13. memcpy((void *)KERN_RESTART_CODE, syscall_restart_code,sizeof(syscall_restart_code));
  14. flush_icache_range(vectors, vectors + PAGE_SIZE);
  15. modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
  16. }

2.early_irq_init 初始化全局irq_desc数组
在(kernel/irqs/irqdesc.c)中定义了全局irq_desc数组

  1. struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
  2. [0 ... NR_IRQS-1] = {
  3. .status     = IRQ_DEFAULT_INIT_FLAGS,
  4. .handle_irq = handle_bad_irq,
  5. .depth      = 1,
  6. .lock       = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
  7. }
  8. };

获取irq_desc数组项的宏

  1. #define irq_to_desc(irq)    (&irq_desc[irq])

early_irq_init函数

  1. int __init early_irq_init(void) //初始化全局irq_desc数组
  2. {
  3. int count, i, node = first_online_node;
  4. struct irq_desc *desc;
  5. init_irq_default_affinity();
  6. printk(KERN_INFO "NR_IRQS:%d\n", NR_IRQS);
  7. desc = irq_desc;    //获取全局irq_desc数组
  8. count = ARRAY_SIZE(irq_desc);   //获取全局irq_desc数组项个数
  9. for (i = 0; i < count; i++) {    //初始化全局irq_desc数组
  10. desc[i].irq_data.irq = i;
  11. desc[i].irq_data.chip = &no_irq_chip;
  12. desc[i].kstat_irqs = kstat_irqs_all[i];
  13. alloc_masks(desc + i, GFP_KERNEL, node);
  14. desc_smp_init(desc + i, node);
  15. lockdep_set_class(&desc[i].lock, &irq_desc_lock_class);
  16. }
  17. return arch_early_irq_init();
  18. }

3.init_IRQ函数调用全局init_arch_irq函数,进入板级初始化

  1. void __init init_IRQ(void)
  2. {
  3. init_arch_irq();    //调用板级驱动的中断初始化函数
  4. }

4.板级中断初始化常用到的API

1.set_irq_chip 通过irq中断号获取对应全局irq_desc数组项,并设置其irq_data.chip指向传递进去的irq_chip指针

  1. int set_irq_chip(unsigned int irq, struct irq_chip *chip)
  2. {
  3. struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项
  4. unsigned long flags;
  5. if (!desc) {
  6. WARN(1, KERN_ERR "Trying to install chip for IRQ%d\n", irq);
  7. return -EINVAL;
  8. }
  9. if (!chip)                      //若irq_chip不存在
  10. chip = &no_irq_chip;        //设置为no_irq_chip
  11. raw_spin_lock_irqsave(&desc->lock, flags);
  12. irq_chip_set_defaults(chip);    //初始化irq_chip
  13. desc->irq_data.chip = chip;      //设置irq_desc->irq_data.chip
  14. raw_spin_unlock_irqrestore(&desc->lock, flags);
  15. return 0;
  16. }
  17. EXPORT_SYMBOL(set_irq_chip);

1.1 irq_chip_set_defaults 根据irq_chip的实际情况初始化默认方法

  1. void irq_chip_set_defaults(struct irq_chip *chip)   //根据irq_chip的实际情况初始化默认方法
  2. {
  3. #ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
  4. if (chip->enable)
  5. chip->irq_enable = compat_irq_enable;
  6. if (chip->disable)
  7. chip->irq_disable = compat_irq_disable;
  8. if (chip->shutdown)
  9. chip->irq_shutdown = compat_irq_shutdown;
  10. if (chip->startup)
  11. chip->irq_startup = compat_irq_startup;
  12. #endif
  13. if (!chip->irq_enable)       //使能中断
  14. chip->irq_enable = default_enable;
  15. if (!chip->irq_disable)      //禁用中断
  16. chip->irq_disable = default_disable;
  17. if (!chip->irq_startup)      //中断开始
  18. chip->irq_startup = default_startup;
  19. if (!chip->irq_shutdown) //关闭中断
  20. chip->irq_shutdown = chip->irq_disable != default_disable ? chip->irq_disable : default_shutdown;
  21. #ifndef CONFIG_GENERIC_HARDIRQS_NO_DEPRECATED
  22. if (!chip->end)
  23. chip->end = dummy_irq_chip.end;
  24. if (chip->bus_lock)
  25. chip->irq_bus_lock = compat_bus_lock;
  26. if (chip->bus_sync_unlock)
  27. chip->irq_bus_sync_unlock = compat_bus_sync_unlock;
  28. if (chip->mask)
  29. chip->irq_mask = compat_irq_mask;
  30. if (chip->unmask)
  31. chip->irq_unmask = compat_irq_unmask;
  32. if (chip->ack)
  33. chip->irq_ack = compat_irq_ack;
  34. if (chip->mask_ack)
  35. chip->irq_mask_ack = compat_irq_mask_ack;
  36. if (chip->eoi)
  37. chip->irq_eoi = compat_irq_eoi;
  38. if (chip->set_affinity)
  39. chip->irq_set_affinity = compat_irq_set_affinity;
  40. if (chip->set_type)
  41. chip->irq_set_type = compat_irq_set_type;
  42. if (chip->set_wake)
  43. chip->irq_set_wake = compat_irq_set_wake;
  44. if (chip->retrigger)
  45. chip->irq_retrigger = compat_irq_retrigger;
  46. #endif
  47. }

2.set_irq_handler和set_irq_chained_handler

这两个函数的功能是:根据irq中断号,获取对应全局irq_desc数组项,并将数组项描述符的handle_irq中断处理函数指针指向handle
如果是chain类型则添加数组项的status状态IRQ_NOREQUEST和IRQ_NOPROBE属性

  1. static inline void set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
  2. {
  3. __set_irq_handler(irq, handle, 0, NULL);    //调用__set_irq_handler
  4. }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  1. static inline void set_irq_chained_handler(unsigned int irq,irq_flow_handler_t handle)
  2. {
  3. __set_irq_handler(irq, handle, 1, NULL);    //调用__set_irq_handler
  4. }

2.1 __set_irq_handler函数

  1. void __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,const char *name)
  2. {
  3. struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项
  4. unsigned long flags;
  5. if (!desc) {
  6. printk(KERN_ERR"Trying to install type control for IRQ%d\n", irq);
  7. return;
  8. }
  9. if (!handle)    //若没指定handle
  10. handle = handle_bad_irq;    //则设置为handle_bad_irq
  11. else if (desc->irq_data.chip == &no_irq_chip) {
  12. printk(KERN_WARNING "Trying to install %sinterrupt handler for IRQ%d\n", is_chained ? "chained " : "", irq);
  13. desc->irq_data.chip = &dummy_irq_chip;   //设置desc->irq_data.chip为dummy_irq_chip(空操作的irq_chip)
  14. }
  15. chip_bus_lock(desc);
  16. raw_spin_lock_irqsave(&desc->lock, flags);
  17. if (handle == handle_bad_irq) {
  18. if (desc->irq_data.chip != &no_irq_chip)
  19. mask_ack_irq(desc);
  20. desc->status |= IRQ_DISABLED;
  21. desc->depth = 1;
  22. }
  23. desc->handle_irq = handle;   //高级中断处理句柄
  24. desc->name = name;
  25. if (handle != handle_bad_irq && is_chained) {   //链接
  26. desc->status &= ~IRQ_DISABLED;
  27. desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE;
  28. desc->depth = 0;
  29. desc->irq_data.chip->irq_startup(&desc->irq_data);
  30. }
  31. raw_spin_unlock_irqrestore(&desc->lock, flags);
  32. chip_bus_sync_unlock(desc);
  33. }
  34. EXPORT_SYMBOL_GPL(__set_irq_handler);

3.set_irq_flags 根据irq号获取全局irq_desc数组项,并设置其status标志(中断标志)

  1. void set_irq_flags(unsigned int irq, unsigned int iflags)
  2. {
  3. struct irq_desc *desc;
  4. unsigned long flags;
  5. if (irq >= nr_irqs) {
  6. printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
  7. return;
  8. }
  9. desc = irq_to_desc(irq);    //获取全局irq_desc数组项
  10. raw_spin_lock_irqsave(&desc->lock, flags);
  11. desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
  12. if (iflags & IRQF_VALID)
  13. desc->status &= ~IRQ_NOREQUEST;
  14. if (iflags & IRQF_PROBE)
  15. desc->status &= ~IRQ_NOPROBE;
  16. if (!(iflags & IRQF_NOAUTOEN))
  17. desc->status &= ~IRQ_NOAUTOEN;
  18. raw_spin_unlock_irqrestore(&desc->lock, flags);
  19. }

4.set_irq_type根据irq号获取全局irq_desc数组项,并设置其status标志(中断触发类型)

  1. int set_irq_type(unsigned int irq, unsigned int type)
  2. {
  3. struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项
  4. unsigned long flags;
  5. int ret = -ENXIO;
  6. if (!desc) {
  7. printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq);
  8. return -ENODEV;
  9. }
  10. type &= IRQ_TYPE_SENSE_MASK;
  11. if (type == IRQ_TYPE_NONE)
  12. return 0;
  13. raw_spin_lock_irqsave(&desc->lock, flags);
  14. ret = __irq_set_trigger(desc, irq, type);   //调用__irq_set_trigger
  15. raw_spin_unlock_irqrestore(&desc->lock, flags);
  16. return ret;
  17. }
  18. EXPORT_SYMBOL(set_irq_type);

4.1 __irq_set_trigger函数

  1. int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,unsigned long flags)
  2. {
  3. int ret;
  4. struct irq_chip *chip = desc->irq_data.chip;
  5. if (!chip || !chip->irq_set_type) {
  6. pr_debug("No set_type function for IRQ %d (%s)\n", irq,chip ? (chip->name ? : "unknown") : "unknown");
  7. return 0;
  8. }
  9. ret = chip->irq_set_type(&desc->irq_data, flags);
  10. if (ret)
  11. pr_err("setting trigger mode %lu for irq %u failed (%pF)\n",flags, irq, chip->irq_set_type);
  12. else {
  13. if (flags & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
  14. flags |= IRQ_LEVEL;
  15. /* note that IRQF_TRIGGER_MASK == IRQ_TYPE_SENSE_MASK */
  16. desc->status &= ~(IRQ_LEVEL | IRQ_TYPE_SENSE_MASK);
  17. desc->status |= flags;
  18. if (chip != desc->irq_data.chip)
  19. irq_chip_set_defaults(desc->irq_data.chip);
  20. }
  21. return ret;
  22. }

5.set_irq_chip_data 根据irq号获取全局irq_desc数组项,并设置其irq_data的chip_data

  1. int set_irq_chip_data(unsigned int irq, void *data)
  2. {
  3. struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项
  4. unsigned long flags;
  5. if (!desc) {
  6. printk(KERN_ERR"Trying to install chip data for IRQ%d\n", irq);
  7. return -EINVAL;
  8. }
  9. if (!desc->irq_data.chip) {
  10. printk(KERN_ERR "BUG: bad set_irq_chip_data(IRQ#%d)\n", irq);
  11. return -EINVAL;
  12. }
  13. raw_spin_lock_irqsave(&desc->lock, flags);
  14. desc->irq_data.chip_data = data;
  15. raw_spin_unlock_irqrestore(&desc->lock, flags);
  16. return 0;
  17. }
  18. EXPORT_SYMBOL(set_irq_chip_data);

6.set_irq_data

  1. int set_irq_data(unsigned int irq, void *data)
  2. {
  3. struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项
  4. unsigned long flags;
  5. if (!desc) {
  6. printk(KERN_ERR"Trying to install controller data for IRQ%d\n", irq);
  7. return -EINVAL;
  8. }
  9. raw_spin_lock_irqsave(&desc->lock, flags);
  10. desc->irq_data.handler_data = data;
  11. raw_spin_unlock_irqrestore(&desc->lock, flags);
  12. return 0;
  13. }
  14. EXPORT_SYMBOL(set_irq_data);

三、中断的申请与释放request_irq

1.申请中断(主要是分配设置irqaction结构体)

  1. static inline int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
  2. {
  3. return request_threaded_irq(irq, handler, NULL, flags, name, dev);
  4. }

1.1 request_threaded_irq函数

  1. int request_threaded_irq(unsigned int irq, irq_handler_t handler,irq_handler_t thread_fn, unsigned long irqflags,const char *devname, void *dev_id)
  2. {
  3. struct irqaction *action;
  4. struct irq_desc *desc;
  5. int retval;
  6. if ((irqflags & IRQF_SHARED) && !dev_id)    //共享中断但没指定中断id
  7. return -EINVAL;
  8. desc = irq_to_desc(irq);    //获取全局irq_desc数组项
  9. if (!desc)
  10. return -EINVAL;
  11. if (desc->status & IRQ_NOREQUEST)    //中断不能被请求
  12. return -EINVAL;
  13. if (!handler) { //没指定handler
  14. if (!thread_fn) //但存在thread_fn
  15. return -EINVAL;
  16. handler = irq_default_primary_handler;  //则设置irq_default_primary_handler
  17. }
  18. action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); //分配irqaction内存
  19. if (!action)
  20. return -ENOMEM;
  21. action->handler = handler;   //设置处理句柄
  22. action->thread_fn = thread_fn;   //设置线程函数NULL
  23. action->flags = irqflags;    //设置中断标志
  24. action->name = devname;      //设置设备名
  25. action->dev_id = dev_id; //设置设备id
  26. chip_bus_lock(desc);
  27. retval = __setup_irq(irq, desc, action);    //-->__setup_irq
  28. chip_bus_sync_unlock(desc);
  29. if (retval)
  30. kfree(action);
  31. #ifdef CONFIG_DEBUG_SHIRQ
  32. if (!retval && (irqflags & IRQF_SHARED)) {
  33. unsigned long flags;
  34. disable_irq(irq);
  35. local_irq_save(flags);
  36. handler(irq, dev_id);
  37. local_irq_restore(flags);
  38. enable_irq(irq);
  39. }
  40. #endif
  41. return retval;
  42. }
  43. EXPORT_SYMBOL(request_threaded_irq);

1.2 __setup_irq函数

  1. static int __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
  2. {
  3. struct irqaction *old, **old_ptr;
  4. const char *old_name = NULL;
  5. unsigned long flags;
  6. int nested, shared = 0;
  7. int ret;
  8. if (!desc)
  9. return -EINVAL;
  10. if (desc->irq_data.chip == &no_irq_chip)
  11. return -ENOSYS;
  12. if (new->flags & IRQF_SAMPLE_RANDOM) {
  13. rand_initialize_irq(irq);
  14. }
  15. if ((new->flags & IRQF_ONESHOT) && (new->flags & IRQF_SHARED))
  16. return -EINVAL;
  17. nested = desc->status & IRQ_NESTED_THREAD;   //嵌套标志
  18. if (nested) {   //嵌套
  19. if (!new->thread_fn) //且存在线程处理句柄
  20. return -EINVAL;
  21. new->handler = irq_nested_primary_handler;       //嵌套处理的句柄
  22. }
  23. if (new->thread_fn && !nested) { //非嵌套且存在线程函数
  24. struct task_struct *t;
  25. t = kthread_create(irq_thread, new, "irq/%d-%s", irq,new->name); //创建线程
  26. if (IS_ERR(t))
  27. return PTR_ERR(t);
  28. get_task_struct(t);
  29. new->thread = t; //设置线程任务结构体
  30. }
  31. raw_spin_lock_irqsave(&desc->lock, flags);
  32. old_ptr = &desc->action;
  33. old = *old_ptr;
  34. if (old) {
  35. if (!((old->flags & new->flags) & IRQF_SHARED) || ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {
  36. old_name = old->name;
  37. goto mismatch;
  38. }
  39. #if defined(CONFIG_IRQ_PER_CPU)
  40. if ((old->flags & IRQF_PERCPU) != (new->flags & IRQF_PERCPU))
  41. goto mismatch;
  42. #endif
  43. do {
  44. old_ptr = &old->next;
  45. old = *old_ptr;
  46. } while (old);
  47. shared = 1; //共享中断标志
  48. }
  49. if (!shared) {  //非共享中断
  50. irq_chip_set_defaults(desc->irq_data.chip);      //设置默认的芯片处理函数
  51. init_waitqueue_head(&desc->wait_for_threads);
  52. if (new->flags & IRQF_TRIGGER_MASK) {    //设置触发方式
  53. ret = __irq_set_trigger(desc, irq,new->flags & IRQF_TRIGGER_MASK);
  54. if (ret)
  55. goto out_thread;
  56. }
  57. else
  58. compat_irq_chip_set_default_handler(desc);
  59. #if defined(CONFIG_IRQ_PER_CPU)
  60. if (new->flags & IRQF_PERCPU)
  61. desc->status |= IRQ_PER_CPU;
  62. #endif
  63. desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_ONESHOT |IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
  64. if (new->flags & IRQF_ONESHOT)
  65. desc->status |= IRQ_ONESHOT;
  66. if (!(desc->status & IRQ_NOAUTOEN)) {
  67. desc->depth = 0;
  68. desc->status &= ~IRQ_DISABLED;
  69. desc->irq_data.chip->irq_startup(&desc->irq_data);
  70. }
  71. else
  72. desc->depth = 1;
  73. if (new->flags & IRQF_NOBALANCING)
  74. desc->status |= IRQ_NO_BALANCING;
  75. setup_affinity(irq, desc);
  76. }
  77. else if ((new->flags & IRQF_TRIGGER_MASK)&& (new->flags & IRQF_TRIGGER_MASK)!= (desc->status & IRQ_TYPE_SENSE_MASK)) {
  78. pr_warning("IRQ %d uses trigger mode %d; requested %d\n",
  79. irq, (int)(desc->status & IRQ_TYPE_SENSE_MASK),(int)(new->flags & IRQF_TRIGGER_MASK));
  80. }
  81. new->irq = irq;  //设置中断号
  82. *old_ptr = new;
  83. desc->irq_count = 0;
  84. desc->irqs_unhandled = 0;
  85. if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {  //共享中断
  86. desc->status &= ~IRQ_SPURIOUS_DISABLED;
  87. __enable_irq(desc, irq, false);
  88. }
  89. raw_spin_unlock_irqrestore(&desc->lock, flags);
  90. if (new->thread)
  91. wake_up_process(new->thread);
  92. register_irq_proc(irq, desc);   //注册proc irq接口
  93. new->dir = NULL;
  94. register_handler_proc(irq, new);    //注册proc handler接口
  95. return 0;
  96. mismatch:
  97. #ifdef CONFIG_DEBUG_SHIRQ
  98. if (!(new->flags & IRQF_PROBE_SHARED)) {
  99. printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);
  100. if (old_name)
  101. printk(KERN_ERR "current handler: %s\n", old_name);
  102. dump_stack();
  103. }
  104. #endif
  105. ret = -EBUSY;
  106. out_thread:
  107. raw_spin_unlock_irqrestore(&desc->lock, flags);
  108. if (new->thread) {
  109. struct task_struct *t = new->thread;
  110. new->thread = NULL;
  111. if (likely(!test_bit(IRQTF_DIED, &new->thread_flags)))
  112. kthread_stop(t);
  113. put_task_struct(t);
  114. }
  115. return ret;
  116. }

代码可以去细究,主要功能是填充irqaction

在设备驱动程序中申请中断可以这么申请

(eg:request_irq(1, &XXX_interrupt,IRQF_TRIGGER_RISING,"nameXXX", (void*)0))

第一个参数是中断号,第二个参数是中断处理函数,第三个参数是中断标志(上升沿),第四个是名字,第五个是设备id(非共享中断设置成(void*)0)即可

共享中断情况下要将第三个参数添加IRQF_SHARED标志,同时要给他制定第五个参数设备id

触发方式宏

  1. #define IRQ_TYPE_NONE       0x00000000  /* Default, unspecified type */
  2. #define IRQ_TYPE_EDGE_RISING    0x00000001  //上升沿触发
  3. #define IRQ_TYPE_EDGE_FALLING   0x00000002  //下降沿触发
  4. #define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)   //双边沿触发
  5. #define IRQ_TYPE_LEVEL_HIGH 0x00000004  //高电平有效
  6. #define IRQ_TYPE_LEVEL_LOW  0x00000008  //低电平有效
  7. #define IRQ_TYPE_SENSE_MASK 0x0000000f  /* Mask of the above */
  8. #define IRQ_TYPE_PROBE      0x00000010  /* Probing in progress */

然后设计中断函数

static irqreturn_t XXX_interrupt(int irq, void *arg){

......

return IRQ_HANDLED;

}

2.释放中断

  1. void free_irq(unsigned int irq, void *dev_id)
  2. {
  3. struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项
  4. if (!desc)
  5. return;
  6. chip_bus_lock(desc);
  7. kfree(__free_irq(irq, dev_id));
  8. chip_bus_sync_unlock(desc);
  9. }
  10. EXPORT_SYMBOL(free_irq);

2.1 __free_irq

  1. static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
  2. {
  3. struct irq_desc *desc = irq_to_desc(irq);   //获取全局irq_desc数组项
  4. struct irqaction *action, **action_ptr;
  5. unsigned long flags;
  6. WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
  7. if (!desc)
  8. return NULL;
  9. raw_spin_lock_irqsave(&desc->lock, flags);
  10. action_ptr = &desc->action;
  11. for (;;) {
  12. action = *action_ptr;
  13. if (!action) {
  14. WARN(1, "Trying to free already-free IRQ %d\n", irq);
  15. raw_spin_unlock_irqrestore(&desc->lock, flags);
  16. return NULL;
  17. }
  18. if (action->dev_id == dev_id)    //找到匹配的id项
  19. break;
  20. action_ptr = &action->next;
  21. }
  22. *action_ptr = action->next;
  23. #ifdef CONFIG_IRQ_RELEASE_METHOD
  24. if (desc->irq_data.chip->release)
  25. desc->irq_data.chip->release(irq, dev_id);
  26. #endif
  27. if (!desc->action) {
  28. desc->status |= IRQ_DISABLED;
  29. if (desc->irq_data.chip->irq_shutdown)
  30. desc->irq_data.chip->irq_shutdown(&desc->irq_data);
  31. else
  32. desc->irq_data.chip->irq_disable(&desc->irq_data);
  33. }
  34. #ifdef CONFIG_SMP
  35. if (WARN_ON_ONCE(desc->affinity_hint))
  36. desc->affinity_hint = NULL;
  37. #endif
  38. raw_spin_unlock_irqrestore(&desc->lock, flags);
  39. unregister_handler_proc(irq, action);
  40. synchronize_irq(irq);
  41. #ifdef CONFIG_DEBUG_SHIRQ
  42. if (action->flags & IRQF_SHARED) {
  43. local_irq_save(flags);
  44. action->handler(irq, dev_id);
  45. local_irq_restore(flags);
  46. }
  47. #endif
  48. if (action->thread) {
  49. if (!test_bit(IRQTF_DIED, &action->thread_flags))
  50. kthread_stop(action->thread);
  51. put_task_struct(action->thread);
  52. }
  53. return action;
  54. }

四、中断处理过程

1.当有中断发生时,程序会到__vectors_star去查找向量表(arch/arm/kernel/entry-armv.S)

  1. .globl  __vectors_start
  2. _vectors_start:
  3. ARM(    swi SYS_ERROR0  )   /* swi指令 */
  4. THUMB(  svc #0      )
  5. THUMB(  nop         )
  6. W(b)    vector_und + stubs_offset
  7. W(ldr)  pc, .LCvswi + stubs_offset
  8. W(b)    vector_pabt + stubs_offset
  9. W(b)    vector_dabt + stubs_offset
  10. W(b)    vector_addrexcptn + stubs_offset
  11. W(b)    vector_irq + stubs_offset   /* 中断向量表 */
  12. W(b)    vector_fiq + stubs_offset
  13. .globl  __vectors_end
  14. _vectors_end:

2.vector_irq的定义声明

  1. .globl  __stubs_start
  2. __stubs_start:
  3. /*
  4. * Interrupt dispatcher
  5. */
  6. vector_stub irq, IRQ_MODE, 4    /*参看下面vector_stub宏的定义*/
  7. .long   __irq_usr           @  0  (USR_26 / USR_32)     /*usr模式下中断处理(见下面)*/
  8. .long   __irq_invalid       @  1  (FIQ_26 / FIQ_32)
  9. .long   __irq_invalid       @  2  (IRQ_26 / IRQ_32)
  10. .long   __irq_svc           @  3  (SVC_26 / SVC_32)     /*svc模式下中断处理(见下面)*/
  11. .long   __irq_invalid       @  4
  12. .long   __irq_invalid       @  5
  13. .long   __irq_invalid       @  6
  14. .long   __irq_invalid       @  7
  15. .long   __irq_invalid       @  8
  16. .long   __irq_invalid       @  9
  17. .long   __irq_invalid       @  a
  18. .long   __irq_invalid       @  b
  19. .long   __irq_invalid       @  c
  20. .long   __irq_invalid       @  d
  21. .long   __irq_invalid       @  e
  22. .long   __irq_invalid       @  f

3.vector_stub宏的定义

  1. /*vector_stub irq, IRQ_MODE, 4*/
  2. .macro  vector_stub, name, mode, correction=0
  3. .align  5
  4. vector_\name:                       /*构造了vector_irq*/
  5. .if \correction                 /*if 4*/
  6. sub lr, lr, #\correction
  7. .endif
  8. @
  9. @ Save r0, lr_<exception> (parent PC) and spsr_<exception>
  10. @ (parent CPSR)
  11. @
  12. stmia   sp, {r0, lr}        @ save r0, lr
  13. mrs lr, spsr
  14. str lr, [sp, #8]        @ save spsr
  15. @
  16. @ Prepare for SVC32 mode.  IRQs remain disabled.    准备切到svc模式
  17. @
  18. mrs r0, cpsr
  19. eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
  20. msr spsr_cxsf, r0
  21. @ /*分支表必须紧接着这段代码*/
  22. @ the branch table must immediately follow this code
  23. @
  24. and lr, lr, #0x0f
  25. THUMB( adr r0, 1f          )
  26. THUMB( ldr lr, [r0, lr, lsl #2]    )
  27. mov r0, sp
  28. ARM(   ldr lr, [pc, lr, lsl #2]    )
  29. movs    pc, lr          @ branch to handler in SVC mode 跳到分支表处
  30. ENDPROC(vector_\name)
  31. .align  2
  32. @ handler addresses follow this label
  33. 1:
  34. .endm

这几段汇编的大致意思是中断发生会跳到vector_irq去执行,vector_irq根据情况会跳到__irq_usr或__irq_svc执行

4.__irq_usr

  1. __irq_usr:
  2. usr_entry
  3. kuser_cmpxchg_check
  4. get_thread_info tsk
  5. #ifdef CONFIG_PREEMPT
  6. ldr r8, [tsk, #TI_PREEMPT]      @ get preempt count
  7. add r7, r8, #1          @ increment it
  8. str r7, [tsk, #TI_PREEMPT]
  9. #endif
  10. irq_handler     /*跳转到irq_handler处理*/
  11. #ifdef CONFIG_PREEMPT
  12. ldr r0, [tsk, #TI_PREEMPT]
  13. str r8, [tsk, #TI_PREEMPT]
  14. teq r0, r7
  15. ARM(   strne   r0, [r0, -r0]   )
  16. THUMB( movne   r0, #0      )
  17. THUMB( strne   r0, [r0]    )
  18. #endif
  19. mov why, #0
  20. b   ret_to_user
  21. UNWIND(.fnend      )
  22. ENDPROC(__irq_usr)

5.__irq_svc

  1. __irq_svc:
  2. svc_entry
  3. #ifdef CONFIG_TRACE_IRQFLAGS
  4. bl  trace_hardirqs_off
  5. #endif
  6. #ifdef CONFIG_PREEMPT
  7. get_thread_info tsk
  8. ldr r8, [tsk, #TI_PREEMPT]      @ get preempt count
  9. add r7, r8, #1          @ increment it
  10. str r7, [tsk, #TI_PREEMPT]
  11. #endif
  12. irq_handler         /*跳转到irq_handler处理*/
  13. #ifdef CONFIG_PREEMPT
  14. str r8, [tsk, #TI_PREEMPT]      @ restore preempt count
  15. ldr r0, [tsk, #TI_FLAGS]        @ get flags
  16. teq r8, #0              @ if preempt count != 0
  17. movne   r0, #0              @ force flags to 0
  18. tst r0, #_TIF_NEED_RESCHED
  19. blne    svc_preempt
  20. #endif
  21. ldr r4, [sp, #S_PSR]        @ irqs are already disabled
  22. #ifdef CONFIG_TRACE_IRQFLAGS
  23. tst r4, #PSR_I_BIT
  24. bleq    trace_hardirqs_on
  25. #endif
  26. svc_exit r4             @ return from exception
  27. UNWIND(.fnend      )
  28. ENDPROC(__irq_svc)

6.不管是__irq_svc或是__irq_usr都会调用到irqhandler

  1. .macro  irq_handler
  2. get_irqnr_preamble r5, lr
  3. 1:  get_irqnr_and_base r0, r6, r5, lr
  4. movne   r1, sp
  5. @ r0保存了中断号,r1保存了保留现场的寄存器指针
  6. @ routine called with r0 = irq number, r1 = struct pt_regs *
  7. @
  8. adrne   lr, BSYM(1b)
  9. bne asm_do_IRQ  /*********************跳转到asm_do_IRQ函数处理*/
  10. #ifdef CONFIG_SMP
  11. /*
  12. * XXX
  13. *
  14. * this macro assumes that irqstat (r6) and base (r5) are
  15. * preserved from get_irqnr_and_base above
  16. */
  17. ALT_SMP(test_for_ipi r0, r6, r5, lr)
  18. ALT_UP_B(9997f)
  19. movne   r0, sp
  20. adrne   lr, BSYM(1b)
  21. bne do_IPI
  22. #ifdef CONFIG_LOCAL_TIMERS
  23. test_for_ltirq r0, r6, r5, lr
  24. movne   r0, sp
  25. adrne   lr, BSYM(1b)
  26. bne do_local_timer
  27. #endif
  28. 9997:
  29. #endif
  30. .endm

7.就这样进入了c处理的阶段asm_do_IRQ

  1. asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
  2. {
  3. struct pt_regs *old_regs = set_irq_regs(regs);
  4. irq_enter();
  5. /*
  6. * Some hardware gives randomly wrong interrupts.  Rather
  7. * than crashing, do something sensible.
  8. */
  9. if (unlikely(irq >= nr_irqs)) {  //中断号大于中断的个数
  10. if (printk_ratelimit())
  11. printk(KERN_WARNING "Bad IRQ%u\n", irq);
  12. ack_bad_irq(irq);
  13. }
  14. else {
  15. generic_handle_irq(irq);    //通用中断处理函数
  16. }
  17. /* AT91 specific workaround */
  18. irq_finish(irq);
  19. irq_exit();
  20. set_irq_regs(old_regs);
  21. }

8.generic_handle_irq函数

  1. static inline void generic_handle_irq(unsigned int irq)
  2. {
  3. generic_handle_irq_desc(irq, irq_to_desc(irq)); //调用了irq_to_desc获取全局irq_desc[irq]项
  4. }

9.generic_handle_irq_desc函数

  1. static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
  2. {
  3. #ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ   //根据板级配置的设置若定义了
  4. desc->handle_irq(irq, desc); //则只能用指定的handle_irq方法
  5. #else
  6. if (likely(desc->handle_irq))    //若中断处理函数存在
  7. desc->handle_irq(irq, desc); //则调用注册的中断处理函数(irq_desc[irq]->handle_irq(irq,desc))
  8. else
  9. __do_IRQ(irq);  //没指定中断处理函数的处理分支
  10. #endif
  11. }

这里有了分支关键看CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ的设置

如果设置为1,则只调用中断描述符的handle_irq方法

如果设置为0,则如果中断描述符存在handle_irq方法则调用该方法,如果没有则调用__do_IRQ()

中断描述符handle_irq方法,一般是芯片厂商写好的,先看看__do_IRQ()吧

10.__do_IRQ函数

  1. unsigned int __do_IRQ(unsigned int irq)
  2. {
  3. struct irq_desc *desc = irq_to_desc(irq);
  4. struct irqaction *action;
  5. unsigned int status;
  6. kstat_incr_irqs_this_cpu(irq, desc);
  7. if (CHECK_IRQ_PER_CPU(desc->status)) {
  8. irqreturn_t action_ret;
  9. if (desc->irq_data.chip->ack)
  10. desc->irq_data.chip->ack(irq);
  11. if (likely(!(desc->status & IRQ_DISABLED))) {
  12. action_ret = handle_IRQ_event(irq, desc->action);//调用handle_IRQ_event函数
  13. if (!noirqdebug)
  14. note_interrupt(irq, desc, action_ret);
  15. }
  16. desc->irq_data.chip->end(irq);
  17. return 1;
  18. }
  19. raw_spin_lock(&desc->lock);
  20. if (desc->irq_data.chip->ack)
  21. desc->irq_data.chip->ack(irq);
  22. status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING);
  23. status |= IRQ_PENDING; /* we _want_ to handle it */
  24. action = NULL;
  25. if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
  26. action = desc->action;
  27. status &= ~IRQ_PENDING; /* we commit to handling */
  28. status |= IRQ_INPROGRESS; /* we are handling it */
  29. }
  30. desc->status = status;
  31. if (unlikely(!action))
  32. goto out;
  33. for (;;) {
  34. irqreturn_t action_ret;
  35. raw_spin_unlock(&desc->lock);
  36. action_ret = handle_IRQ_event(irq, action);//调用handle_IRQ_event函数
  37. if (!noirqdebug)
  38. note_interrupt(irq, desc, action_ret);
  39. raw_spin_lock(&desc->lock);
  40. if (likely(!(desc->status & IRQ_PENDING)))
  41. break;
  42. desc->status &= ~IRQ_PENDING;
  43. }
  44. desc->status &= ~IRQ_INPROGRESS;
  45. out:
  46. desc->irq_data.chip->end(irq);
  47. raw_spin_unlock(&desc->lock);
  48. return 1;
  49. }

.__do_IRQ函数主要是调用handle_IRQ_event来处理中断

11.handle_IRQ_event函数

  1. irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
  2. {
  3. irqreturn_t ret, retval = IRQ_NONE;
  4. unsigned int status = 0;
  5. do {
  6. trace_irq_handler_entry(irq, action);
  7. ret = action->handler(irq, action->dev_id);//调用了irqaction的handler方法
  8. trace_irq_handler_exit(irq, action, ret);
  9. switch (ret) {
  10. case IRQ_WAKE_THREAD:
  11. ret = IRQ_HANDLED;
  12. if (unlikely(!action->thread_fn)) {
  13. warn_no_thread(irq, action);
  14. break;
  15. }
  16. if (likely(!test_bit(IRQTF_DIED,
  17. &action->thread_flags))) {
  18. set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
  19. wake_up_process(action->thread);
  20. }
  21. case IRQ_HANDLED:
  22. status |= action->flags;
  23. break;
  24. default:
  25. break;
  26. }
  27. retval |= ret;
  28. action = action->next;
  29. } while (action);
  30. if (status & IRQF_SAMPLE_RANDOM)
  31. add_interrupt_randomness(irq);
  32. local_irq_disable();
  33. return retval;
  34. }

这里调用的irqaction的handler方法就是调用了之前设备驱动中用request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)

申请中断时传递进来的第二个参数的函数
其实很多芯片厂商在编写中断描述符handle_irq方法的时候也会调用到handle_IRQ_event函数

整个中断的处理过程就是

linux 中断机制浅析的更多相关文章

  1. SQL Server on Linux 理由浅析

    SQL Server on Linux 理由浅析 今天的爆炸性新闻<SQL Server on Linux>基本上在各大科技媒体上刷屏了 大家看到这个新闻都觉得非常震精,而美股,今天微软开 ...

  2. linux网桥浅析

    linux网桥浅析 原文链接:http://hi.baidu.com/_kouu/item/25787d38efec56637c034bd0 什么是桥接?简单来说,桥接就是把一台机器上的若干个网络接口 ...

  3. Linux 中断处理浅析

    最近在研究异步消息处理, 突然想起linux内核的中断处理, 里面由始至终都贯穿着"重要的事马上做, 不重要的事推后做"的异步处理思想. 于是整理一下~ 第一阶段--获取中断号 每 ...

  4. linux awk浅析(转)

    Awk 是一种非常好的语言,同时有一个非常奇怪的名称.在本系列(共三篇文章)的第一篇文章中,Daniel Robbins 将使您迅速掌握 awk 编程技巧.随着本系列的进展,将讨论更高级的主题,最后将 ...

  5. Linux文件管理浅析(一) _磁盘管理基础

    本文主要讨论一些磁盘管理相关的基本概念,同时也是这一系列文章的第一篇,就是下图中的最下一层的一部分. 在Linux中,SATA/USB/SCSI接口都是使用SCSI模块实现的,所以使用这些接口的硬盘在 ...

  6. 转 Linux会话浅析(写得极好,表述清楚语言不硬)

    说起会话,我们经常登录到linux系统,执行各种各样的程序,这都牵涉到会话.但是,一般情况下我们又很少会去关注到会话的存在,很少会去了解它的来龙去脉.本文就对linux会话相关的信息做一些整理,看看隐 ...

  7. Linux 线程浅析

    进程和线程的区别与联系 在许多经典的操作系统教科书中,总是把进程定义为程序的执行实例,它并不执行什么, 只是维护应用程序所需的各种资源,而线程则是真正的执行实体. 为了让进程完成一定的工作,进程必须至 ...

  8. Linux中断机制

    1.中断概念 中断是指在CPU正常运行期间,由于内外部事件或由程序预先安排的事件引起的CPU暂时停止正在运行的程序,转而为该内部或外部事件或预先安排的事件服务的程序中去,服务完毕后再返回去继续运行被暂 ...

  9. Linux Cgroup浅析

    cgroup从2.6.4引入linux内核主线,目前默认已启用该特性.在cgroup出现之前,只能对一个进程做资源限制,比如通过sched_setaffinity设置进程cpu亲和性,使用ulimit ...

随机推荐

  1. Django 路由 —— Djangon如何处理一个请求

    Django URL路由概述 一个干净优雅的URL方案是高质量Web应用程序中的一个重要细则Django可以让你设计URL,无论你想要什么,没有框剪限制要为应用程序设计URL,您可以非正式地创建一个名 ...

  2. DP || HYSBZ 1207 打鼹鼠

    n*n的网格,有m个鼹鼠,t时间会有一只鼹鼠出现在(x,y)点处,如果机器人也在这个点就可以打到鼹鼠 机器人初始位置任意,每秒可以移动一格,问最多打到多少鼹鼠 *解法:f[i]表示前i只鼹鼠打了多少个 ...

  3. C++ Simple Message/Logging Class

    在 Qt的源码与Protobuf 的代码中,看到相同的简单消息(日志)输出的类实现,基本思路是使用宏定义,重载临时类对象,调用类方法或者通过析构函数自动调用输出方法,实现消息输出.这里以 Protob ...

  4. 组管理命令--groupadd.groupmod.groupdel.gpasswd

    添加用户组 格式 groupadd [参数] 组名 参数选项 -g GID:指定新组的GID,默认值是已有的最大的GID加1.-r:建立一个系统专用组,与-g不同时使用时,则分配一个1-499的GID ...

  5. docker-machine 快速搭建docker环境

    环境:腾讯云测试成功 1.条件:本地主机A和远程主机B 2.远程主机B,配置免密登录 1,在本地主机A上生成公钥和私钥,生成命令:ssh-keygen -t rsa 私钥:id_rsa 公钥:id_r ...

  6. Python旅途——简单语法

    1. 前言 在我们对环境以及pycharm安装好之后,我们就可以开始我们的Python之旅了,那么,我们学习一门语言应该如何开始呢?就像我们学习汉语一样,从abcd这些拼音学起,而对于我们Python ...

  7. c++ 十进制转二进制 代码实现

    我初中的时候就没搞清楚手动怎么算二进制 写这个代码的时候研究了好久百度 https://jingyan.baidu.com/article/597a0643614568312b5243c0.html ...

  8. tomcat常见设置

    1.请求日志 tomcat 统一访问日志记录,添加请求响应时间 <Host name="localhost" appBase="webapps" unpa ...

  9. 【01】魔芋使用MDN的一点点经验

    [01]魔芋使用MDN的一点点经验     1,MDN地址: https://developer.mozilla.org/en-US/(下图)   2,建议看英文原文.因为中文翻译落后,并且有些翻译并 ...

  10. 大数据学习——点击流日志每天都10T,在业务应用服务器上,需要准实时上传至(Hadoop HDFS)上

    点击流日志每天都10T,在业务应用服务器上,需要准实时上传至(Hadoop HDFS)上 1需求说明 点击流日志每天都10T,在业务应用服务器上,需要准实时上传至(Hadoop HDFS)上 2需求分 ...