📄 fen-data.c
字号:
return 0; }}voidfdata_sub_add (fdata *f, gpointer sub){ FD_W ("[%s] [data: 0x%p ] [s: 0x%p ] %s\n", __func__, f, sub, FN_NAME(f)); g_assert (g_list_find_custom (f->subs, sub, (GCompareFunc)fdata_sub_find) == NULL); f->subs = g_list_prepend (f->subs, sub);}voidfdata_sub_remove (fdata *f, gpointer sub){ GList *l; FD_W ("[%s] [data: 0x%p ] [s: 0x%p ] %s\n", __func__, f, sub, FN_NAME(f)); g_assert (g_list_find_custom (f->subs, sub, (GCompareFunc)fdata_sub_find) != NULL); l = g_list_find_custom (f->subs, sub, (GCompareFunc)fdata_sub_find); g_assert (l); g_assert (sub == l->data); f->subs = g_list_delete_link (f->subs, l);}/** * Adjust self on failing to Port */voidfdata_adjust_deleted (fdata* f){ node_t* parent; fdata* pdata; node_op_t op = {NULL, NULL, pre_del_cb, NULL}; /* * It's a top node. We move it to missing list. */ parent = get_parent_node (f); pdata = get_parent_data (f); if (!FN_IS_PASSIVE(f) || children_num (FN_NODE(f)) > 0 || (pdata && !FN_IS_PASSIVE(pdata))) { if (parent) { if (pdata == NULL) { pdata = fdata_new (parent, FALSE); } g_assert (pdata); if (!port_add (&pdata->fobj, &pdata->len, pdata)) { fdata_adjust_deleted (pdata); } } else { /* f is root */ g_assert (IS_TOPNODE(FN_NODE(f))); missing_add (f); } } else {#ifdef GIO_COMPILATION pending_remove_node (FN_NODE(f), &op);#else remove_node (FN_NODE(f), &op);#endif }}static gbooleanfdata_adjust_changed (fdata *f){ fnode_event_t *ev; struct stat buf; node_t* parent; fdata* pdata; G_LOCK (fen_lock); parent = get_parent_node (f); pdata = get_parent_data (f); if (!FN_IS_LIVING(f) || (children_num (FN_NODE(f)) == 0 && FN_IS_PASSIVE(f) && pdata && FN_IS_PASSIVE(pdata))) { f->change_update_id = 0; G_UNLOCK (fen_lock); return FALSE; } FD_W ("[ %s ] %s\n", __func__, FN_NAME(f)); if (FN_STAT (FN_NAME(f), &buf) != 0) { FD_W ("LSTAT [%-20s] %s\n", FN_NAME(f), g_strerror (errno)); goto L_delete; } f->is_dir = S_ISDIR (buf.st_mode) ? TRUE : FALSE; if (f->len != buf.st_size) { /* FD_W ("LEN [%lld:%lld] %s\n", f->len, buf.st_size, FN_NAME(f)); */ f->len = buf.st_size; ev = fnode_event_new (FILE_MODIFIED, TRUE, f); if (ev != NULL) { ev->is_pending = TRUE; fdata_add_event (f, ev); } /* Fdata is still changing, so scalable scan */ f->change_update_id = g_timeout_add (get_scalable_scan_time (f), (GSourceFunc)fdata_adjust_changed, (gpointer)f); G_UNLOCK (fen_lock); return FALSE; } else { f->changed_event_num = 0; f->fobj.fo_atime = buf.st_atim; f->fobj.fo_mtime = buf.st_mtim; f->fobj.fo_ctime = buf.st_ctim; if (FN_IS_DIR(f)) { if (FN_IS_MONDIR(f)) { scan_children (FN_NODE(f)); } else { scan_known_children (FN_NODE(f)); if ((children_num (FN_NODE(f)) == 0 && FN_IS_PASSIVE(f) && pdata && FN_IS_PASSIVE(pdata))) { port_remove (f); goto L_exit; } } } if (!port_add_simple (&f->fobj, f)) { L_delete: ev = fnode_event_new (FILE_DELETE, FALSE, f); if (ev != NULL) { fdata_add_event (f, ev); } } }L_exit: f->change_update_id = 0; G_UNLOCK (fen_lock); return FALSE;}voidfdata_emit_events_once (fdata *f, int event, gpointer sub){ emit_once_cb (f, _event_converter (event), sub);}voidfdata_emit_events (fdata *f, int event){ emit_cb (f, _event_converter (event));}static gbooleanprocess_events (gpointer udata){ node_op_t op = {NULL, NULL, pre_del_cb, NULL}; fdata* f; fnode_event_t* ev; int e; /* FD_W ("IN <======== %s\n", __func__); */ f = (fdata*)udata; FD_W ("%s 0x%p id:%-4d %s\n", __func__, f, f->eventq_id, FN_NAME(f)); G_LOCK (fen_lock); if (!FN_IS_LIVING(f)) { f->eventq_id = 0; G_UNLOCK (fen_lock); return FALSE; } if ((ev = (fnode_event_t*)g_queue_pop_head (f->eventq)) != NULL) { /* Send events to clients. */ e = ev->e; if (!ev->is_pending) {#ifdef GIO_COMPILATION if (ev->has_twin) { fdata_emit_events (f, FILE_ATTRIB); }#endif fdata_emit_events (f, ev->e); } fnode_event_delete (ev); ev = NULL; /* Adjust node state. */ /* * Node the node has been created, so we can delete create event in * optimizing. To reduce the statings, we add it to Port on discoving * it then emit CREATED event. So we don't need to do anything here. */ switch (e) { case FILE_MODIFIED: case MOUNTEDOVER: case UNMOUNTED: /* If the event is a changed event, then pending process it */ if (f->change_update_id == 0) { f->change_update_id = g_timeout_add (get_scalable_scan_time(f), (GSourceFunc)fdata_adjust_changed, (gpointer)f); g_assert (f->change_update_id > 0); } break; case FILE_ATTRIB: g_assert (f->change_update_id == 0); if (!port_add (&f->fobj, &f->len, f)) { ev = fnode_event_new (FILE_DELETE, FALSE, f); if (ev != NULL) { fdata_add_event (f, ev); } } break; case FILE_DELETE: /* Ignored */ break; default: g_assert_not_reached (); break; } /* Process one event a time */ G_UNLOCK (fen_lock); return TRUE; } f->eventq_id = 0; G_UNLOCK (fen_lock); /* FD_W ("OUT ========> %s\n", __func__); */ return FALSE;}/** * fdata_add_event: * */voidfdata_add_event (fdata *f, fnode_event_t *ev){ node_op_t op = {NULL, NULL, pre_del_cb, NULL}; fnode_event_t *tail; if (!FN_IS_LIVING(f)) { fnode_event_delete (ev); return; } FD_W ("%s %d\n", __func__, ev->e); g_get_current_time (&ev->t); /* * If created/deleted events of child node happened, then we use parent * event queue to handle. * If child node emits deleted event, it seems no changes for the parent * node, but the attr is changed. So we may try to cancel processing the * coming changed events of the parent node. */ tail = (fnode_event_t*)g_queue_peek_tail (f->eventq); switch (ev->e) { case FILE_RENAME_FROM: case FILE_RENAME_TO: case FILE_ACCESS: fnode_event_delete (ev); g_assert_not_reached (); return; case FILE_DELETE: /* clear changed event number */ f->changed_event_num = 0; /* * We will cancel all previous events. */ if (tail) { g_queue_pop_tail (f->eventq); do { fnode_event_delete (tail); } while ((tail = (fnode_event_t*)g_queue_pop_tail (f->eventq)) != NULL); } /* * Given a node "f" is deleted, process it ASAP. */ fdata_emit_events (f, ev->e); fnode_event_delete (ev); fdata_adjust_deleted (f); return; case FILE_MODIFIED: case UNMOUNTED: case MOUNTEDOVER: /* clear changed event number */ f->changed_event_num ++; case FILE_ATTRIB: default: /* * If in the time range, we will try optimizing * (changed+) to (changed) * (attrchanged changed) to ([changed, attrchanged]) * (event attrchanged) to ([event, attrchanged]) */ if (tail) { do { if (tail->e == ev->e) { if (g_timeval_lt (&ev->t, &tail->t)) { g_queue_peek_tail (f->eventq); /* Add the increment */ g_time_val_add (&ev->t, PAIR_EVENTS_INC_TIMEVAL); /* skip the previous event */ FD_W ("SKIPPED -- %s\n", _event_string (tail->e)); fnode_event_delete (tail); } else { break; } } else if (ev->e == FILE_MODIFIED && tail->e == FILE_ATTRIB) { ev->has_twin = TRUE; fnode_event_delete (tail); } else if (ev->e == FILE_ATTRIB && f->change_update_id > 0) { tail->has_twin = TRUE; /* skip the current event */ fnode_event_delete (ev); return; } else { break; } } while ((tail = (fnode_event_t*)g_queue_peek_tail (f->eventq)) != NULL); } } /* must add the threshold time */ g_time_val_add (&ev->t, PAIR_EVENTS_TIMEVAL); g_queue_push_tail (f->eventq, ev); /* starting process_events */ if (f->eventq_id == 0) { f->eventq_id = g_timeout_add (PROCESS_EVENTQ_TIME, process_events, (gpointer)f); g_assert (f->eventq_id > 0); } FD_W ("%s 0x%p id:%-4d %s\n", __func__, f, f->eventq_id, FN_NAME(f));}gbooleanfdata_class_init (void (*user_emit_cb) (fdata*, int), void (*user_emit_once_cb) (fdata*, int, gpointer), int (*user_event_converter) (int event)){ FD_W ("%s\n", __func__); if (user_emit_cb == NULL) { return FALSE; } if (user_emit_once_cb == NULL) { return FALSE; } if (user_event_converter == NULL) { return FALSE; } emit_cb = user_emit_cb; emit_once_cb = user_emit_once_cb; _event_converter = user_event_converter; if (!port_class_init (fdata_add_event)) { FD_W ("port_class_init failed."); return FALSE; } return TRUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -