pthread_t workers[WORKERS_MAX];
unsigned n_valid_workers;
- unsigned current_id, current_index;
- sd_resolve_query* queries[QUERIES_MAX];
- unsigned n_queries, n_done;
+ unsigned current_id;
+ sd_resolve_query* query_array[QUERIES_MAX];
+ unsigned n_queries, n_done, n_outstanding;
sd_event_source *event_source;
sd_event *event;
sd_resolve **default_resolve_ptr;
pid_t tid;
+
+ LIST_HEAD(sd_resolve_query, queries);
};
struct sd_resolve_query {
QueryType type:4;
bool done:1;
+ bool floating:1;
unsigned id;
int ret;
};
void *userdata;
+
+ LIST_FIELDS(sd_resolve_query, queries);
};
typedef struct RHeader {
static int getnameinfo_done(sd_resolve_query *q);
static int res_query_done(sd_resolve_query* q);
+static void resolve_query_disconnect(sd_resolve_query *q);
+
#define RESOLVE_DONT_DESTROY(resolve) \
_cleanup_resolve_unref_ _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve)
unsigned n;
int r;
- n = resolve->n_queries + extra - resolve->n_done;
+ n = resolve->n_outstanding + extra;
n = CLAMP(n, WORKERS_MIN, WORKERS_MAX);
while (resolve->n_valid_workers < n) {
static void resolve_free(sd_resolve *resolve) {
PROTECT_ERRNO;
+ sd_resolve_query *q;
unsigned i;
assert(resolve);
+ while ((q = resolve->queries)) {
+ assert(q->floating);
+ resolve_query_disconnect(q);
+ sd_resolve_query_unref(q);
+ }
+
if (resolve->default_resolve_ptr)
*(resolve->default_resolve_ptr) = NULL;
assert(resolve);
- q = resolve->queries[id % QUERIES_MAX];
+ q = resolve->query_array[id % QUERIES_MAX];
if (q)
if (q->id == id)
return q;
q->done = true;
resolve->n_done ++;
- resolve->current = q;
+ resolve->current = sd_resolve_query_ref(q);
switch (q->type) {
resolve->current = NULL;
+ if (q->floating) {
+ resolve_query_disconnect(q);
+ sd_resolve_query_unref(q);
+ }
+
+ sd_resolve_query_unref(q);
+
return r;
}
return 0;
}
+ assert(resolve->n_outstanding > 0);
+ resolve->n_outstanding--;
+
q = lookup_query(resolve, resp->id);
if (!q)
return 0;
return sd_resolve_process(resolve);
}
-static int alloc_query(sd_resolve *resolve, sd_resolve_query **_q) {
+static int alloc_query(sd_resolve *resolve, bool floating, sd_resolve_query **_q) {
sd_resolve_query *q;
int r;
if (r < 0)
return r;
- while (resolve->queries[resolve->current_index]) {
- resolve->current_index++;
+ while (resolve->query_array[resolve->current_id % QUERIES_MAX])
resolve->current_id++;
- resolve->current_index %= QUERIES_MAX;
- }
-
- q = resolve->queries[resolve->current_index] = new0(sd_resolve_query, 1);
+ q = resolve->query_array[resolve->current_id % QUERIES_MAX] = new0(sd_resolve_query, 1);
if (!q)
return -ENOMEM;
q->n_ref = 1;
- q->resolve = sd_resolve_ref(resolve);
- q->id = resolve->current_id;
+ q->resolve = resolve;
+ q->floating = floating;
+ q->id = resolve->current_id++;
+
+ if (!floating)
+ sd_resolve_ref(resolve);
+ LIST_PREPEND(queries, resolve->queries, q);
resolve->n_queries++;
*_q = q;
int r;
assert_return(resolve, -EINVAL);
- assert_return(_q, -EINVAL);
assert_return(node || service, -EINVAL);
assert_return(callback, -EINVAL);
assert_return(!resolve_pid_changed(resolve), -ECHILD);
- r = alloc_query(resolve, &q);
+ r = alloc_query(resolve, !_q, &q);
if (r < 0)
return r;
return -errno;
}
- *_q = q;
+ resolve->n_outstanding++;
+
+ if (_q)
+ *_q = q;
+
return 0;
}
int r;
assert_return(resolve, -EINVAL);
- assert_return(_q, -EINVAL);
assert_return(sa, -EINVAL);
assert_return(salen >= sizeof(struct sockaddr), -EINVAL);
assert_return(salen <= sizeof(union sockaddr_union), -EINVAL);
assert_return(callback, -EINVAL);
assert_return(!resolve_pid_changed(resolve), -ECHILD);
- r = alloc_query(resolve, &q);
+ r = alloc_query(resolve, !_q, &q);
if (r < 0)
return r;
return -errno;
}
- *_q = q;
+ resolve->n_outstanding++;
+
+ if (_q)
+ *_q = q;
+
return 0;
}
int r;
assert_return(resolve, -EINVAL);
- assert_return(_q, -EINVAL);
assert_return(dname, -EINVAL);
assert_return(callback, -EINVAL);
assert_return(!resolve_pid_changed(resolve), -ECHILD);
- r = alloc_query(resolve, &q);
+ r = alloc_query(resolve, !_q, &q);
if (r < 0)
return r;
return -errno;
}
- *_q = q;
+ resolve->n_outstanding++;
+
+ if (_q)
+ *_q = q;
+
return 0;
}
}
}
-static void resolve_query_free(sd_resolve_query *q) {
+static void resolve_query_disconnect(sd_resolve_query *q) {
+ sd_resolve *resolve;
unsigned i;
assert(q);
- assert(q->resolve);
- assert(q->resolve->n_queries > 0);
+
+ if (!q->resolve)
+ return;
+
+ resolve = q->resolve;
+ assert(resolve->n_queries > 0);
if (q->done) {
- assert(q->resolve->n_done > 0);
- q->resolve->n_done--;
+ assert(resolve->n_done > 0);
+ resolve->n_done--;
}
i = q->id % QUERIES_MAX;
- assert(q->resolve->queries[i] == q);
- q->resolve->queries[i] = NULL;
- q->resolve->n_queries--;
- sd_resolve_unref(q->resolve);
+ assert(resolve->query_array[i] == q);
+ resolve->query_array[i] = NULL;
+ LIST_REMOVE(queries, resolve->queries, q);
+ resolve->n_queries--;
+
+ q->resolve = NULL;
+ if (!q->floating)
+ sd_resolve_unref(resolve);
+}
+
+static void resolve_query_free(sd_resolve_query *q) {
+ assert(q);
+
+ resolve_query_disconnect(q);
resolve_freeaddrinfo(q->addrinfo);
free(q->host);