From: Bart Van Assche Date: Tue, 24 Jan 2012 18:28:55 +0000 (+0000) Subject: drd: Use macros and inline functions for list manipulation X-Git-Tag: svn/VALGRIND_3_8_0~500 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f7db19c85a0928162ef03170c1cbc3c7ea0e9a6f;p=thirdparty%2Fvalgrind.git drd: Use macros and inline functions for list manipulation git-svn-id: svn://svn.valgrind.org/valgrind/trunk@12353 --- diff --git a/drd/drd_list.h b/drd/drd_list.h new file mode 100644 index 0000000000..ac9705a9f1 --- /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 . + + 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 . + */ + +/** + * 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 de8613c0c0..26e04a0325 100644 --- a/drd/drd_main.c +++ b/drd/drd_main.c @@ -820,6 +820,8 @@ void drd_pre_clo_init(void) 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 c3f8d31d5d..40db038925 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 @@ static void sg_init(Segment* const sg, 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 @@ Segment* DRD_(sg_new)(const DrdThreadId creator, const DrdThreadId created) 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 @@ static void DRD_(sg_delete)(Segment* const sg) 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 5d980cec36..5782b4ad1e 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 @@ typedef struct segment 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 9f0bbcbd7c..0b522284cd 100644 --- a/drd/drd_thread.c +++ b/drd/drd_thread.c @@ -140,6 +140,14 @@ void DRD_(thread_set_join_list_vol)(const int jlv) 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 @@ static DrdThreadId DRD_(VgThreadIdToNewDrdThreadId)(const ThreadId tid) 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 @@ DrdThreadId DRD_(thread_pre_create)(const DrdThreadId creator, 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 @@ void DRD_(thread_delete)(const DrdThreadId tid, const Bool detached) 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 @@ void DRD_(thread_delete)(const DrdThreadId tid, const Bool detached) 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 @@ void thread_append_segment(const DrdThreadId tid, Segment* const sg) 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 @@ void thread_discard_segment(const DrdThreadId tid, Segment* const sg) 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 @@ void thread_discard_segment(const DrdThreadId tid, Segment* const sg) */ 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 @@ VectorClock* DRD_(thread_get_vc)(const DrdThreadId tid) */ 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 @@ static void DRD_(thread_compute_minimum_vc)(VectorClock* vc) { 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 @@ static void DRD_(thread_compute_maximum_vc)(VectorClock* vc) { 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 @@ static void thread_discard_ordered_segments(void) { 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 @@ static Bool thread_consistent_segment_ordering(const DrdThreadId tid, 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 @@ static Bool thread_consistent_segment_ordering(const DrdThreadId tid, 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 @@ static void thread_merge_segments(void) 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 @@ static void thread_merge_segments(void) */ void DRD_(thread_new_segment)(const DrdThreadId tid) { + struct list_head* sg_list; Segment* last_sg; Segment* new_sg; @@ -1042,7 +1054,9 @@ void DRD_(thread_new_segment)(const DrdThreadId tid) && 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 @@ void DRD_(thread_combine_vc_join)(DrdThreadId joiner, DrdThreadId joinee) && 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 @@ static void thread_combine_vc_sync(DrdThreadId tid, const Segment* sg) 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_new_segment_and_combine_vc)(DrdThreadId tid, const Segment* sg) */ 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_set_record_stores)(const DrdThreadId tid, const Bool enabled) 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 @@ void DRD_(thread_print_all)(void) 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 @@ thread_report_conflicting_segments_segment(const DrdThreadId tid, 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 @@ thread_report_conflicting_segments_segment(const DrdThreadId tid, 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)(" \n"); @@ -1304,7 +1320,9 @@ thread_report_conflicting_segments_segment(const DrdThreadId tid, 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)(" \n"); } @@ -1325,13 +1343,10 @@ void DRD_(thread_report_conflicting_segments)(const DrdThreadId tid, 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 @@ static void thread_compute_conflict_set(struct bitmap** conflict_set, 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 @@ static void thread_compute_conflict_set(struct bitmap** conflict_set, 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 @@ void DRD_(thread_update_conflict_set)(const DrdThreadId tid, 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 @@ void DRD_(thread_update_conflict_set)(const DrdThreadId tid, 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 @@ void DRD_(thread_update_conflict_set)(const DrdThreadId tid, 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 ae36216dbe..cfe04d1812 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 @@ typedef UWord PThreadId; /** 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 @@ int DRD_(thread_get_segment_merge_interval)(void); 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 @@ Bool DRD_(thread_address_on_any_stack)(const Addr a) 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. */