progs/pixie.c: Rewrite list hacking to avoid strict-aliasing badness.
authorMark Wooding <mdw@distorted.org.uk>
Wed, 19 Jun 2013 00:43:57 +0000 (01:43 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Fri, 28 Jun 2013 23:30:17 +0000 (00:30 +0100)
The circular list stuff was quite pretty but involved some really
unpleasant casting which modern GCC (quite properly) complains about
vociferously.

Replace it with more traditional doubly-linked-list hacking with
null-pointer sentinels, with the slightly nasty pointer swizzling tucked
away in useful macros.  Some of the uses of these macros (e.g.,
unlinking the first or last item in a list) could be made more efficient
by using special-case versions, but it doesn't seem worthwhile.

progs/pixie.c

index 1198fcb..667a588 100644 (file)
@@ -125,8 +125,7 @@ static void pxlog(const char *p, ...)
 /* --- Data structures --- */
 
 typedef struct phrase {
 /* --- Data structures --- */
 
 typedef struct phrase {
-  struct phrase *next;
-  struct phrase *prev;
+  struct phrase *next, *prev;
   char *tag;
   char *p;
   unsigned long t;
   char *tag;
   char *p;
   unsigned long t;
@@ -136,8 +135,21 @@ typedef struct phrase {
 
 /* --- Variables --- */
 
 
 /* --- Variables --- */
 
-#define P_ROOT ((phrase *)&p_root)
-static struct { phrase *next; phrase *prev; } p_root = { P_ROOT, P_ROOT };
+static phrase *p_head = 0, *p_tail = 0;
+
+/* --- Utility macros --- */
+
+#define P_LINKTAIL(p) do {                                             \
+  (p)->next = 0;                                                       \
+  (p)->prev = p_tail;                                                  \
+  *(p_tail ? &p_tail->next : &p_head) = (p);                           \
+  p_tail = (p);                                                                \
+} while (0)
+
+#define P_UNLINK(p) do {                                               \
+  *((p)->next ? &(p)->next->prev : &p_tail) = (p)->prev;               \
+  *((p)->prev ? &(p)->prev->next : &p_head) = (p)->next;               \
+} while (0)
 
 /* --- @p_free@ --- *
  *
 
 /* --- @p_free@ --- *
  *
@@ -154,8 +166,7 @@ static void p_free(phrase *p)
     sel_rmtimer(&p->timer);
   xfree(p->tag);
   l_free(&lm, p->p);
     sel_rmtimer(&p->timer);
   xfree(p->tag);
   l_free(&lm, p->p);
-  p->next->prev = p->prev;
-  p->prev->next = p->next;
+  P_UNLINK(p);
   DESTROY(p);
 }
 
   DESTROY(p);
 }
 
@@ -193,13 +204,13 @@ static void *p_alloc(size_t sz)
     char *p;
     if ((p = l_alloc(&lm, sz)) != 0)
       return (p);
     char *p;
     if ((p = l_alloc(&lm, sz)) != 0)
       return (p);
-    if (P_ROOT->next == P_ROOT)
+    if (!p_head)
       return (0);
     if (verbose) {
       pxlog("flushing passphrase `%s' to free up needed space",
            p_head->tag);
     }
       return (0);
     if (verbose) {
       pxlog("flushing passphrase `%s' to free up needed space",
            p_head->tag);
     }
-    p_free(P_ROOT->next);
+    p_free(p_head);
   }
 }
 
   }
 }
 
@@ -216,7 +227,7 @@ static phrase *p_find(const char *tag)
 {
   phrase *p;
 
 {
   phrase *p;
 
-  for (p = P_ROOT->next; p != P_ROOT; p = p->next) {
+  for (p = p_head; p; p = p->next) {
     if (strcmp(p->tag, tag) == 0) {
       if (p->t) {
        struct timeval tv;
     if (strcmp(p->tag, tag) == 0) {
       if (p->t) {
        struct timeval tv;
@@ -225,12 +236,8 @@ static phrase *p_find(const char *tag)
        tv.tv_sec += p->t;
        sel_addtimer(&sel, &p->timer, &tv, p_timer, p);
       }
        tv.tv_sec += p->t;
        sel_addtimer(&sel, &p->timer, &tv, p_timer, p);
       }
-      p->next->prev = p->prev;
-      p->prev->next = p->next;
-      p->next = P_ROOT;
-      p->prev = P_ROOT->prev;
-      P_ROOT->prev->next = p;
-      P_ROOT->prev = p;
+      P_UNLINK(p);
+      P_LINKTAIL(p);
       return (p);
     }
   }
       return (p);
     }
   }
@@ -279,10 +286,7 @@ static phrase *p_add(const char *tag, const char *p, unsigned long t)
 
   /* --- Link the block into the chain --- */
 
 
   /* --- Link the block into the chain --- */
 
-  pp->next = P_ROOT;
-  pp->prev = P_ROOT->prev;
-  P_ROOT->prev->next = pp;
-  P_ROOT->prev = pp;
+  P_LINKTAIL(pp);
   return (pp);
 }
 
   return (pp);
 }
 
@@ -301,8 +305,8 @@ static void p_flush(const char *tag)
 
   if (!tag && verbose > 1)
     pxlog("flushing all passphrases");
 
   if (!tag && verbose > 1)
     pxlog("flushing all passphrases");
-  p = P_ROOT->next;
-  while (p != P_ROOT) {
+  p = p_head;
+  while (p) {
     phrase *pp = p->next;
     if (!tag)
       p_free(p);
     phrase *pp = p->next;
     if (!tag)
       p_free(p);
@@ -695,7 +699,7 @@ OK\n\
   else if (strcmp(q, "list") == 0) {
     phrase *p;
 
   else if (strcmp(q, "list") == 0) {
     phrase *p;
 
-    for (p = P_ROOT->next; p != P_ROOT; p = p->next) {
+    for (p = p_head; p; p = p->next) {
       if (!p->t)
        pixserv_write(px, "ITEM %s no-expire\n", p->tag);
       else {
       if (!p->t)
        pixserv_write(px, "ITEM %s no-expire\n", p->tag);
       else {