📄 inotify-kernel.c
字号:
if (is_dir) { switch (mask) { case IN_ACCESS: return "ACCESS (dir)"; case IN_MODIFY: return "MODIFY (dir)"; case IN_ATTRIB: return "ATTRIB (dir)"; case IN_CLOSE_WRITE: return "CLOSE_WRITE (dir)"; case IN_CLOSE_NOWRITE: return "CLOSE_NOWRITE (dir)"; case IN_OPEN: return "OPEN (dir)"; case IN_MOVED_FROM: return "MOVED_FROM (dir)"; case IN_MOVED_TO: return "MOVED_TO (dir)"; case IN_DELETE: return "DELETE (dir)"; case IN_CREATE: return "CREATE (dir)"; case IN_DELETE_SELF: return "DELETE_SELF (dir)"; case IN_UNMOUNT: return "UNMOUNT (dir)"; case IN_Q_OVERFLOW: return "Q_OVERFLOW (dir)"; case IN_IGNORED: return "IGNORED (dir)"; default: return "UNKNOWN_EVENT (dir)"; } } else { switch (mask) { case IN_ACCESS: return "ACCESS"; case IN_MODIFY: return "MODIFY"; case IN_ATTRIB: return "ATTRIB"; case IN_CLOSE_WRITE: return "CLOSE_WRITE"; case IN_CLOSE_NOWRITE: return "CLOSE_NOWRITE"; case IN_OPEN: return "OPEN"; case IN_MOVED_FROM: return "MOVED_FROM"; case IN_MOVED_TO: return "MOVED_TO"; case IN_DELETE: return "DELETE"; case IN_CREATE: return "CREATE"; case IN_DELETE_SELF: return "DELETE_SELF"; case IN_UNMOUNT: return "UNMOUNT"; case IN_Q_OVERFLOW: return "Q_OVERFLOW"; case IN_IGNORED: return "IGNORED"; default: return "UNKNOWN_EVENT"; } }}static voidik_read_events (gsize *buffer_size_out, gchar **buffer_out){ static gchar *buffer = NULL; static gsize buffer_size; /* Initialize the buffer on our first call */ if (buffer == NULL) { buffer_size = AVERAGE_EVENT_SIZE; buffer_size *= MAX_QUEUED_EVENTS; buffer = g_malloc (buffer_size); } *buffer_size_out = 0; *buffer_out = NULL; memset (buffer, 0, buffer_size); if (g_io_channel_read_chars (inotify_read_ioc, (char *)buffer, buffer_size, buffer_size_out, NULL) != G_IO_STATUS_NORMAL) { /* error reading */ } *buffer_out = buffer;}static gbooleanik_read_callback (gpointer user_data){ gchar *buffer; gsize buffer_size, buffer_i, events; G_LOCK (inotify_lock); ik_read_events (&buffer_size, &buffer); buffer_i = 0; events = 0; while (buffer_i < buffer_size) { struct inotify_event *event; gsize event_size; event = (struct inotify_event *)&buffer[buffer_i]; event_size = sizeof(struct inotify_event) + event->len; g_queue_push_tail (events_to_process, ik_event_internal_new (ik_event_new (&buffer[buffer_i]))); buffer_i += event_size; events++; } /* If the event process callback is off, turn it back on */ if (!process_eq_running && events) { process_eq_running = TRUE; g_timeout_add (PROCESS_EVENTS_TIME, ik_process_eq_callback, NULL); } G_UNLOCK (inotify_lock); return TRUE;}static gbooleang_timeval_lt (GTimeVal *val1, GTimeVal *val2){ if (val1->tv_sec < val2->tv_sec) return TRUE; if (val1->tv_sec > val2->tv_sec) return FALSE; /* val1->tv_sec == val2->tv_sec */ if (val1->tv_usec < val2->tv_usec) return TRUE; return FALSE;}static gbooleang_timeval_eq (GTimeVal *val1, GTimeVal *val2){ return (val1->tv_sec == val2->tv_sec) && (val1->tv_usec == val2->tv_usec);}static voidik_pair_events (ik_event_internal_t *event1, ik_event_internal_t *event2){ g_assert (event1 && event2); /* We should only be pairing events that have the same cookie */ g_assert (event1->event->cookie == event2->event->cookie); /* We shouldn't pair an event that already is paired */ g_assert (event1->pair == NULL && event2->pair == NULL); /* Pair the internal structures and the ik_event_t structures */ event1->pair = event2; event1->event->pair = event2->event; if (g_timeval_lt (&event1->hold_until, &event2->hold_until)) event1->hold_until = event2->hold_until; event2->hold_until = event1->hold_until;}static voidik_event_add_microseconds (ik_event_internal_t *event, glong ms){ g_assert (event); g_time_val_add (&event->hold_until, ms);}static gbooleanik_event_ready (ik_event_internal_t *event){ GTimeVal tv; g_assert (event); g_get_current_time (&tv); /* An event is ready if, * * it has no cookie -- there is nothing to be gained by holding it * or, it is already paired -- we don't need to hold it anymore * or, we have held it long enough */ return event->event->cookie == 0 || event->pair != NULL || g_timeval_lt (&event->hold_until, &tv) || g_timeval_eq (&event->hold_until, &tv);}static voidik_pair_moves (gpointer data, gpointer user_data){ ik_event_internal_t *event = (ik_event_internal_t *)data; if (event->seen == TRUE || event->sent == TRUE) return; if (event->event->cookie != 0) { /* When we get a MOVED_FROM event we delay sending the event by * MOVE_HOLD_UNTIL_TIME microseconds. We need to do this because a * MOVED_TO pair _might_ be coming in the near future */ if (event->event->mask & IN_MOVED_FROM) { g_hash_table_insert (cookie_hash, GINT_TO_POINTER (event->event->cookie), event); /* because we don't deliver move events there is no point in waiting for the match right now. */ ik_event_add_microseconds (event, MOVE_HOLD_UNTIL_TIME); } else if (event->event->mask & IN_MOVED_TO) { /* We need to check if we are waiting for this MOVED_TO events cookie to pair it with * a MOVED_FROM */ ik_event_internal_t *match = NULL; match = g_hash_table_lookup (cookie_hash, GINT_TO_POINTER (event->event->cookie)); if (match) { g_hash_table_remove (cookie_hash, GINT_TO_POINTER (event->event->cookie)); ik_pair_events (match, event); } } } event->seen = TRUE;}static voidik_process_events (void){ g_queue_foreach (events_to_process, ik_pair_moves, NULL); while (!g_queue_is_empty (events_to_process)) { ik_event_internal_t *event = g_queue_peek_head (events_to_process); /* This must have been sent as part of a MOVED_TO/MOVED_FROM */ if (event->sent) { /* Pop event */ g_queue_pop_head (events_to_process); /* Free the internal event structure */ g_free (event); continue; } /* The event isn't ready yet */ if (!ik_event_ready (event)) break; /* Pop it */ event = g_queue_pop_head (events_to_process); /* Check if this is a MOVED_FROM that is also sitting in the cookie_hash */ if (event->event->cookie && event->pair == NULL && g_hash_table_lookup (cookie_hash, GINT_TO_POINTER (event->event->cookie))) g_hash_table_remove (cookie_hash, GINT_TO_POINTER (event->event->cookie)); if (event->pair) { /* We send out paired MOVED_FROM/MOVED_TO events in the same event buffer */ /* g_assert (event->event->mask == IN_MOVED_FROM && event->pair->event->mask == IN_MOVED_TO); */ /* Copy the paired data */ event->pair->sent = TRUE; event->sent = TRUE; ik_move_matches++; } else if (event->event->cookie) { /* If we couldn't pair a MOVED_FROM and MOVED_TO together, we change * the event masks */ /* Changeing MOVED_FROM to DELETE and MOVED_TO to create lets us make * the gaurantee that you will never see a non-matched MOVE event */ if (event->event->mask & IN_MOVED_FROM) { event->event->mask = IN_DELETE|(event->event->mask & IN_ISDIR); ik_move_misses++; /* not super accurate, if we aren't watching the destination it still counts as a miss */ } if (event->event->mask & IN_MOVED_TO) event->event->mask = IN_CREATE|(event->event->mask & IN_ISDIR); } /* Push the ik_event_t onto the event queue */ g_queue_push_tail (event_queue, event->event); /* Free the internal event structure */ g_free (event); }}static gbooleanik_process_eq_callback (gpointer user_data){ gboolean res; /* Try and move as many events to the event queue */ G_LOCK (inotify_lock); ik_process_events (); while (!g_queue_is_empty (event_queue)) { ik_event_t *event = g_queue_pop_head (event_queue); user_cb (event); } res = TRUE; if (g_queue_get_length (events_to_process) == 0) { process_eq_running = FALSE; res = FALSE; } G_UNLOCK (inotify_lock); return res;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -