事件处理循环

现在我们已经设置了一些监控,接下来就要等待事件。如果还存在监控,并且 keep_running 标志没有被信号处理程序重置,则循环会一直进行。循环进程等待事件的发生,对有效事件进行排队,并在返回等待状态之前并处理队列。 在真实应用程序当中,可能会采用一个线程将事件放入队列,而采用另一个线程处理它们,清单 5 展示了该循环。

清单 5. 事件处理循环

  1. int process_inotify_events (queue_t q, int fd)  
  2. {  
  3. while (keep_running && (watched_items > 0))  
  4. {  
  5. if (event_check (fd) > 0)  
  6. {  
  7. int r;  
  8. r = read_events (q, fd);  
  9. if (r < 0)  
  10. {  
  11. break;  
  12. }  
  13. else  
  14. {  
  15. handle_events (q);  
  16. }  
  17. }  
  18. }  
  19. return 0;  

等待事件

在本程序中,循环会不停地进行下去,直至发生被监控事件或者收到了中断信号。清单 6 展示了相关代码。

清单 6. 等待事件或中断

  1. int event_check (int fd)  
  2. {  
  3. fd_set rfds;  
  4. FD_ZERO (&rfds);  
  5. FD_SET (fd, &rfds);  
  6. /* Wait until an event happens or we get interrupted   
  7. by a signal that we catch */  
  8. return select (FD_SETSIZE, &rfds, NULL, NULL, NULL);  

读取事件

当事件发生时,程序会依照缓存区的大小来读取尽量多的事件,然后把这些事件放入队列等待事件处理程序来处理。 样例代码对于事件量大于 16.384-byte 之类的问题不作处理。 想处理这类问题,需要在缓存末端处理局部事件。当前对名字长度所做的限制没有问题,但是优秀的防御式编程会检查名字,来确保不会出现缓存区溢出。

清单 7. 读取事件并排队

  1. int read_events (queue_t q, int fd)  
  2. {  
  3. char buffer[16384];  
  4. size_t buffer_i;  
  5. struct inotify_event *pevent;  
  6. queue_entry_t event;  
  7. ssize_t r;  
  8. size_t event_size, q_event_size;-  
  9. int count = 0;  
  10. r = read (fd, buffer, 16384);  
  11. if (r <= 0)  
  12. return r;  
  13. buffer_i = 0;  
  14. while (buffer_i < r)  
  15. {  
  16. /* Parse events and queue them. */  
  17. pevent = (struct inotify_event *) &buffer[buffer_i];  
  18. event_size = offsetof (struct inotify_event, name) + pevent->
    len;  
  19. q_event_size = offsetof (struct queue_entry, inot_ev.name) +   
  20. pevent->len;  
  21. event = malloc (q_event_size);  
  22. memmove (&(event->inot_ev), pevent, event_size);  
  23. queue_enqueue (event, q);  
  24. buffer_i += event_size;  
  25. count++;  
  26. }  
  27. printf ("\n%d events queued\n", count);  
  28. return count;  

处理事件

最终,需要对事件做处理。本例中的应用程序不处理事件,只报告发生了哪些事件。如果事件结构体中有一个名字出现, 程序将报告其是目录还是文件。在发生移动操作时,还会报告与移动或重命名事件相关的 cookie 信息。 清单 8 展示了部分代码,包括对一些事件的处理。参见 下载 部分可获得全部代码。

清单 8. 处理事件

  1. void handle_event (queue_entry_t event)  
  2. {  
  3. /* If the event was associated with a filename, we will 
    store it here */  
  4. char *cur_event_filename = NULL;  
  5. char *cur_event_file_or_dir = NULL;  
  6. /* This is the watch descriptor the event occurred on */  
  7. int cur_event_wd = event->inot_ev.wd;  
  8. int cur_event_cookie = event->inot_ev.cookie;  
  9. unsigned long flags;  
  10. if (event->inot_ev.len)  
  11. {  
  12. cur_event_filename = event->inot_ev.name;  
  13. }  
  14. if ( event->inot_ev.mask & IN_ISDIR )  
  15. {  
  16. cur_event_file_or_dir = "Dir";  
  17. }  
  18. else   
  19. {  
  20. cur_event_file_or_dir = "File";  
  21. }  
  22. flags = event->inot_ev.mask &   
  23. ~(IN_ALL_EVENTS | IN_UNMOUNT | IN_Q_OVERFLOW | IN_IGNORED );  
  24. /* Perform event dependent handler routines */  
  25. /* The mask is the magic that tells us what file operation 
    occurred */  
  26. switch (event->inot_ev.mask &   
  27. (IN_ALL_EVENTS | IN_UNMOUNT | IN_Q_OVERFLOW | IN_IGNORED))  
  28. {  
  29. /* File was accessed */  
  30. case IN_ACCESS:  
  31. printf ("ACCESS: %s \"%s\" on WD #%i\n",  
  32. cur_event_file_or_dir, cur_event_filename, cur_event_wd);  
  33. break;  
  34. /* File was modified */  
  35. case IN_MODIFY:  
  36. printf ("MODIFY: %s \"%s\" on WD #%i\n",  
  37. cur_event_file_or_dir, cur_event_filename, cur_event_wd);  
  38. break;  
  39. /* File changed attributes */  
  40. case IN_ATTRIB:  
  41. printf ("ATTRIB: %s \"%s\" on WD #%i\n",  
  42. cur_event_file_or_dir, cur_event_filename, cur_event_wd);  
  43. break;  
  44. /* File open for writing was closed */  
  45. case IN_CLOSE_WRITE:  
  46. printf ("CLOSE_WRITE: %s \"%s\" on WD #%i\n",  
  47. cur_event_file_or_dir, cur_event_filename, cur_event_wd);  
  48. break;  
  49. /* File open read-only was closed */  
  50. case IN_CLOSE_NOWRITE:  
  51. printf ("CLOSE_NOWRITE: %s \"%s\" on WD #%i\n",  
  52. cur_event_file_or_dir, cur_event_filename, cur_event_wd);  
  53. break;  
  54. /* File was opened */  
  55. case IN_OPEN:  
  56. printf ("OPEN: %s \"%s\" on WD #%i\n",  
  57. cur_event_file_or_dir, cur_event_filename, cur_event_wd);  
  58. break;  
  59. /* File was moved from X */  
  60. case IN_MOVED_FROM:  
  61. printf ("MOVED_FROM: %s \"%s\" on WD #%i. Cookie=%d\n",  
  62. cur_event_file_or_dir, cur_event_filename, cur_event_wd,   
  63. cur_event_cookie);  
  64. break;  
  65. .  
  66. . (other cases)  
  67. .  
  68. /* Watch was removed explicitly by inotify_rm_watch or 
    automatically  
  69. because file was deleted, or file system was unmounted. */  
  70. case IN_IGNORED:  
  71. watched_items--;  
  72. printf ("IGNORED: WD #%d\n", cur_event_wd);  
  73. printf("Watching = %d items\n",watched_items);   
  74. break;  
  75. /* Some unknown message received */  
  76. default:  
  77. printf ("UNKNOWN EVENT \"%X\" OCCURRED for file \"%s\" on WD #%i\n",  
  78. event->inot_ev.mask, cur_event_filename, cur_event_wd);  
  79. break;  
  80. }  
  81. /* If any flags were set other than IN_ISDIR, report the flags */  
  82. if (flags & (~IN_ISDIR))  
  83. {  
  84. flags = event->inot_ev.mask;  
  85. printf ("Flags=%lX\n", flags);  
  86. }  

该例子用来举例说明 inotify 如何工作以及能够监控哪些事件。 您的实际需求将决定对哪些事件进行监控以及如何处理这些事件。


相关内容