Beispiel #1
0
static bool inot_root_consume_notify(watchman_global_watcher_t watcher,
    w_root_t *root, struct watchman_pending_collection *coll)
{
  struct inot_root_state *state = root->watch;
  struct inotify_event *ine;
  char *iptr;
  int n;
  struct timeval now;
  unused_parameter(watcher);

  n = read(state->infd, &state->ibuf, sizeof(state->ibuf));
  if (n == -1) {
    if (errno == EINTR) {
      return false;
    }
    w_log(W_LOG_FATAL, "read(%d, %zu): error %s\n",
        state->infd, sizeof(state->ibuf), strerror(errno));
  }

  w_log(W_LOG_DBG, "inotify read: returned %d.\n", n);
  gettimeofday(&now, NULL);

  for (iptr = state->ibuf; iptr < state->ibuf + n;
      iptr = iptr + sizeof(*ine) + ine->len) {
    ine = (struct inotify_event*)iptr;

    process_inotify_event(root, coll, ine, now);

    if (root->cancelled) {
      return false;
    }
  }

  // It is possible that we can accumulate a set of pending_move
  // structs in move_map.  This happens when a directory is moved
  // outside of the watched tree; we get the MOVE_FROM but never
  // get the MOVE_TO with the same cookie.  To avoid leaking these,
  // we'll age out the move_map after processing a full set of
  // inotify events.   We age out rather than delete all because
  // the MOVE_TO may yet be waiting to read in another go around.
  // We allow a somewhat arbitrary but practical grace period to
  // observe the corresponding MOVE_TO.
  if (w_ht_size(state->move_map) > 0) {
    w_ht_iter_t iter;
    if (w_ht_first(state->move_map, &iter)) do {
      struct pending_move *pending = w_ht_val_ptr(iter.value);
      if (now.tv_sec - pending->created > 5 /* seconds */) {
        w_log(W_LOG_DBG,
            "deleting pending move %s (moved outside of watch?)\n",
            pending->name->buf);
        w_ht_iter_del(state->move_map, &iter);
      }
    } while (w_ht_next(state->move_map, &iter));
  }

  return true;
}
Beispiel #2
0
void w_cancel_subscriptions_for_root(w_root_t *root) {
  w_ht_iter_t iter;
  pthread_mutex_lock(&w_client_lock);
  if (w_ht_first(clients, &iter)) {
    do {
      struct watchman_user_client *client = w_ht_val_ptr(iter.value);
      w_ht_iter_t citer;

      if (w_ht_first(client->subscriptions, &citer)) {
        do {
          struct watchman_client_subscription *sub = w_ht_val_ptr(citer.value);

          if (sub->root == root) {
            json_t *response = make_response();

            w_log(W_LOG_ERR,
                  "Cancel subscription %.*s for client:stm=%p due to "
                  "root cancellation\n",
                  sub->name->len, sub->name->buf, client->client.stm);

            set_prop(response, "root", w_string_to_json(root->root_path));
            set_prop(response, "subscription", w_string_to_json(sub->name));
            set_prop(response, "unilateral", json_true());
            set_prop(response, "canceled", json_true());

            if (!enqueue_response(&client->client, response, true)) {
              w_log(W_LOG_DBG, "failed to queue sub cancellation\n");
              json_decref(response);
            }

            w_ht_iter_del(client->subscriptions, &citer);
          }
        } while (w_ht_next(client->subscriptions, &citer));
      }
    } while (w_ht_next(clients, &iter));
  }
  pthread_mutex_unlock(&w_client_lock);
}