Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 3 Oct 2007 21:23:28 GMT
From:      Fredrik Lindberg <fli@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 127147 for review
Message-ID:  <200710032123.l93LNS2B096898@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=127147

Change 127147 by fli@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 *);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200710032123.l93LNS2B096898>