drd: Use macros and inline functions for list manipulation

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12353 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/drd/drd_list.h b/drd/drd_list.h
new file mode 100644
index 0000000..ac9705a
--- /dev/null
+++ b/drd/drd_list.h
@@ -0,0 +1,203 @@
+/*
+  This file is part of drd, a thread error detector.
+
+  Copyright (C) 1990-2011 Linus Torvalds and other kernel authors.
+  Copyright (C) 2012 Bart Van Assche <bvanassche@acm.org>.
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+  02111-1307, USA.
+
+  The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef _DRD_LIST_H_
+#define _DRD_LIST_H_
+
+/*
+ * Doubly linked lists. See also the Linux kernel headers <linux/types.h>.
+ */
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:        the pointer to the member.
+ * @type:       the type of the container struct this is embedded in.
+ * @member:     the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({                      \
+         const typeof( ((type *)0)->member ) *__mptr = (ptr);   \
+         (type *)( (char *)__mptr - offsetof(type,member) );})
+
+struct list_head {
+   struct list_head *next;
+   struct list_head *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+static inline void init_list_head(struct list_head *list)
+{
+   list->next = list;
+   list->prev = list;
+}
+
+static inline void __list_add(struct list_head *new,
+                              struct list_head *prev,
+                              struct list_head *next)
+{
+   next->prev = new;
+   new->next = next;
+   new->prev = prev;
+   prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+   __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+   __list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+   next->prev = prev;
+   prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+   __list_del(entry->prev, entry->next);
+   entry->next = NULL;
+   entry->prev = NULL;
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+                                const struct list_head *head)
+{
+   return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+   return head->next == head;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:        the &struct list_head pointer.
+ * @type:       the type of the struct this is embedded in.
+ * @member:     the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+   container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr:        the list head to take the element from.
+ * @type:       the type of the struct this is embedded in.
+ * @member:     the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+   list_entry((ptr)->next, type, member)
+
+#define list_next_entry(ptr, type, member) \
+   list_entry((ptr)->next, type, member)
+
+#define list_last_entry(ptr, type, member) \
+   list_entry((ptr)->prev, type, member)
+
+/**
+ * list_for_each_entry  -       iterate over list of given type
+ * @pos:        the type * to use as a loop cursor.
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)                          \
+   for (pos = list_entry((head)->next, typeof(*pos), member);           \
+        &pos->member != (head);                                         \
+        pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos:        the type * to use as a loop cursor.
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)                  \
+   for (pos = list_entry((head)->prev, typeof(*pos), member);           \
+        &pos->member != (head);                                         \
+        pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+#define list_for_each_entry_reverse_continue(pos, head, member)         \
+   for ( ;                                                              \
+        &pos->member != (head);                                         \
+        pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:        the type * to use as a loop cursor.
+ * @n:          another type * to use as temporary storage
+ * @head:       the head for your list.
+ * @member:     the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)                  \
+   for (pos = list_entry((head)->next, typeof(*pos), member),           \
+           n = list_entry(pos->member.next, typeof(*pos), member);      \
+        &pos->member != (head);                                         \
+        pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+#endif /* _DRD_LIST_H_ */
diff --git a/drd/drd_main.c b/drd/drd_main.c
index de8613c..26e04a0 100644
--- a/drd/drd_main.c
+++ b/drd/drd_main.c
@@ -820,6 +820,8 @@
 
    DRD_(clientobj_init)();
 
+   DRD_(thread_init)();
+
    {
       Char* const smi = VG_(getenv)("DRD_SEGMENT_MERGING_INTERVAL");
       if (smi)
diff --git a/drd/drd_segment.c b/drd/drd_segment.c
index c3f8d31..40db038 100644
--- a/drd/drd_segment.c
+++ b/drd/drd_segment.c
@@ -34,6 +34,11 @@
 #include "pub_tool_threadstate.h" // VG_INVALID_THREADID
 
 
+/* Global variables. */
+
+struct list_head DRD_(g_sg_list) = LIST_HEAD_INIT(DRD_(g_sg_list));
+
+
 /* Local variables. */
 
 static ULong s_segment_merge_count;
@@ -68,8 +73,10 @@
    creator_sg = (creator != DRD_INVALID_THREADID
                  ? DRD_(thread_get_segment)(creator) : 0);
 
-   sg->next = 0;
-   sg->prev = 0;
+   sg->g_list.next = NULL;
+   sg->g_list.prev = NULL;
+   sg->thr_list.next = NULL;
+   sg->thr_list.prev = NULL;
    sg->tid = created;
    sg->refcnt = 1;
 
@@ -119,6 +126,7 @@
    sg = VG_(malloc)("drd.segment.sn.1", sizeof(*sg));
    tl_assert(sg);
    sg_init(sg, creator, created);
+   list_add(&sg->g_list, &DRD_(g_sg_list));
    return sg;
 }
 
@@ -137,6 +145,7 @@
    s_segments_alive_count--;
 
    tl_assert(sg);
+   list_del(&sg->g_list);
    DRD_(sg_cleanup)(sg);
    VG_(free)(sg);
 }
diff --git a/drd/drd_segment.h b/drd/drd_segment.h
index 5d980ce..5782b4a 100644
--- a/drd/drd_segment.h
+++ b/drd/drd_segment.h
@@ -33,6 +33,7 @@
  */
 
 
+#include "drd_list.h"
 #include "drd_vc.h"
 #include "pub_drd_bitmap.h"
 #include "pub_tool_execontext.h" // ExeContext
@@ -41,9 +42,9 @@
 
 typedef struct segment
 {
+   struct list_head   g_list;
    /** Pointers to next and previous segments executed by the same thread. */
-   struct segment*    next;
-   struct segment*    prev;
+   struct list_head   thr_list;
    DrdThreadId        tid;
    /** Reference count: number of pointers that point to this segment. */
    int                refcnt;
@@ -58,6 +59,7 @@
    struct bitmap      bm;
 } Segment;
 
+extern struct list_head DRD_(g_sg_list);
 
 Segment* DRD_(sg_new)(const DrdThreadId creator, const DrdThreadId created);
 static int DRD_(sg_get_refcnt)(const Segment* const sg);
diff --git a/drd/drd_thread.c b/drd/drd_thread.c
index 9f0bbcb..0b52228 100644
--- a/drd/drd_thread.c
+++ b/drd/drd_thread.c
@@ -140,6 +140,14 @@
    s_join_list_vol = jlv;
 }
 
+void DRD_(thread_init)(void)
+{
+   int i;
+
+   for (i = 0; i < DRD_N_THREADS; i++)
+      init_list_head(&DRD_(g_threadinfo)[i].sg_list);
+}
+
 /**
  * Convert Valgrind's ThreadId into a DrdThreadId.
  *
@@ -193,8 +201,7 @@
          DRD_(g_threadinfo)[i].pthread_create_nesting_level = 0;
          DRD_(g_threadinfo)[i].synchr_nesting = 0;
          DRD_(g_threadinfo)[i].deletion_seq = s_deletion_tail - 1;
-         tl_assert(DRD_(g_threadinfo)[i].first == 0);
-         tl_assert(DRD_(g_threadinfo)[i].last == 0);
+         tl_assert(list_empty(&DRD_(g_threadinfo)[i].sg_list));
 
          tl_assert(DRD_(IsValidDrdThreadId)(i));
 
@@ -290,8 +297,7 @@
    tl_assert(0 <= (int)created && created < DRD_N_THREADS
              && created != DRD_INVALID_THREADID);
 
-   tl_assert(DRD_(g_threadinfo)[created].first == 0);
-   tl_assert(DRD_(g_threadinfo)[created].last == 0);
+   tl_assert(list_empty(&DRD_(g_threadinfo)[created].sg_list));
    /* Create an initial segment for the newly created thread. */
    thread_append_segment(created, DRD_(sg_new)(creator, created));
 
@@ -490,11 +496,10 @@
    tl_assert(DRD_(IsValidDrdThreadId)(tid));
 
    tl_assert(DRD_(g_threadinfo)[tid].synchr_nesting >= 0);
-   for (sg = DRD_(g_threadinfo)[tid].last; sg; sg = sg_prev)
+   list_for_each_entry_safe(sg, sg_prev, &DRD_(g_threadinfo)[tid].sg_list,
+                            thr_list)
    {
-      sg_prev = sg->prev;
-      sg->prev = 0;
-      sg->next = 0;
+      list_del(&sg->thr_list);
       DRD_(sg_put)(sg);
    }
    DRD_(g_threadinfo)[tid].valid = False;
@@ -504,8 +509,7 @@
       DRD_(g_threadinfo)[tid].detached_posix_thread = False;
    else
       tl_assert(!DRD_(g_threadinfo)[tid].detached_posix_thread);
-   DRD_(g_threadinfo)[tid].first = 0;
-   DRD_(g_threadinfo)[tid].last = 0;
+   tl_assert(list_empty(&DRD_(g_threadinfo)[tid].sg_list));
 
    tl_assert(! DRD_(IsValidDrdThreadId)(tid));
 }
@@ -742,13 +746,7 @@
    tl_assert(DRD_(sane_ThreadInfo)(&DRD_(g_threadinfo)[tid]));
 #endif
 
-   sg->prev = DRD_(g_threadinfo)[tid].last;
-   sg->next = 0;
-   if (DRD_(g_threadinfo)[tid].last)
-      DRD_(g_threadinfo)[tid].last->next = sg;
-   DRD_(g_threadinfo)[tid].last = sg;
-   if (DRD_(g_threadinfo)[tid].first == 0)
-      DRD_(g_threadinfo)[tid].first = sg;
+   list_add_tail(&sg->thr_list, &DRD_(g_threadinfo)[tid].sg_list);
 
 #ifdef ENABLE_DRD_CONSISTENCY_CHECKS
    tl_assert(DRD_(sane_ThreadInfo)(&DRD_(g_threadinfo)[tid]));
@@ -769,14 +767,7 @@
    tl_assert(DRD_(sane_ThreadInfo)(&DRD_(g_threadinfo)[tid]));
 #endif
 
-   if (sg->prev)
-      sg->prev->next = sg->next;
-   if (sg->next)
-      sg->next->prev = sg->prev;
-   if (sg == DRD_(g_threadinfo)[tid].first)
-      DRD_(g_threadinfo)[tid].first = sg->next;
-   if (sg == DRD_(g_threadinfo)[tid].last)
-      DRD_(g_threadinfo)[tid].last = sg->prev;
+   list_del(&sg->thr_list);
    DRD_(sg_put)(sg);
 
 #ifdef ENABLE_DRD_CONSISTENCY_CHECKS
@@ -790,10 +781,13 @@
  */
 VectorClock* DRD_(thread_get_vc)(const DrdThreadId tid)
 {
+   struct list_head* sg_list;
+
    tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
              && tid != DRD_INVALID_THREADID);
-   tl_assert(DRD_(g_threadinfo)[tid].last);
-   return &DRD_(g_threadinfo)[tid].last->vc;
+   sg_list = &DRD_(g_threadinfo)[tid].sg_list;
+   tl_assert(!list_empty(sg_list));
+   return &list_last_entry(sg_list, Segment, thr_list)->vc;
 }
 
 /**
@@ -801,13 +795,16 @@
  */
 void DRD_(thread_get_latest_segment)(Segment** sg, const DrdThreadId tid)
 {
+   struct list_head* sg_list;
+
    tl_assert(sg);
    tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
              && tid != DRD_INVALID_THREADID);
-   tl_assert(DRD_(g_threadinfo)[tid].last);
+   sg_list = &DRD_(g_threadinfo)[tid].sg_list;
+   tl_assert(!list_empty(sg_list));
 
    DRD_(sg_put)(*sg);
-   *sg = DRD_(sg_get)(DRD_(g_threadinfo)[tid].last);
+   *sg = DRD_(sg_get)(list_last_entry(sg_list, Segment, thr_list));
 }
 
 /**
@@ -820,14 +817,15 @@
 {
    unsigned i;
    Bool first;
+   struct list_head* sg_list;
    Segment* latest_sg;
 
    first = True;
    for (i = 0; i < DRD_N_THREADS; i++)
    {
-      latest_sg = DRD_(g_threadinfo)[i].last;
-      if (latest_sg)
-      {
+      sg_list = &DRD_(g_threadinfo)[i].sg_list;
+      if (!list_empty(sg_list)) {
+         latest_sg = list_last_entry(sg_list, Segment, thr_list);
          if (first)
             DRD_(vc_assign)(vc, &latest_sg->vc);
          else
@@ -846,14 +844,15 @@
 {
    unsigned i;
    Bool first;
+   struct list_head* sg_list;
    Segment* latest_sg;
 
    first = True;
    for (i = 0; i < DRD_N_THREADS; i++)
    {
-      latest_sg = DRD_(g_threadinfo)[i].last;
-      if (latest_sg)
-      {
+      sg_list = &DRD_(g_threadinfo)[i].sg_list;
+      if (!list_empty(sg_list)) {
+         latest_sg = list_last_entry(sg_list, Segment, thr_list);
          if (first)
             DRD_(vc_assign)(vc, &latest_sg->vc);
          else
@@ -898,10 +897,13 @@
    {
       Segment* sg;
       Segment* sg_next;
-      for (sg = DRD_(g_threadinfo)[i].first;
-           sg && (sg_next = sg->next) && DRD_(vc_lte)(&sg->vc, &thread_vc_min);
-           sg = sg_next)
-      {
+      struct list_head* sg_list;
+
+      sg_list = &DRD_(g_threadinfo)[i].sg_list;
+      list_for_each_entry_safe(sg, sg_next, sg_list, thr_list) {
+         if (list_is_last(&sg->thr_list, sg_list)
+             || !DRD_(vc_lte)(&sg->vc, &thread_vc_min))
+            break;
          thread_discard_segment(i, sg);
       }
    }
@@ -942,19 +944,23 @@
                                                Segment* const sg2)
 {
    unsigned i;
+   struct list_head* sg_list;
 
-   tl_assert(sg1->next);
-   tl_assert(sg2->next);
-   tl_assert(sg1->next == sg2);
+   sg_list = &DRD_(g_threadinfo)[tid].sg_list;
+   tl_assert(!list_is_last(&sg1->thr_list, sg_list));
+   tl_assert(!list_is_last(&sg2->thr_list, sg_list));
+   tl_assert(list_next_entry(&sg1->thr_list, Segment, thr_list) == sg2);
    tl_assert(DRD_(vc_lte)(&sg1->vc, &sg2->vc));
 
    for (i = 0; i < DRD_N_THREADS; i++)
    {
       Segment* sg;
 
-      for (sg = DRD_(g_threadinfo)[i].first; sg; sg = sg->next)
+      sg_list = &DRD_(g_threadinfo)[i].sg_list;
+      list_for_each_entry(sg, sg_list, thr_list)
       {
-         if (! sg->next || DRD_(sg_get_refcnt)(sg) > 1)
+         if (list_is_last(&sg->thr_list, sg_list)
+             || DRD_(sg_get_refcnt)(sg) > 1)
          {
             if (DRD_(vc_lte)(&sg2->vc, &sg->vc))
                break;
@@ -962,9 +968,10 @@
                return False;
          }
       }
-      for (sg = DRD_(g_threadinfo)[i].last; sg; sg = sg->prev)
+      list_for_each_entry_reverse(sg, sg_list, thr_list)
       {
-         if (! sg->next || DRD_(sg_get_refcnt)(sg) > 1)
+         if (list_is_last(&sg->thr_list, sg_list)
+             || DRD_(sg_get_refcnt)(sg) > 1)
          {
             if (DRD_(vc_lte)(&sg->vc, &sg1->vc))
                break;
@@ -1009,17 +1016,21 @@
       tl_assert(DRD_(sane_ThreadInfo)(&DRD_(g_threadinfo)[i]));
 #endif
 
-      for (sg = DRD_(g_threadinfo)[i].first; sg; sg = sg->next)
+      struct list_head* sg_list = &DRD_(g_threadinfo)[i].sg_list;
+      list_for_each_entry(sg, sg_list, thr_list)
       {
          if (DRD_(sg_get_refcnt)(sg) == 1
-             && sg->next
-             && DRD_(sg_get_refcnt)(sg->next) == 1
-             && sg->next->next
-             && thread_consistent_segment_ordering(i, sg, sg->next))
-         {
-            /* Merge sg and sg->next into sg. */
-            DRD_(sg_merge)(sg, sg->next);
-            thread_discard_segment(i, sg->next);
+             && !list_is_last(&sg->thr_list, sg_list)) {
+            Segment* sg_next = list_next_entry(&sg->thr_list, Segment,
+                                               thr_list);
+            if (DRD_(sg_get_refcnt)(sg_next) == 1
+                && !list_is_last(&sg_next->thr_list, sg_list)
+                && thread_consistent_segment_ordering(i, sg, sg_next))
+            {
+               /* Merge sg and sg_next into sg. */
+               DRD_(sg_merge)(sg, sg_next);
+               thread_discard_segment(i, sg_next);
+            }
          }
       }
 
@@ -1035,6 +1046,7 @@
  */
 void DRD_(thread_new_segment)(const DrdThreadId tid)
 {
+   struct list_head* sg_list;
    Segment* last_sg;
    Segment* new_sg;
 
@@ -1042,7 +1054,9 @@
              && tid != DRD_INVALID_THREADID);
    tl_assert(thread_conflict_set_up_to_date(DRD_(g_drd_running_tid)));
 
-   last_sg = DRD_(g_threadinfo)[tid].last;
+   sg_list = &DRD_(g_threadinfo)[tid].sg_list;
+   last_sg = list_empty(sg_list) ? NULL
+      : list_last_entry(sg_list, Segment, thr_list);
    new_sg = DRD_(sg_new)(tid, tid);
    thread_append_segment(tid, new_sg);
    if (tid == DRD_(g_drd_running_tid) && last_sg)
@@ -1069,8 +1083,8 @@
              && joiner != DRD_INVALID_THREADID);
    tl_assert(0 <= (int)joinee && joinee < DRD_N_THREADS
              && joinee != DRD_INVALID_THREADID);
-   tl_assert(DRD_(g_threadinfo)[joiner].last);
-   tl_assert(DRD_(g_threadinfo)[joinee].last);
+   tl_assert(!list_empty(&DRD_(g_threadinfo)[joiner].sg_list));
+   tl_assert(!list_empty(&DRD_(g_threadinfo)[joinee].sg_list));
 
    if (DRD_(sg_get_trace)())
    {
@@ -1117,7 +1131,7 @@
 
    tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
              && tid != DRD_INVALID_THREADID);
-   tl_assert(DRD_(g_threadinfo)[tid].last);
+   tl_assert(!list_empty(&DRD_(g_threadinfo)[tid].sg_list));
    tl_assert(sg);
    tl_assert(vc);
 
@@ -1178,12 +1192,10 @@
  */
 void DRD_(thread_stop_using_mem)(const Addr a1, const Addr a2)
 {
-   unsigned i;
    Segment* p;
 
-   for (i = 0; i < DRD_N_THREADS; i++)
-      for (p = DRD_(g_threadinfo)[i].first; p; p = p->next)
-         DRD_(bm_clear)(DRD_(sg_bm)(p), a1, a2);
+   list_for_each_entry(p, &DRD_(g_sg_list), g_list)
+      DRD_(bm_clear)(DRD_(sg_bm)(p), a1, a2);
 
    DRD_(bm_clear)(DRD_(g_conflict_set), a1, a2);
 }
@@ -1216,11 +1228,13 @@
 void DRD_(thread_print_all)(void)
 {
    unsigned i;
+   struct list_head* sg_list;
    Segment* p;
 
    for (i = 0; i < DRD_N_THREADS; i++)
    {
-      if (DRD_(g_threadinfo)[i].first)
+      sg_list = &DRD_(g_threadinfo)[i].sg_list;
+      if (!list_empty(sg_list))
       {
          VG_(printf)("**************\n"
                      "* thread %3d (%d/%d/%d/%d/0x%lx/%d) *\n"
@@ -1232,10 +1246,8 @@
                      DRD_(g_threadinfo)[i].posix_thread_exists,
                      DRD_(g_threadinfo)[i].pt_threadid,
                      DRD_(g_threadinfo)[i].detached_posix_thread);
-         for (p = DRD_(g_threadinfo)[i].first; p; p = p->next)
-         {
+         list_for_each_entry(p, sg_list, thr_list)
             DRD_(sg_print)(p);
-         }
       }
    }
 }
@@ -1276,8 +1288,10 @@
       if (i != tid)
       {
          Segment* q;
-         for (q = DRD_(g_threadinfo)[i].last; q; q = q->prev)
-         {
+         struct list_head *sg_list;
+
+         sg_list = &DRD_(g_threadinfo)[i].sg_list;
+         list_for_each_entry_reverse(q, sg_list, thr_list) {
             /*
              * Since q iterates over the segments of thread i in order of
              * decreasing vector clocks, if q->vc <= p->vc, then
@@ -1291,6 +1305,8 @@
                if (DRD_(bm_has_conflict_with)(DRD_(sg_bm)(q), addr, addr + size,
                                               access_type))
                {
+                  Segment* q_next;
+
                   tl_assert(q->stacktrace);
                   if (VG_(clo_xml))
                      VG_(printf_xml)("  <other_segment_start>\n");
@@ -1304,7 +1320,9 @@
                   else
                      VG_(message)(Vg_UserMsg,
                                   "Other segment end (thread %d)\n", i);
-                  show_call_stack(i, q->next ? q->next->stacktrace : 0);
+                  q_next = list_is_last(&q->thr_list, sg_list)
+                     ? NULL : list_next_entry(&q->thr_list, Segment, thr_list);
+                  show_call_stack(i, q_next ? q_next->stacktrace : 0);
                   if (VG_(clo_xml))
                      VG_(printf_xml)("  </other_segment_end>\n");
                }
@@ -1325,13 +1343,10 @@
    tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
              && tid != DRD_INVALID_THREADID);
 
-   for (p = DRD_(g_threadinfo)[tid].first; p; p = p->next)
-   {
+   list_for_each_entry(p, &DRD_(g_threadinfo)[tid].sg_list, thr_list) {
       if (DRD_(bm_has)(DRD_(sg_bm)(p), addr, addr + size, access_type))
-      {
          thread_report_conflicting_segments_segment(tid, addr, size,
                                                     access_type, p);
-      }
    }
 }
 
@@ -1403,7 +1418,7 @@
       VG_(free)(str);
    }
 
-   p = DRD_(g_threadinfo)[tid].last;
+   p = list_last_entry(&DRD_(g_threadinfo)[tid].sg_list, Segment, thr_list);
    {
       unsigned j;
 
@@ -1422,8 +1437,8 @@
          if (j != tid && DRD_(IsValidDrdThreadId)(j))
          {
             Segment* q;
-            for (q = DRD_(g_threadinfo)[j].last; q; q = q->prev)
-            {
+            list_for_each_entry_reverse(q, &DRD_(g_threadinfo)[j].sg_list,
+                                        thr_list) {
                if (! DRD_(vc_lte)(&q->vc, &p->vc)
                    && ! DRD_(vc_lte)(&p->vc, &q->vc))
                {
@@ -1510,13 +1525,14 @@
       if (j == tid || ! DRD_(IsValidDrdThreadId)(j))
          continue;
 
-      for (q = DRD_(g_threadinfo)[j].last;
-           q && !DRD_(vc_lte)(&q->vc, new_vc);
-           q = q->prev) {
-         const Bool included_in_old_conflict_set
-            = !DRD_(vc_lte)(old_vc, &q->vc);
-         const Bool included_in_new_conflict_set
-            = !DRD_(vc_lte)(new_vc, &q->vc);
+      list_for_each_entry_reverse(q, &DRD_(g_threadinfo)[j].sg_list, thr_list) {
+         Bool included_in_old_conflict_set, included_in_new_conflict_set;
+
+         if (DRD_(vc_lte)(&q->vc, new_vc))
+            break;
+
+         included_in_old_conflict_set = !DRD_(vc_lte)(old_vc, &q->vc);
+         included_in_new_conflict_set = !DRD_(vc_lte)(new_vc, &q->vc);
 
          if (UNLIKELY(s_trace_conflict_set)) {
             char* str;
@@ -1533,12 +1549,16 @@
             DRD_(bm_mark)(DRD_(g_conflict_set), DRD_(sg_bm)(q));
       }
 
-      for ( ; q && !DRD_(vc_lte)(&q->vc, old_vc); q = q->prev) {
-         const Bool included_in_old_conflict_set
-            = !DRD_(vc_lte)(old_vc, &q->vc);
-         const Bool included_in_new_conflict_set
-            = !DRD_(vc_lte)(&q->vc, new_vc)
-            && !DRD_(vc_lte)(new_vc, &q->vc);
+      list_for_each_entry_reverse_continue(q, &DRD_(g_threadinfo)[j].sg_list,
+                                           thr_list) {
+         Bool included_in_old_conflict_set, included_in_new_conflict_set;
+
+         if (DRD_(vc_lte)(&q->vc, old_vc))
+            break;
+
+         included_in_old_conflict_set = !DRD_(vc_lte)(old_vc, &q->vc);
+         included_in_new_conflict_set
+            = !DRD_(vc_lte)(&q->vc, new_vc) && !DRD_(vc_lte)(new_vc, &q->vc);
 
          if (UNLIKELY(s_trace_conflict_set)) {
             char* str;
@@ -1558,15 +1578,16 @@
 
    DRD_(bm_clear_marked)(DRD_(g_conflict_set));
 
-   p = DRD_(g_threadinfo)[tid].last;
+   p = list_last_entry(&DRD_(g_threadinfo)[tid].sg_list, Segment, thr_list);
    for (j = 0; j < DRD_N_THREADS; j++)
    {
       if (j != tid && DRD_(IsValidDrdThreadId)(j))
       {
          Segment* q;
-         for (q = DRD_(g_threadinfo)[j].last;
-              q && !DRD_(vc_lte)(&q->vc, &p->vc);
-              q = q->prev) {
+         list_for_each_entry_reverse(q, &DRD_(g_threadinfo)[j].sg_list,
+                                     thr_list) {
+            if (DRD_(vc_lte)(&q->vc, &p->vc))
+               break;
             if (!DRD_(vc_lte)(&p->vc, &q->vc))
                DRD_(bm_merge2_marked)(DRD_(g_conflict_set), DRD_(sg_bm)(q));
          }
diff --git a/drd/drd_thread.h b/drd/drd_thread.h
index ae36216..cfe04d1 100644
--- a/drd/drd_thread.h
+++ b/drd/drd_thread.h
@@ -29,6 +29,7 @@
 /* Include directives. */
 
 #include "drd_basics.h"
+#include "drd_list.h"
 #include "drd_segment.h"
 #include "pub_drd_bitmap.h"
 #include "pub_tool_libcassert.h"  /* tl_assert()        */
@@ -66,8 +67,7 @@
 /** Per-thread information managed by DRD. */
 typedef struct
 {
-   Segment*  first;         /**< Pointer to first segment. */
-   Segment*  last;          /**< Pointer to last segment. */
+   struct list_head sg_list;/**< Segment list. */
    ThreadId  vg_threadid;   /**< Valgrind thread ID. */
    PThreadId pt_threadid;   /**< POSIX thread ID. */
    Addr      stack_min_min; /**< Lowest value stack pointer ever had. */
@@ -130,6 +130,7 @@
 void DRD_(thread_set_segment_merge_interval)(const int i);
 void DRD_(thread_set_join_list_vol)(const int jlv);
 
+void DRD_(thread_init)(void);
 DrdThreadId DRD_(VgThreadIdToDrdThreadId)(const ThreadId tid);
 DrdThreadId DRD_(NewVgThreadIdToDrdThreadId)(const ThreadId tid);
 DrdThreadId DRD_(PtThreadIdToDrdThreadId)(const PThreadId tid);
@@ -339,12 +340,17 @@
 static __inline__
 Segment* DRD_(thread_get_segment)(const DrdThreadId tid)
 {
+   struct list_head* sg_list;
+
 #ifdef ENABLE_DRD_CONSISTENCY_CHECKS
    tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
              && tid != DRD_INVALID_THREADID);
-   tl_assert(DRD_(g_threadinfo)[tid].last);
 #endif
-   return DRD_(g_threadinfo)[tid].last;
+   sg_list = &DRD_(g_threadinfo)[tid].sg_list;
+#ifdef ENABLE_DRD_CONSISTENCY_CHECKS
+   tl_assert(!list_empty(sg_list));
+#endif
+   return list_last_entry(sg_list, Segment, thr_list);
 }
 
 /** Return a pointer to the latest segment for the running thread. */