PERFORCE change 127147 for review
Fredrik Lindberg
fli at FreeBSD.org
Wed Oct 3 14:23:29 PDT 2007
http://perforce.freebsd.org/chv.cgi?CH=127147
Change 127147 by fli at fli_nexus on 2007/10/03 21:22:36
- Follow changes to record subsystem.
- Move query rescheduling into a function to remove
duplicated code.
- Better failure handling.
- New debugging asserts.
- Other minor fixes.
Affected files ...
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/queries.c#2 edit
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/queries.h#2 edit
Differences ...
==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/queries.c#2 (text+ko) ====
@@ -35,6 +35,7 @@
#include "output_aggr.h"
#include "threads.h"
#include "queries.h"
+#include "util.h"
static void timeout_enqueue(struct queries *, struct query_cons *);
static void timeout_dequeue(struct queries *, struct query_cons *);
@@ -57,8 +58,11 @@
queries_init(struct queries *q, struct md_if *mif)
{
struct aq_func aqf;
+ int error;
- records_init(&q->q_recs, mdns_c_in);
+ error = records_init(&q->q_recs);
+ if (error != 0)
+ goto queries_init_fail;
MTX_INIT(q, q_mtx, NULL);
TAILQ_INIT(&q->q_to_head);
TAILQ_INIT(&q->q_ret_head);
@@ -77,40 +81,22 @@
MDNS_INIT_SET(q, q_magic);
dprintf(DEBUG_QUERY, "Initialized queries system q=%x mif=%x", q, mif);
return (0);
+queries_init_fail:
+ dprintf(DEBUG_QUERY, "Failed to initialize queries system mif=%x", mif);
+ return (-1);
}
/*
- * Destroy callback, destroys a record and all its types
- */
-static void
-record_del_cb(struct record *r, void *arg)
-{
- struct query_type *qt;
- struct record_type *rt;
- struct query_cons *qc, *qc2;
- struct queries *q;
-
- q = arg;
- record_foreach(rt, r) {
- qt = record_type_getparent(rt);
- ret_dequeue(q, qt);
- TAILQ_FOREACH_SAFE(qc, &qt->qt_cons_list, qc_next, qc2) {
- query_timeout_notify(q, qc);
- }
- }
-}
-
-/*
* Destroy a query system
*/
void
queries_destroy(struct queries *q)
{
-
MDNS_INIT_ASSERT(q, q_magic);
MTX_LOCK(q, q_mtx);
- records_foreach(&q->q_recs, record_del_cb, q);
+
records_destroy(&q->q_recs);
+
MTX_UNLOCK(q, q_mtx);
MTX_DESTROY(q, q_mtx);
MDNS_INIT_UNSET(q, q_magic);
@@ -158,7 +144,6 @@
struct query_cons *qc;
struct query_type *qt;
struct record_type *rt;
- struct record *r;
q = arg.ptr;
MDNS_INIT_ASSERT(q, q_magic);
@@ -174,17 +159,12 @@
qt = qc->qc_qt;
TAILQ_REMOVE(&qt->qt_cons_list, qc, qc_next);
TAILQ_REMOVE(&q->q_to_head, qc, qc_to_next);
+
query_timeout_notify(q, qc);
obj_free(OBJ_QCONS, qc);
rt = &qt->qt_type;
- r = rt->rt_record;
- record_release(r);
- if (record_type_refcnt(rt) == 1) {
- destroy_query_type(q, qt);
- }
- else
- record_type_release(rt);
+ record_type_release(rt);
qc = TAILQ_FIRST(&q->q_to_head);
if (qc == NULL)
@@ -206,6 +186,7 @@
{
struct query_cons *qc2, *qc3;
+ MDNS_INIT_ASSERT(q, q_magic);
qc->qc_torel = qc->qc_timeout;
qc2 = TAILQ_FIRST(&q->q_to_head);
@@ -214,7 +195,7 @@
}
else if (qc->qc_torel < qc2->qc_torel) {
qc2->qc_torel -= qc->qc_torel;
- TAILQ_INSERT_HEAD(&q->q_to_head, qc, qc_next);
+ TAILQ_INSERT_HEAD(&q->q_to_head, qc, qc_to_next);
}
else {
while (qc->qc_torel >= qc2->qc_torel) {
@@ -237,6 +218,7 @@
{
struct query_cons *qc2;
+ MDNS_INIT_ASSERT(q, q_magic);
qc2 = TAILQ_NEXT(qc, qc_to_next);
if (qc2 != NULL)
qc2->qc_torel += qc->qc_torel;
@@ -253,6 +235,8 @@
struct query_type *qt2, *qt3;
struct md_glob *g;
+ MDNS_INIT_ASSERT(q, q_magic);
+
qt->qt_retrel = qt->qt_retabs;
qt2 = TAILQ_FIRST(&q->q_ret_head);
@@ -294,6 +278,8 @@
struct query_type *qt2;
struct md_glob *g;
+ MDNS_INIT_ASSERT(q, q_magic);
+
if (!(qt->qt_flags & QT_INRETQ))
return;
@@ -361,36 +347,44 @@
{
struct mdns_qset *qs;
struct record *r;
+ struct record_class *rc;
struct record_type *rt, *rt2;
int range;
+ MDNS_INIT_ASSERT(q, q_magic);
+
if (qt->qt_flags & QT_SENT)
return;
rt = &qt->qt_type;
- r = rt->rt_record;
+ rc = record_get_class(rt);
+ r = record_get_record(rc);
/*
* Check if a query exists on this record for T_ANY
*/
- record_type_get(r, &rt2, RECORD_NOINIT, mdns_in_any);
+ rt2 = record_type_find(&q->q_recs, REC_OBJCLASS, NULL, (uintptr_t)rc,
+ mdns_t_any);
if (rt2 != NULL) {
- record_type_release(rt2);
if (rt2 != rt)
return;
}
qs = mdns_pkg_getqset();
+ if (qs == NULL)
+ return;
mdns_qset_name_dup(qs, r->r_name);
qs->q_type = rt->rt_type;
- qs->q_class = mdns_c_in; /* XXX */
+ qs->q_class = rc->rc_class;
aq_enqueue(&q->q_aq4, qs, 20, 500);
#ifdef INET6
qs = mdns_pkg_getqset();
+ if (qs == NULL)
+ return;
mdns_qset_name_dup(qs, r->r_name);
qs->q_type = rt->rt_type;
- qs->q_class = mdns_c_in; /* XXX */
+ qs->q_class = rc->rc_class;
aq_enqueue(&q->q_aq6, qs, 20, 500);
#endif
@@ -435,12 +429,9 @@
static void
destroy_query_type(struct queries *q, struct query_type *qt)
{
- struct record_type *rt;
struct query_cons *qc, *qc2;
MDNS_INIT_ASSERT(qt, qt_magic);
- rt = &qt->qt_type;
- assert(record_type_refcnt(rt) == 1);
if (qt->qt_flags & QT_INRETQ)
ret_dequeue(q, qt);
@@ -454,12 +445,27 @@
obj_free(OBJ_QCONS, qc);
}
- record_type_release(rt);
MDNS_INIT_UNSET(qt, qt_magic);
obj_free(OBJ_QTYPE, qt);
}
/*
+ * Callback from record sub-system when the last reference to a
+ * query_type {} is about to be released.
+ */
+static int
+qt_del_cb(void *arg)
+{
+ struct query_type *qt = arg;
+ struct queries *q;
+
+ MDNS_INIT_ASSERT(qt, qt_magic);
+ q = qt->qt_queries;
+ destroy_query_type(q, qt);
+ return (0);
+}
+
+/*
* Aggregation queue callback on packet chain intialization
*/
static void
@@ -486,39 +492,47 @@
/*
* Register a consumer with a query
- * g - Global software state
- * ifidx - Interface index to register query on (-1 equals all interfaces)
+ * q - Queries handle
* qs - qset structure with query information
* func - Callback function, called when a response comes in to the query
* arg - Uniquely identifies the consumer, passed to func()
* timeout - Specifies that timeout in seconds for oneshot queries, if
* zero the query is treated as a continuous query.
+ * family - Address family
*/
int
query_reg(struct queries *q, struct mdns_qset *qs, qc_cb func,
void *arg, int timeout, int family)
{
struct record_type *rt;
- struct record *r;
struct query_type *qt;
struct query_cons *qc, *qc2;
+ int error;
+ struct recpar rp;
MDNS_INIT_ASSERT(q, q_magic);
MTX_LOCK(q, q_mtx);
- record_get(&q->q_recs, &r, 0, qs->q_name);
- if (r == NULL)
- goto out;
- record_type_get(r, &rt, RECORD_NOINIT, qs->q_type);
+ error = record_type_get(&q->q_recs, &rt, REC_NOINIT, NULL, qs->q_name,
+ qs->q_class, qs->q_type);
if (rt == NULL) {
qt = obj_alloc(OBJ_QTYPE);
+ if (qt == NULL)
+ goto query_reg_fail;
bzero(qt, sizeof(struct query_type));
+ qt->qt_queries = q;
MDNS_INIT_SET(qt, qt_magic);
TAILQ_INIT(&qt->qt_cons_list);
rt = &qt->qt_type;
- record_type_get(r, &rt, RECORD_NOALLOC, qs->q_type);
- record_type_setparent(rt, qt);
+ rp.rp_handle = qt;
+ rp.rp_del_cb = qt_del_cb;
+ error = record_type_get(&q->q_recs, &rt, REC_NOALLOC, &rp,
+ qs->q_name, qs->q_class, qs->q_type);
+ if (error != 0) {
+ obj_free(OBJ_QTYPE, qt);
+ goto query_reg_fail;
+ }
}
assert(rt != NULL);
@@ -531,15 +545,15 @@
TAILQ_FOREACH(qc2, &qt->qt_cons_list, qc_next) {
if (qc2->qc_arg != arg)
continue;
- record_type_release(rt);
- record_release(r);
- goto out;
+ goto query_reg_fail2;
}
/* TODO: send data from database record to client */
/* TODO: send data from cache to client */
qc = obj_alloc(OBJ_QCONS);
+ if (qc == NULL)
+ goto query_reg_fail2;
qc->qc_func = func;
qc->qc_arg = arg;
qc->qc_timeout = timeout;
@@ -553,9 +567,15 @@
timeout_enqueue(q, qc);
MTX_UNLOCK(q, q_mtx);
+ dprintf(DEBUG_QUERY, "Registered query q=%p, qt=%p, consumer=%p",
+ q, qt, arg);
return (0);
-out:
+query_reg_fail2:
+ record_type_release(rt);
+query_reg_fail:
MTX_UNLOCK(q, q_mtx);
+ dprintf(DEBUG_QUERY, "Failed to register query q=%p, consumer=%p",
+ q, arg);
return (-1);
}
@@ -565,7 +585,6 @@
int
query_dereg(struct queries *q, struct mdns_qset *qs, void *cons)
{
- struct record *r;
struct record_type *rt;
struct query_cons *qc;
struct query_type *qt;
@@ -573,42 +592,73 @@
MDNS_INIT_ASSERT(q, q_magic);
MTX_LOCK(q, q_mtx);
- record_get(&q->q_recs, &r, RECORD_NOINIT, qs->q_name);
- if (r == NULL)
- goto out1;
+ rt = record_type_find(&q->q_recs, 0, qs->q_name, qs->q_class,
+ qs->q_type);
+ if (rt == NULL)
+ goto query_dereg_fail;
- record_type_get(r, &rt, RECORD_NOINIT, qs->q_type);
- if (rt == NULL)
- goto out2;
-
qt = record_type_getparent(rt);
- TAILQ_FOREACH(qc, &qt->qt_cons_list, qc_next)
+ TAILQ_FOREACH(qc, &qt->qt_cons_list, qc_next) {
if (qc->qc_arg == cons)
break;
+ }
if (qc != NULL) {
if (qc->qc_timeout != 0)
timeout_dequeue(q, qc);
TAILQ_REMOVE(&qt->qt_cons_list, qc, qc_next);
- record_release(r);
record_type_release(rt);
obj_free(OBJ_QCONS, qc);
}
- if (record_type_refcnt(rt) == 1) {
- destroy_query_type(q, qt);
- }
- else
- record_type_release(rt);
-out2:
- record_release(r);
MTX_UNLOCK(q, q_mtx);
+ dprintf(DEBUG_QUERY, "De-registered consumer=%p from queries q=%p",
+ cons, q);
return (0);
-out1:
+query_dereg_fail:
MTX_UNLOCK(q, q_mtx);
+ dprintf(DEBUG_QUERY, "Failed to de-registered consumer=%p "
+ "from queries q=%p", cons, q);
return (-1);
}
+/* Notify consumers */
+static inline void
+notify_cons(struct query_type *qt, struct mdns_rrset *rs, int ifidx, int fam,
+ int trunc)
+{
+ struct query_cons *qc;
+
+ TAILQ_FOREACH(qc, &qt->qt_cons_list, qc_next) {
+ if (qc->qc_fam != AF_UNSPEC && qc->qc_fam != fam)
+ continue;
+ qc->qc_func(qc->qc_arg, rs, ifidx, fam, trunc);
+ }
+}
+
+static inline void
+reschedule_query(struct queries *q, struct query_type *qt, uint32_t ttl)
+{
+ int range;
+
+ range = (random() % 3);
+
+ /* Expired record, re-schedule transmission */
+ if (ttl == 0) {
+ qt->qt_flags &= ~QT_RESP;
+ qt->qt_tries = 0;
+ qt->qt_retabs = 1;
+ }
+ else {
+ qt->qt_flags |= QT_RESP;
+ qt->qt_ttl = ttl;
+ qt->qt_tries = 80; /* next at 80% of ttl */
+ qt->qt_retabs = (qt->qt_ttl * (qt->qt_tries + range)) / 100;
+ }
+ ret_enqueue(q, qt);
+}
+
+
/*
* Notify callback, called to notify potential consumers about
* new resource data.
@@ -621,84 +671,62 @@
query_notify(struct queries *q, struct mdns_rrset *rs, int ifidx, int fam,
int trunc)
{
- struct record *r;
struct record_type *rt;
- struct query_cons *qc;
struct query_type *qt;
- int range, sched = 0;
+ int sched = 0;
MDNS_INIT_ASSERT(q, q_magic);
+
MTX_LOCK(q, q_mtx);
- record_get(&q->q_recs, &r, RECORD_NOINIT, rs->r_name);
- if (r == NULL)
- goto out;
+ /* Clients waiting for C_ANY/T_ANY */
+ rt = record_type_find(&q->q_recs, 0, rs->r_name, mdns_c_any,
+ mdns_t_any);
+ if (rt != NULL) {
+ qt = record_type_getparent(rt);
+ ret_dequeue(q, qt);
+ notify_cons(qt, rs, ifidx, fam, trunc);
+ reschedule_query(q, qt, rs->r_ttl);
+ sched = 1;
+ }
- range = (random() % 3);
-
- /*
- * Check for clients waiting on T_ANY
- */
- record_type_get(r, &rt, RECORD_NOINIT, mdns_in_any);
+ /* Clients waiting for C_ANY */
+ rt = record_type_find(&q->q_recs, 0, rs->r_name, mdns_c_any,
+ rs->r_type);
if (rt != NULL) {
qt = record_type_getparent(rt);
- TAILQ_FOREACH(qc, &qt->qt_cons_list, qc_next) {
- if (qc->qc_fam != AF_UNSPEC && qc->qc_fam != fam)
- continue;
- qc->qc_func(qc->qc_arg, rs, ifidx, fam, trunc);
+ ret_dequeue(q, qt);
+ notify_cons(qt, rs, ifidx, fam, trunc);
+ if (!sched) {
+ reschedule_query(q, qt, rs->r_ttl);
+ sched++;
}
+ }
+ /* Clients waiting for T_ANY */
+ rt = record_type_find(&q->q_recs, 0, rs->r_name, rs->r_class,
+ mdns_t_any);
+ if (rt != NULL) {
+ qt = record_type_getparent(rt);
ret_dequeue(q, qt);
-
- /* Expired record, re-schedule transmission */
- if (rs->r_ttl == 0) {
- qt->qt_flags &= ~QT_RESP;
- qt->qt_tries = 0;
- qt->qt_retabs = 1;
+ notify_cons(qt, rs, ifidx, fam, trunc);
+ if (!sched) {
+ reschedule_query(q, qt, rs->r_ttl);
+ sched++;
}
- else {
- qt->qt_flags |= QT_RESP;
- qt->qt_ttl = rs->r_ttl;
- qt->qt_tries = 80; /* next at 80% of ttl */
- qt->qt_retabs =
- (qt->qt_ttl * (qt->qt_tries + range)) / 100;
- }
- sched = 1;
- ret_enqueue(q, qt);
- record_type_release(rt);
}
- record_type_get(r, &rt, RECORD_NOINIT, rs->r_type);
+ /* Exact match on class, type pair */
+ rt = record_type_find(&q->q_recs, 0, rs->r_name, rs->r_class,
+ rs->r_type);
if (rt != NULL) {
qt = record_type_getparent(rt);
- TAILQ_FOREACH(qc, &qt->qt_cons_list, qc_next) {
- if (qc->qc_fam != AF_UNSPEC && qc->qc_fam != fam)
- continue;
- qc->qc_func(qc->qc_arg, rs, ifidx, fam, trunc);
- }
-
ret_dequeue(q, qt);
- /* Expired record, re-schedule transmission */
- if (rs->r_ttl == 0) {
- qt->qt_flags &= ~QT_RESP;
- qt->qt_tries = 0;
- qt->qt_retabs = 1;
- }
- else {
- qt->qt_flags |= QT_RESP;
- qt->qt_ttl = rs->r_ttl;
- qt->qt_tries = 80; /* next at 80% of ttl */
- qt->qt_retabs =
- (qt->qt_ttl * (qt->qt_tries + range)) / 100;
- }
+ notify_cons(qt, rs, ifidx, fam, trunc);
if (!sched)
- ret_enqueue(q, qt);
-
- record_type_release(rt);
+ reschedule_query(q, qt, rs->r_ttl);
}
- record_release(r);
-out:
MTX_UNLOCK(q, q_mtx);
}
@@ -707,10 +735,8 @@
* any longer.
*/
static void
-query_timeout_notify(struct queries *q, struct query_cons *qc)
+query_timeout_notify(struct queries *q __unused, struct query_cons *qc)
{
- MTX_UNLOCK(q, q_mtx);
qc->qc_func(qc->qc_arg, NULL, 0, 0, 0);
- MTX_LOCK(q, q_mtx);
}
==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/queries.h#2 (text+ko) ====
@@ -75,6 +75,7 @@
MAGIC(qt_magic);
struct record_type qt_type;
TAILQ_HEAD(, query_cons) qt_cons_list; /* consumer list head */
+ struct queries *qt_queries;
int qt_flags;
#define QT_INRETQ 0x01 /* scheduled for re-transmission */
#define QT_SENT 0x02 /* query sent */
@@ -83,7 +84,7 @@
int qt_retrel; /* relative re-transmit value (book keeping only) */
int qt_retabs; /* absolute re-transmission value */
int qt_tries; /* number of re-transmission retries */
- int qt_ttl; /* ttl from response */
+ int qt_ttl; /* ttl from response */
};
int queries_init(struct queries *, struct md_if *);
More information about the p4-projects
mailing list