Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 20 Jun 2007 10:52:19 GMT
From:      Fredrik Lindberg <fli@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 122024 for review
Message-ID:  <200706201052.l5KAqJTu006661@repoman.freebsd.org>

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

Change 122024 by fli@fli_genesis on 2007/06/20 10:52:02

	- Do reference counting on records and record types so they can
	  be released when no longer needed.
	- Make record_type_*() functions non-static.
	- Add a function to manipulate the name of a record in-place.
	- Add a function to manipulate resource data in-place.
	- Add functions to traverse records, record types and resources.
	- Reverse the logic of the memory allocation flag.
	- Add macros to set the parent (owner).
	- Add a NOINIT flag, allows *_get() to be used as search functions.
	- Follow hash table changes.
	- Add debugging printouts. 

Affected files ...

.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/record.c#2 edit
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/record.h#2 edit

Differences ...

==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/record.c#2 (text+ko) ====

@@ -29,10 +29,10 @@
 #include <string.h>
 
 #include "record.h"
+#include "log.h"
 
-static int record_type_get(struct record *, struct record_type **,
-    int, uint16_t);
-static void record_type_release(struct record_type *);
+#define record_aquire(r) (r)->r_refcnt++;
+#define record_type_aquire(rt) (rt)->rt_refcnt++;
 
 /*
  * Initialize a record set for `class'
@@ -47,7 +47,8 @@
 }
 
 static void
-rec_free(struct hashtbl *ht, void *key, size_t keylen, void *data)
+rec_free(__unused struct hashtbl *ht, __unused const void *key,
+    __unused size_t keylen, void *data, __unused void *arg)
 {
 	struct record *r = (struct record *)data;
 	struct record_type *rt, *rt2;
@@ -73,7 +74,7 @@
 records_destroy(struct records *recs)
 {
 
-	hashtbl_walk(&recs->r_recs, rec_free);
+	hashtbl_walk(&recs->r_recs, rec_free, NULL);
 	hashtbl_destroy(&recs->r_recs);
 	MDNS_INIT_UNSET(recs, r_magic);
 }
@@ -83,10 +84,10 @@
  *  recs - Record set
  *  r    - Pointer to record
  *  name - Resource name
- *  flags - RECORD_ALLOC will cause it to allocate memory if needed
+ *  flags - RECORD_NOALLOC will supress memory allocation 
  */
 int
-record_get(struct records *recs, struct record **r, char *name, int flags)
+record_get(struct records *recs, struct record **r, int flags, char *name)
 {
 	size_t len;
 	struct record *rec;
@@ -95,8 +96,19 @@
 
 	len = strlen(name);
 	rec = hashtbl_find(&recs->r_recs, name, len);
+
+	if (rec == NULL && (flags & RECORD_NOINIT)) {
+		*r = NULL;
+		return (0);
+	}
+
+	if (len > MDNS_RECORD_LEN) {
+		*r = NULL;
+		return (-1);
+	}
+
 	if (rec == NULL) {
-		if (flags & RECORD_ALLOC)
+		if (!(flags & RECORD_NOALLOC))
 			*r = malloc(sizeof(struct record));
 		MDNS_INIT_SET((*r), r_magic);
 		(*r)->r_recs = recs;
@@ -110,7 +122,8 @@
 	else {
 		*r = rec;
 	}
-	(*r)->r_refcnt++;
+	record_aquire(*r);
+	dprintf(DEBUG_REC, "Record aquired r=%x, refcnt=%d", *r, (*r)->r_refcnt);
 	return (0);
 }
 
@@ -129,23 +142,66 @@
 	recs = r->r_recs;
 	MDNS_INIT_ASSERT(recs, r_magic);
 
-	if (TAILQ_EMPTY(&r->r_list)) {
+	if (--r->r_refcnt == 0) {
+		assert(TAILQ_EMPTY(&r->r_list) == 1);
 		len = strlen(r->r_name);
 		hashtbl_del(&recs->r_recs, r->r_name, len);
 		MDNS_INIT_UNSET(r, r_magic);
-		if (r->r_flags & RECORD_ALLOC)
+		if (!(r->r_flags & RECORD_NOALLOC))
 			free(r);
+		dprintf(DEBUG_REC, "References cleared on r=%x, removed", r);
 	}
+	else {
+		dprintf(DEBUG_REC, "Record released r=%x, refs=%d", r, r->r_refcnt);
+	}
 }
 
 /*
+ * Modify the name of a record in-place without releasing
+ * types and resources.
+ */
+void
+record_setname(struct record *r, char *name)
+{
+	struct records *recs;
+	size_t len;
+
+	MDNS_INIT_ASSERT(r, r_magic);
+	recs = r->r_recs;
+	MDNS_INIT_ASSERT(recs, r_magic);
+
+	len = strlen(r->r_name);
+	hashtbl_del(&recs->r_recs, r->r_name, len);
+	len = strlen(name);
+	memcpy(r->r_name, name, len+1);
+	hashtbl_add(&recs->r_recs, r->r_name, len, r, 0);
+	dprintf(DEBUG_REC, "Record name set to %s on r=%x", r->r_name, r);
+}
+
+/*
+ * Lookup if a record exists
+ */
+struct record *
+record_find(struct records *recs, char *name)
+{
+	struct record *r;
+	size_t len;
+
+	MDNS_INIT_ASSERT(recs, r_magic);
+
+	len = strlen(name);
+	r = hashtbl_find(&recs->r_recs, name, len);
+	return (r);
+}
+
+/*
  * Get a record type for a record, will be intialized if needed
  *  r  - Record
  *  rt - Pointer to the new record type
- *  flags - RECORD_ALLOC will cause it to allocated memory if needed
+ *  flags - RECORD_NOALLOC will supress memory allocation 
  *  type - DNS type
  */
-static int
+int
 record_type_get(struct record *r, struct record_type **rt, int flags,
     uint16_t type)
 {
@@ -157,9 +213,13 @@
 		if (type == rt2->rt_type)
 			break;
 	}
+	if (rt2 == NULL && (flags & RECORD_NOINIT)) {
+		*rt = NULL;
+		return (0);
+	}
 
 	if (rt2 == NULL) {
-		if (flags & RECORD_ALLOC)
+		if (!(flags & RECORD_NOALLOC))
 			*rt = malloc(sizeof(struct record_type));
 		MDNS_INIT_SET((*rt), rt_magic);
 		(*rt)->rt_parent = NULL;
@@ -167,6 +227,7 @@
 		(*rt)->rt_flags = flags;
 		(*rt)->rt_record = r;
 		(*rt)->rt_refcnt = 0;
+		record_aquire(r);
 		TAILQ_INIT(&((*rt)->rt_list));
 		TAILQ_FOREACH(rt2, &r->r_list, rt_next) {
 			if (type > rt2->rt_type)
@@ -180,7 +241,9 @@
 	else {
 		*rt = rt2;
 	}
-	(*rt)->rt_refcnt++;
+	record_type_aquire(*rt);
+	dprintf(DEBUG_REC, "Record type aquired rt=%x, refcnt=%d", *rt,
+	    (*rt)->rt_refcnt);
 	return (0);
 }
 
@@ -189,7 +252,7 @@
  * was the last reference.
  *  rt - Record type to release
  */
-static void
+void
 record_type_release(struct record_type *rt)
 {
 	struct record *r;
@@ -199,13 +262,17 @@
 		r = rt->rt_record;
 		TAILQ_REMOVE(&r->r_list, rt, rt_next);
 		MDNS_INIT_UNSET(rt, rt_magic);
-		if (rt->rt_flags & RECORD_ALLOC)
+		if (!(rt->rt_flags & RECORD_NOALLOC))
 			free(rt);
+		dprintf(DEBUG_REC, "References cleared on rt=%x, removed", rt);
 		record_release(r);
 	}
+	else {
+		dprintf(DEBUG_REC, "Record type released rt=%x, refcnt=%d",
+		    rt, rt->rt_refcnt);
+	}
 }
 
-
 /*
  * Add a resource record to a resource type
  *  r - Parent record
@@ -223,17 +290,17 @@
 
 	MDNS_INIT_ASSERT(r, r_magic);
 
-	record_type_get(r, &rt, RECORD_ALLOC, type);
-	if (flags & RECORD_ALLOC)
+	record_type_get(r, &rt, 0, type);
+	if (!(flags & RECORD_NOALLOC))
 		*rr = malloc(sizeof(struct record_res));
 	MDNS_INIT_SET((*rr), rr_magic);
 	(*rr)->rr_parent = NULL;
 	(*rr)->rr_flags = flags;
-	(*rr)->rr_data = data;
+	(*rr)->rr_data = data; /* FIXME: assumption, new flag */
 	(*rr)->rr_len = dlen;
 	(*rr)->rr_type = rt;
 	TAILQ_INSERT_TAIL(&rt->rt_list, *rr, rr_next);
-
+	dprintf(DEBUG_REC, "Resource rr=%x added on r=%x, rt=%x", *rr, r, rt);
 	return (0);
 }
 
@@ -252,13 +319,27 @@
 	MDNS_INIT_ASSERT(rt, rt_magic);
 	flags = rr->rr_flags;
 	TAILQ_REMOVE(&rt->rt_list, rr, rr_next);
-	free(rr->rr_data); /* XXX asumption */
+	free(rr->rr_data); /* FIXME assumption */
 	record_type_release(rt);
 	MDNS_INIT_UNSET(rr, rr_magic);
-	if (flags & RECORD_ALLOC)
+	if (!(flags & RECORD_NOALLOC))
 		free(rr);
+	dprintf(DEBUG_REC, "Resource rr=%x removed, rt=%x", rr, rt);
+}
+
+void
+record_res_setdata(struct record_res *rr, void *data, size_t dlen)
+{
+
+	MDNS_INIT_ASSERT(rr, rr_magic);
+	free(rr->rr_data); /* FIXME: assumption */
+	rr->rr_data = data;
+	rr->rr_len = dlen;
+	dprintf(DEBUG_REC, "Resource data set on rr=%x, data=%x, dlen=%d",
+	    rr, data, dlen);
 }
 
+
 /*
  * Returns a pointer to the first resource record identified by (name, type)
  *  recs - Record set
@@ -290,3 +371,67 @@
 	rr = TAILQ_FIRST(&rt->rt_list);
 	return (rr);
 }
+
+static void
+rec_walk(__unused struct hashtbl *ht, __unused const void *key,
+    __unused size_t keylen, void *data, void *arg)
+{
+	void **args = (void **)arg;
+	record_foreach cb = args[0];
+	void *cbarg = args[1];
+	struct record *r = data;
+
+	cb(r, cbarg);
+}
+
+void
+records_foreach(struct records *recs, record_foreach cb, void *arg)
+{
+	void *args[]= {cb, arg};
+
+	MDNS_INIT_ASSERT(recs, r_magic);
+	hashtbl_walk(&recs->r_recs, rec_walk, (void *)args);
+}
+
+void
+record_foreach_type(struct record *r, record_type_foreach cb, void *arg)
+{
+	struct record_type *rt, *rt2;
+
+	MDNS_INIT_ASSERT(r, r_magic);
+	TAILQ_FOREACH_SAFE(rt, &r->r_list, rt_next, rt2) {
+		MDNS_INIT_ASSERT(rt, rt_magic);
+		cb(rt, arg);
+	}
+}
+
+void
+record_type_foreach_res(struct record_type *rt, record_res_foreach cb,
+    void *arg)
+{
+	struct record_res *rr, *rr_tmp;
+	struct record_res *rr_head, *rr_next, *rr_prev;
+
+	MDNS_INIT_ASSERT(rt, rt_magic);
+
+	rr = rr_head = TAILQ_FIRST(&rt->rt_list);
+	while (rr != NULL) {
+		MDNS_INIT_ASSERT(rr, rr_magic);
+		rr_next = TAILQ_NEXT(rr, rr_next);
+		rr_prev = TAILQ_PREV(rr, record_res_head, rr_next);
+
+		cb(rr, arg);
+
+		if (rr_head != TAILQ_FIRST(&rt->rt_list)) {
+			rr = rr_head = TAILQ_FIRST(&rt->rt_list);
+		}
+		else {
+			rr_tmp = TAILQ_NEXT(TAILQ_NEXT(rr_prev, rr_next), rr_next);
+			if (rr_tmp != NULL && rr_tmp != rr_next)
+				rr = rr_tmp;
+			else
+				rr = rr_next;
+		}
+	}
+
+}

==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/record.h#2 (text+ko) ====

@@ -74,7 +74,7 @@
 	int rt_type;
 	int rt_flags;
 	size_t rt_refcnt;
-	TAILQ_HEAD(, record_res) rt_list;
+	TAILQ_HEAD(record_res_head, record_res) rt_list;
 };
 
 /*
@@ -92,19 +92,44 @@
 	char r_name[MDNS_RECORD_LEN];
 };
 
-#define RECORD_ALLOC 0x01
+/*
+ * Flags used with record_* functions
+ */
+#define RECORD_NOINIT	0x01	/* Do not initialize, assumes valid ptr */
+#define RECORD_NOALLOC	0x02	/* Do not allocate memory */
 
 void records_init(struct records *, int);
 void records_destroy(struct records *);
-int record_get(struct records *, struct record **, char *, int);
+void record_setname(struct record *, char *);
+int record_get(struct records *, struct record **, int, char *);
 void record_release(struct record *);
+struct record * record_find(struct records *, char *);
+
+int record_type_get(struct record *, struct record_type **, int, uint16_t);
+void record_type_release(struct record_type *);
+
 int record_res_add(struct record *, struct record_res **, int, uint16_t,
     void *, size_t);
 void record_res_del(struct record_res *);
 struct record_res * record_res_find(struct records *, char *, uint16_t);
+void record_res_setdata(struct record_res *, void *, size_t);
 
-#define record_setparent(x, y) (x)->r_parent = y
-#define record_res_setparent(x, y) (x)->rr_parent = y
-#define record_res_getparent(x) (x)->rr_parent
+typedef void (*record_foreach)(struct record *, void *);
+typedef void (*record_type_foreach)(struct record_type *, void *);
+typedef void (*record_res_foreach)(struct record_res *, void *);
+
+void records_foreach(struct records *, record_foreach, void *);
+void record_foreach_type(struct record *, record_type_foreach, void *);
+void record_type_foreach_res(struct record_type *, record_res_foreach, void *);
+
+#define __getparent(x, f) (x)->f
+#define record_setparent(x, y) __getparent(x, r_parent) = y
+#define record_getparent(x) __getparent(x, r_parent)
+#define record_refcnt(x) (x)->r_refcnt
+#define record_type_setparent(x, y) __getparent(x, rt_parent) = y
+#define record_type_getparent(x) __getparent(x, rt_parent)
+#define record_type_refcnt(x) (x)->rt_refcnt
+#define record_res_setparent(x, y) __getparent(x, rr_parent) = y
+#define record_res_getparent(x) __getparent(x, rr_parent)
 
 #endif /* _RECORD_H_ */



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