[quagga-dev 3108] Re: list loop cleanup/audit

Paul Jakma paul at clubi.ie
Tue Apr 5 13:47:12 BST 2005


On Tue, 5 Apr 2005, Paul Jakma wrote:

> The ever popular list loop cleanup.
>
> Attached is the linklist.h and ChangeLog diff.

Arg, actually attached this time.

regards,
-- 
Paul Jakma	paul at clubi.ie	paul at jakma.org	Key ID: 64A2FF6A
Fortune:
"His eyes were cold.  As cold as the bitter winter snow that was falling
outside.  Yes, cold and therefore difficult to chew..."
-------------- next part --------------
Index: lib/ChangeLog
===================================================================
RCS file: /var/cvsroot/quagga/lib/ChangeLog,v
retrieving revision 1.159
diff -u -r1.159 ChangeLog
--- lib/ChangeLog	5 Apr 2005 00:45:23 -0000	1.159
+++ lib/ChangeLog	5 Apr 2005 10:47:06 -0000
@@ -1,3 +1,24 @@
+2005-04-05 Paul Jakma <paul.jakma at sun.com>
+
+	* linklist.h: Add usage comments.	  
+	  Rename getdata macro to listgetdata.
+	  Rename nextnode to listnextnode and fix its odd behaviour to be
+	  less dangerous.
+	  Make listgetdata macro assert node is not null, NULL list entries
+          should be bug condition.
+          ALL_LIST_ELEMENTS, new macro, forward-referencing macro for use
+          with for loop, Suggested by Jim Carlson of Sun.
+          Add ALL_LIST_ELEMENTS_RO for cases which obviously do not need the
+          "safety" of previous macro.
+	  LISTNODE_ADD and DELETE macros renamed to ATTACH, DETACH, to
+	  distinguish from the similarly named functions, and reflect their
+	  effect better.
+	  Add a QUAGGA_DEPRECATED define guarded section with the old
+	  defines which were modified above, for backwards compatibility.
+	* linklist.c: fix up for linklist.h changes.
+	* *.c: fix up for new list loop macro, try audit other loop
+          usage at same time, to some degree.
+
 2004-04-05 Paul Jakma <paul at dishone.st>
 
 	* vty.c: Improve logging of failures to open vty socket(s).
Index: lib/linklist.h
===================================================================
RCS file: /var/cvsroot/quagga/lib/linklist.h,v
retrieving revision 1.5
diff -u -r1.5 linklist.h
--- lib/linklist.h	23 Sep 2004 19:18:23 -0000	1.5
+++ lib/linklist.h	5 Apr 2005 10:47:06 -0000
@@ -22,10 +22,15 @@
 #ifndef _ZEBRA_LINKLIST_H
 #define _ZEBRA_LINKLIST_H
 
+/* listnodes must always contain data to be valid. Adding an empty node
+ * to a list is invalid
+ */
 struct listnode 
 {
   struct listnode *next;
   struct listnode *prev;
+  
+  /* private member, use getdata() to retrieve, do not access directly */
   void *data;
 };
 
@@ -33,25 +38,31 @@
 {
   struct listnode *head;
   struct listnode *tail;
+
   /* invariant: count is the number of listnodes in the list */
   unsigned int count;
+
   /*
    * Returns -1 if val1 < val2, 0 if equal?, 1 if val1 > val2.
    * Used as definition of sorted for listnode_add_sort
    */
   int (*cmp) (void *val1, void *val2);
+
+  /* callback to free user-owned data when listnode is deleted. supplying
+   * this callback is very much encouraged!
+   */
   void (*del) (void *val);
 };
 
-#define nextnode(X) ((X) = (X)->next)
+#define listnextnode(X) ((X)->next)
 #define listhead(X) ((X)->head)
 #define listtail(X) ((X)->tail)
 #define listcount(X) ((X)->count)
 #define list_isempty(X) ((X)->head == NULL && (X)->tail == NULL)
-#define getdata(X) ((X)->data)
+#define listgetdata(X) (assert((X)->data != NULL), (X)->data)
 
 /* Prototypes. */
-struct list *list_new();
+struct list *list_new(); /* encouraged: set list.del callback on new lists */
 void list_free (struct list *);
 
 void listnode_add (struct list *, void *);
@@ -72,13 +83,33 @@
 void list_add_node_next (struct list *, struct listnode *, void *);
 void list_add_list (struct list *, struct list *);
 
-/* List iteration macro. */
-#define LIST_LOOP(L,V,N) \
-  for ((N) = (L)->head; (N); (N) = (N)->next) \
-    if (((V) = (N)->data) != NULL)
-
-/* List node add macro.  */
-#define LISTNODE_ADD(L,N) \
+/* List iteration macro. 
+ * Usage: for (ALL_LIST_ELEMENTS (...) { ... }
+ * It is safe to delete the listnode using this macro.
+ */
+#define ALL_LIST_ELEMENTS(list,node,nextnode,data) \
+  (node) = listhead(list); \
+  (node) != NULL && \
+    ((data) = listgetdata(node),(nextnode) = listnextnode(node), 1); \
+  (node) = (nextnode)
+
+/* read-only list iteration macro.
+ * Usage: as per ALL_LIST_ELEMENTS, but not safe to delete the listnode Only
+ * use this macro when it is *immediately obvious* the listnode is not
+ * deleted in the body of the loop. Does not have forward-reference overhead
+ * of previous macro.
+ */
+#define ALL_LIST_ELEMENTS_RO(list,node,data) \
+  (node) = listhead(list); \
+  (node) != NULL && ((data) = listgetdata(node), 1); \
+  (node) = listnextnode(node)
+
+/* these *do not* cleanup list nodes and referenced data, as the functions
+ * do - these macros simply {de,at}tach a listnode from/to a list.
+ */
+ 
+/* List node attach macro.  */
+#define LISTNODE_ATTACH(L,N) \
   do { \
     (N)->prev = (L)->tail; \
     if ((L)->head == NULL) \
@@ -89,8 +120,8 @@
     (L)->count++; \
   } while (0)
 
-/* List node delete macro.  */
-#define LISTNODE_DELETE(L,N) \
+/* List node detach macro.  */
+#define LISTNODE_DETACH(L,N) \
   do { \
     if ((N)->prev) \
       (N)->prev->next = (N)->next; \
@@ -102,5 +133,16 @@
       (L)->tail = (N)->prev; \
     (L)->count--; \
   } while (0)
+
+/* Deprecated */
+#if defined(QUAGGA_DEPRECATED) && (QUAGGA_DEPRECATED >= 20050405)
+#warning "Using deprecated libzebra functions."
+#define LISTNODE_ADD(L,N) LISTNODE_ATTACH(L,N)
+#define LISTNODE_DELETE(L,N) LISTNODE_DETACH(L,N)
+#define nextnode(X) ((X) = (X)->next)
+#define getdata(X) listgetdata(X)
+#define LIST_LOOP(L,V,N) \
+  for (ALL_LIST_ELEMENTS_RO (L,N,V))
+#endif /* QUAGGA_DEPRECATED */
 
 #endif /* _ZEBRA_LINKLIST_H */


More information about the Quagga-dev mailing list