static void command_read_cb (CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) { SeafWTMonitorPriv *priv = (SeafWTMonitorPriv *)info; WatchCommand cmd; int n; n = pipereadn (priv->cmd_pipe[0], &cmd, sizeof(cmd)); if (n != sizeof(cmd)) { seaf_warning ("[wt mon] failed to read command.\n"); CFFileDescriptorEnableCallBacks (fdref, kCFFileDescriptorReadCallBack); return; } seaf_debug ("[wt mon] %ld receive command type=%d, repo=%s\n", (long)CFRunLoopGetCurrent(), cmd.type, cmd.repo_id); handle_watch_command (priv, &cmd); CFFileDescriptorEnableCallBacks (fdref, kCFFileDescriptorReadCallBack); }
static void * wt_monitor_job (void *vmonitor) { SeafWTMonitor *monitor = vmonitor; SeafWTMonitorPriv *priv = monitor->priv; /* 2 * sizeof(inotify_event) + 256, should be large enough for one event.*/ WTStatus *status; WatchCommand cmd; int n; int rc; fd_set fds; int inotify_fd; char event_buf[(sizeof(struct inotify_event) << 1) + 256]; gpointer key, value; GHashTableIter iter; FD_SET (priv->cmd_pipe[0], &priv->read_fds); priv->maxfd = priv->cmd_pipe[0]; while (1) { fds = priv->read_fds; rc = select (priv->maxfd + 1, &fds, NULL, NULL, NULL); if (rc < 0 && errno == EINTR) { continue; } else if (rc < 0) { seaf_warning ("[wt mon] select error: %s.\n", strerror(errno)); break; } if (FD_ISSET (priv->cmd_pipe[0], &fds)) { n = pipereadn (priv->cmd_pipe[0], &cmd, sizeof(cmd)); if (n != sizeof(cmd)) { seaf_warning ("[wt mon] failed to read command.\n"); continue; } handle_watch_command (priv, &cmd); } g_hash_table_iter_init (&iter, priv->status_hash); while (g_hash_table_iter_next (&iter, &key, &value)) { inotify_fd = (int)(long)key; if (FD_ISSET (inotify_fd, &fds)) { /* We don't care about the details of the event now. * So we just read out the data but don't parse it. * We may read partial event structure. */ n = read (inotify_fd, event_buf, sizeof(event_buf)); if (n <= 0) { seaf_warning ("[wt mon] failed to read inotify event.\n"); continue; } status = value; if (status) { g_atomic_int_set (&status->last_changed, (gint)time(NULL)); } } } } return NULL; }
static void * wt_monitor_job_win32 (void *vmonitor) { SeafWTMonitor *monitor = vmonitor; SeafWTMonitorPriv *priv = monitor->priv; /* 2 * sizeof(inotify_event) + 256, should be large enough for one event.*/ RepoWatchInfo *info; DWORD bytesRead = 0; ULONG_PTR key = 0; OVERLAPPED *ol = NULL; /* Use I/O Completion Port to watch asynchronous events on: * 1) dir watch handles(events created by ReadDirectoryChangesW) * 2) the cmd pipe (which is a socket indeed) */ if (!add_all_to_iocp(monitor)) { seaf_warning("Failed to add all to iocp\n"); return NULL; } while (1) { BOOL ret = GetQueuedCompletionStatus (priv->iocp_handle, /* iocp handle */ &bytesRead, /* length of info */ &key, /* completion key */ &ol, /* OVERLAPPED */ INFINITE); /* timeout */ static int retry; if (!ret) { seaf_warning ("GetQueuedCompletionStatus failed, " "error code %lu", GetLastError()); if (retry++ < 3) continue; else break; } else { /* clear the retry counter on success */ retry = 0; } if (key == (ULONG_PTR)monitor->cmd_pipe[0]) { /* Triggered by a cmd pipe event */ if (bytesRead != sizeof(WatchCommand)) { seaf_warning ("broken cmd from pipe: get" " %d(expected: %d) bytes\n", (int)bytesRead, sizeof(WatchCommand)); continue; } seaf_debug ("recevied a pipe cmd, type %d for repo %s\n", priv->cmd.type, priv->cmd.repo_id); handle_watch_command (monitor, &priv->cmd); reset_overlapped(ol); start_watch_cmd_pipe (monitor, ol); } else { /* Trigger by one of the dir watch handles */ HANDLE hTriggered = (HANDLE)key; info = (RepoWatchInfo *)g_hash_table_lookup (priv->info_hash, (gconstpointer)hTriggered); if (info) { DirWatchAux *aux = g_hash_table_lookup (priv->buf_hash, (gconstpointer)hTriggered); process_events (info->status->repo_id, info, aux->buf, bytesRead); reset_overlapped(ol); if (!start_watch_dir_change(priv, hTriggered)) { seaf_warning ("start_watch_dir_change failed" "for repo %s, error code %lu\n", info->status->repo_id, GetLastError()); } } else { /* A previously unwatched dir_handle's DirWatchAux buf was scheduled to be freed. */ DirWatchAux *aux = g_hash_table_lookup (priv->buf_hash, (gconstpointer)hTriggered); if (aux && aux->unused) g_free (aux); g_hash_table_remove (priv->buf_hash, (gconstpointer)hTriggered); } } } return NULL; }