sel/bres.c: Rewrite list hacking to avoid strict-aliasing badness.
authorMark Wooding <mdw@distorted.org.uk>
Wed, 19 Jun 2013 00:35:21 +0000 (01:35 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Fri, 28 Jun 2013 22:24:18 +0000 (23:24 +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.

sel/bres.c

index 3a308b3..2885d0e 100644 (file)
 
 static bres_server servers[BRES_MAX];  /* Statically allocated servers */
 
-#define FREE ((bres_server *)&freelist)
-static struct { bres_server *next, *prev; } freelist = { FREE, FREE };
+static bres_server *freelist, *freetail;
+static bres_client *qhead, *qtail;
+static sel_state *sel;
+static const char *server = 0;
 
-#define QUEUE ((bres_client *)&queue)
-static struct { bres_client *next, *prev; } queue = { QUEUE, QUEUE };
+#define UNLINK(head, tail, p) do {                                     \
+  *((p)->next ? &(p)->next->prev : &(tail)) = (p)->prev;               \
+  *((p)->prev ? &(p)->prev->next : &(head)) = (p)->next;               \
+} while (0)
 
-static sel_state *sel;
+#define LINKHEAD(head, tail, p) do {                                   \
+  (p)->next = (head);                                                  \
+  (p)->prev = 0;                                                       \
+  *((head) ? &(head)->prev : &(tail)) = (p);                           \
+  (head) = (p);                                                                \
+} while (0)
 
-static const char *server = 0;
+#define LINKTAIL(head, tail, p) do {                                   \
+  (p)->next = 0;                                                       \
+  (p)->prev = (head);                                                  \
+  *((tail) ? &(tail)->next : &(head)) = (p);                           \
+  (tail) = (p);                                                                \
+} while (0)
 
 #endif
 
@@ -577,12 +591,8 @@ static void zap(bres_server *rs)
 
   /* --- Move the server to the back of the list --- */
 
-  rs->next->prev = rs->prev;
-  rs->prev->next = rs->next;
-  rs->next = FREE;
-  rs->prev = FREE->prev;
-  FREE->prev->next = rs;
-  FREE->prev = rs;
+  UNLINK(freelist, freetail, rs);
+  LINKTAIL(freelist, freetail, rs);
 }
 
 /* --- @bres_abort@ --- *
@@ -598,13 +608,12 @@ void bres_abort(bres_client *rc)
 {
   if (rc->q == BRES_BYNAME)
     xfree(rc->u.name);
-  if (rc->rs) {
+  if (!rc->rs)
+    UNLINK(qhead, qtail, rc);
+  else {
     sel_rmfile(&rc->rs->f);
     zap(rc->rs);
     rc->rs = 0;
-  } else {
-    rc->next->prev = rc->prev;
-    rc->prev->next = rc->next;
   }
 }
 
@@ -677,10 +686,7 @@ static void answer(int fd, unsigned mode, void *vp)
 
   rs->rc = 0;
   rc->rs = 0;
-  rs->next = FREE->next;
-  rs->prev = FREE;
-  FREE->next->prev = rs;
-  FREE->next = rs;
+  LINKHEAD(freelist, freetail, rs);
 
   /* --- Tie a timer onto the server block --- */
 
@@ -694,10 +700,9 @@ static void answer(int fd, unsigned mode, void *vp)
 
   /* --- If there are any clients waiting, attach one --- */
 
-  if (QUEUE->next != QUEUE) {
-    rc = QUEUE->next;
-    QUEUE->next = rc->next;
-    rc->next->prev = QUEUE;
+  if (qhead) {
+    rc = qhead;
+    UNLINK(qhead, qtail, rc);
     attach(rc);
   }
 }
@@ -787,7 +792,7 @@ static void attach(bres_client *rc)
    */
 
 again:
-  rs = FREE->next;
+  rs = freelist;
   if (rs->kid != -1)
     sel_rmtimer(&rs->t);
   else {
@@ -844,9 +849,7 @@ again:
   /* --- Fiddle with lists so that everything's OK --- */
 
   sel_addfile(&rs->f);
-  rs->next->prev = FREE;
-  FREE->next = rs->next;
-  rs->next = rs->prev = rs;
+  UNLINK(freelist, freetail, rs);
   rs->rc = rc;
   rc->rs = rs;
   return;
@@ -871,13 +874,10 @@ static void resolve(bres_client *rc)
   /* --- If there's a free server, plug it in --- */
 
   rc->rs = 0;
-  if (FREE->next == FREE) {
-    rc->next = QUEUE;
-    rc->prev = QUEUE->prev;
-    QUEUE->prev->next = rc;
-    QUEUE->prev = rc;
-  } else
+  if (freelist)
     attach(rc);
+  else
+    LINKTAIL(qhead, qtail, rc);
 }
 
 /* --- @bres_byaddr@ --- *
@@ -967,12 +967,9 @@ void bres_init(sel_state *s)
 
   sel = s;
   for (i = 0; i < BRES_MAX; i++) {
-    servers[i].next = FREE;
-    servers[i].prev = FREE->prev;
     servers[i].kid = -1;
     servers[i].rc = 0;
-    FREE->prev->next = &servers[i];
-    FREE->prev = &servers[i];
+    LINKTAIL(freelist, freetail, &servers[i]);
   }
 }