drd_semaphore.c revision 195e41fe2b9e02e142a0461113bfa55c89d24c5e
1/* 2 This file is part of drd, a data race detector. 3 4 Copyright (C) 2006-2008 Bart Van Assche 5 bart.vanassche@gmail.com 6 7 This program is free software; you can redistribute it and/or 8 modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the 10 License, or (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 20 02111-1307, USA. 21 22 The GNU General Public License is contained in the file COPYING. 23*/ 24 25 26#include "drd_clientobj.h" 27#include "drd_error.h" 28#include "drd_semaphore.h" 29#include "drd_suppression.h" 30#include "pub_tool_errormgr.h" // VG_(maybe_record_error)() 31#include "pub_tool_libcassert.h" // tl_assert() 32#include "pub_tool_libcprint.h" // VG_(printf)() 33#include "pub_tool_machine.h" // VG_(get_IP)() 34#include "pub_tool_mallocfree.h" // VG_(malloc), VG_(free) 35#include "pub_tool_threadstate.h" // VG_(get_running_tid)() 36 37 38// Local functions. 39 40static void semaphore_cleanup(struct semaphore_info* p); 41 42 43// Local variables. 44 45static Bool s_trace_semaphore; 46static ULong s_semaphore_segment_creation_count; 47 48 49// Function definitions. 50 51static void segment_push(struct semaphore_info* p, Segment* sg) 52{ 53 Word n; 54 55 tl_assert(sg); 56 n = VG_(addToXA)(p->last_sem_post_seg, &sg); 57#if 0 58 VG_(message)(Vg_UserMsg, "0x%lx push: added at position %ld/%ld", 59 p->a1, n, VG_(sizeXA)(p->last_sem_post_seg)); 60#endif 61 tl_assert(*(Segment**)VG_(indexXA)(p->last_sem_post_seg, n) == sg); 62} 63 64static Segment* segment_pop(struct semaphore_info* p) 65{ 66 Word sz; 67 Segment* sg; 68 69 sz = VG_(sizeXA)(p->last_sem_post_seg); 70#if 0 71 VG_(message)(Vg_UserMsg, "0x%lx pop: removed from position %ld/%ld", 72 p->a1, sz - 1, sz); 73#endif 74 sg = 0; 75 if (sz > 0) 76 { 77 sg = *(Segment**)VG_(indexXA)(p->last_sem_post_seg, sz - 1); 78 tl_assert(sg); 79 VG_(dropTailXA)(p->last_sem_post_seg, 1); 80 } 81 return sg; 82} 83 84void semaphore_set_trace(const Bool trace_semaphore) 85{ 86 s_trace_semaphore = trace_semaphore; 87} 88 89static 90void semaphore_initialize(struct semaphore_info* const p, const Addr semaphore) 91{ 92 tl_assert(semaphore != 0); 93 tl_assert(p->a1 == semaphore); 94 tl_assert(p->type == ClientSemaphore); 95 96 p->cleanup = (void(*)(DrdClientobj*))semaphore_cleanup; 97 p->waits_to_skip = 0; 98 p->value = 0; 99 p->waiters = 0; 100 p->last_sem_post_tid = DRD_INVALID_THREADID; 101 p->last_sem_post_seg = VG_(newXA)(VG_(malloc), "drd.sg-stack", 102 VG_(free), sizeof(Segment*)); 103} 104 105/** 106 * Free the memory that was allocated by semaphore_initialize(). Called by 107 * DRD_(clientobj_remove)(). 108 */ 109static void semaphore_cleanup(struct semaphore_info* p) 110{ 111 Segment* sg; 112 113 if (p->waiters > 0) 114 { 115 SemaphoreErrInfo sei = { p->a1 }; 116 VG_(maybe_record_error)(VG_(get_running_tid)(), 117 SemaphoreErr, 118 VG_(get_IP)(VG_(get_running_tid)()), 119 "Destruction of semaphore that is being waited" 120 " upon", 121 &sei); 122 } 123 while ((sg = segment_pop(p))) 124 DRD_(sg_put)(sg); 125 VG_(deleteXA)(p->last_sem_post_seg); 126} 127 128static 129struct semaphore_info* 130semaphore_get_or_allocate(const Addr semaphore) 131{ 132 struct semaphore_info *p; 133 134 tl_assert(offsetof(DrdClientobj, semaphore) == 0); 135 p = &(DRD_(clientobj_get)(semaphore, ClientSemaphore)->semaphore); 136 if (p == 0) 137 { 138 tl_assert(offsetof(DrdClientobj, semaphore) == 0); 139 p = &(DRD_(clientobj_add)(semaphore, ClientSemaphore)->semaphore); 140 semaphore_initialize(p, semaphore); 141 } 142 return p; 143} 144 145static struct semaphore_info* semaphore_get(const Addr semaphore) 146{ 147 tl_assert(offsetof(DrdClientobj, semaphore) == 0); 148 return &(DRD_(clientobj_get)(semaphore, ClientSemaphore)->semaphore); 149} 150 151/** Called before sem_init(). */ 152struct semaphore_info* semaphore_init(const Addr semaphore, 153 const Word pshared, const UInt value) 154{ 155 struct semaphore_info* p; 156 Segment* sg; 157 158 if (s_trace_semaphore) 159 { 160 VG_(message)(Vg_UserMsg, 161 "[%d/%d] semaphore_init 0x%lx value %u", 162 VG_(get_running_tid)(), 163 thread_get_running_tid(), 164 semaphore, 165 value); 166 } 167 p = semaphore_get(semaphore); 168 if (p) 169 { 170 const ThreadId vg_tid = VG_(get_running_tid)(); 171 SemaphoreErrInfo SEI = { semaphore }; 172 VG_(maybe_record_error)(vg_tid, 173 SemaphoreErr, 174 VG_(get_IP)(vg_tid), 175 "Semaphore reinitialization", 176 &SEI); 177 // Remove all segments from the segment stack. 178 while ((sg = segment_pop(p))) 179 { 180 DRD_(sg_put)(sg); 181 } 182 } 183 else 184 { 185 p = semaphore_get_or_allocate(semaphore); 186 } 187 tl_assert(p); 188 p->waits_to_skip = value; 189 p->value = value; 190 return p; 191} 192 193/** Called after sem_destroy(). */ 194void semaphore_destroy(const Addr semaphore) 195{ 196 struct semaphore_info* p; 197 198 p = semaphore_get(semaphore); 199 200 if (s_trace_semaphore) 201 { 202 VG_(message)(Vg_UserMsg, 203 "[%d/%d] semaphore_destroy 0x%lx value %u", 204 VG_(get_running_tid)(), 205 thread_get_running_tid(), 206 semaphore, 207 p ? p->value : 0); 208 } 209 210 if (p == 0) 211 { 212 GenericErrInfo GEI; 213 VG_(maybe_record_error)(VG_(get_running_tid)(), 214 GenericErr, 215 VG_(get_IP)(VG_(get_running_tid)()), 216 "Not a semaphore", 217 &GEI); 218 return; 219 } 220 221 DRD_(clientobj_remove)(semaphore, ClientSemaphore); 222} 223 224/** Called before sem_wait(). */ 225void semaphore_pre_wait(const Addr semaphore) 226{ 227 struct semaphore_info* p; 228 229 p = semaphore_get_or_allocate(semaphore); 230 tl_assert(p); 231 tl_assert((int)p->waiters >= 0); 232 p->waiters++; 233 tl_assert(p->waiters > 0); 234} 235 236/** Called after sem_wait() finished. 237 * @note Do not rely on the value of 'waited' -- some glibc versions do 238 * not set it correctly. 239 */ 240void semaphore_post_wait(const DrdThreadId tid, const Addr semaphore, 241 const Bool waited) 242{ 243 struct semaphore_info* p; 244 Segment* sg; 245 246 p = semaphore_get(semaphore); 247 if (s_trace_semaphore) 248 { 249 VG_(message)(Vg_UserMsg, 250 "[%d/%d] semaphore_wait 0x%lx value %u -> %u", 251 VG_(get_running_tid)(), 252 thread_get_running_tid(), 253 semaphore, 254 p ? p->value : 0, 255 p ? p->value - 1 : 0); 256 } 257 tl_assert(p); 258 tl_assert(p->waiters > 0); 259 p->waiters--; 260 tl_assert((int)p->waiters >= 0); 261 tl_assert((int)p->value >= 0); 262 if (p->value == 0) 263 { 264 SemaphoreErrInfo sei = { semaphore }; 265 VG_(maybe_record_error)(VG_(get_running_tid)(), 266 SemaphoreErr, 267 VG_(get_IP)(VG_(get_running_tid)()), 268 "Invalid semaphore", 269 &sei); 270 return; 271 } 272 p->value--; 273 tl_assert((int)p->value >= 0); 274 if (p->waits_to_skip > 0) 275 p->waits_to_skip--; 276 else 277 { 278 sg = segment_pop(p); 279 tl_assert(sg); 280 if (sg) 281 { 282 if (p->last_sem_post_tid != tid 283 && p->last_sem_post_tid != DRD_INVALID_THREADID) 284 { 285 thread_combine_vc2(tid, &sg->vc); 286 } 287 DRD_(sg_put)(sg); 288 thread_new_segment(tid); 289 s_semaphore_segment_creation_count++; 290 } 291 } 292} 293 294/** Called before sem_post(). */ 295void semaphore_pre_post(const DrdThreadId tid, const Addr semaphore) 296{ 297 struct semaphore_info* p; 298 Segment* sg; 299 300 p = semaphore_get_or_allocate(semaphore); 301 p->value++; 302 303 if (s_trace_semaphore) 304 { 305 VG_(message)(Vg_UserMsg, 306 "[%d/%d] semaphore_post 0x%lx value %u -> %u", 307 VG_(get_running_tid)(), 308 thread_get_running_tid(), 309 semaphore, 310 p->value - 1, p->value); 311 } 312 313 p->last_sem_post_tid = tid; 314 thread_new_segment(tid); 315 sg = 0; 316 thread_get_latest_segment(&sg, tid); 317 tl_assert(sg); 318 segment_push(p, sg); 319 s_semaphore_segment_creation_count++; 320} 321 322/** Called after sem_post() finished successfully. */ 323void semaphore_post_post(const DrdThreadId tid, const Addr semaphore, 324 const Bool waited) 325{ 326 /* Note: it is hard to implement the sem_post() wrapper correctly in */ 327 /* case sem_post() returns an error code. This is because handling this */ 328 /* case correctly requires restoring the vector clock associated with */ 329 /* the semaphore to its original value here. In order to do that without */ 330 /* introducing a race condition, extra locking has to be added around */ 331 /* each semaphore call. Such extra locking would have to be added in */ 332 /* drd_intercepts.c. However, it is hard to implement synchronization */ 333 /* in drd_intercepts.c in a portable way without calling already */ 334 /* redirected functions. */ 335} 336 337void semaphore_thread_delete(const DrdThreadId threadid) 338{ } 339 340ULong get_semaphore_segment_creation_count(void) 341{ 342 return s_semaphore_segment_creation_count; 343} 344