drd_semaphore.c revision 62ada3f31afe602f7c9a651530d16b06655400ff
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/** Free the memory that was allocated by semaphore_initialize(). Called by 106 * clientobj_remove(). 107 */ 108static void semaphore_cleanup(struct semaphore_info* p) 109{ 110 Segment* sg; 111 112 if (p->waiters > 0) 113 { 114 SemaphoreErrInfo sei = { p->a1 }; 115 VG_(maybe_record_error)(VG_(get_running_tid)(), 116 SemaphoreErr, 117 VG_(get_IP)(VG_(get_running_tid)()), 118 "Destruction of semaphore that is being waited" 119 " upon", 120 &sei); 121 } 122 while ((sg = segment_pop(p))) 123 DRD_(sg_put)(sg); 124 VG_(deleteXA)(p->last_sem_post_seg); 125} 126 127static 128struct semaphore_info* 129semaphore_get_or_allocate(const Addr semaphore) 130{ 131 struct semaphore_info *p; 132 133 tl_assert(offsetof(DrdClientobj, semaphore) == 0); 134 p = &clientobj_get(semaphore, ClientSemaphore)->semaphore; 135 if (p == 0) 136 { 137 tl_assert(offsetof(DrdClientobj, semaphore) == 0); 138 p = &clientobj_add(semaphore, ClientSemaphore)->semaphore; 139 semaphore_initialize(p, semaphore); 140 } 141 return p; 142} 143 144static struct semaphore_info* semaphore_get(const Addr semaphore) 145{ 146 tl_assert(offsetof(DrdClientobj, semaphore) == 0); 147 return &clientobj_get(semaphore, ClientSemaphore)->semaphore; 148} 149 150/** Called before sem_init(). */ 151struct semaphore_info* semaphore_init(const Addr semaphore, 152 const Word pshared, const UInt value) 153{ 154 struct semaphore_info* p; 155 Segment* sg; 156 157 if (s_trace_semaphore) 158 { 159 VG_(message)(Vg_UserMsg, 160 "[%d/%d] semaphore_init 0x%lx value %u", 161 VG_(get_running_tid)(), 162 thread_get_running_tid(), 163 semaphore, 164 value); 165 } 166 p = semaphore_get(semaphore); 167 if (p) 168 { 169 const ThreadId vg_tid = VG_(get_running_tid)(); 170 SemaphoreErrInfo SEI = { semaphore }; 171 VG_(maybe_record_error)(vg_tid, 172 SemaphoreErr, 173 VG_(get_IP)(vg_tid), 174 "Semaphore reinitialization", 175 &SEI); 176 // Remove all segments from the segment stack. 177 while ((sg = segment_pop(p))) 178 { 179 DRD_(sg_put)(sg); 180 } 181 } 182 else 183 { 184 p = semaphore_get_or_allocate(semaphore); 185 } 186 tl_assert(p); 187 p->waits_to_skip = value; 188 p->value = value; 189 return p; 190} 191 192/** Called after sem_destroy(). */ 193void semaphore_destroy(const Addr semaphore) 194{ 195 struct semaphore_info* p; 196 197 p = semaphore_get(semaphore); 198 199 if (s_trace_semaphore) 200 { 201 VG_(message)(Vg_UserMsg, 202 "[%d/%d] semaphore_destroy 0x%lx value %u", 203 VG_(get_running_tid)(), 204 thread_get_running_tid(), 205 semaphore, 206 p ? p->value : 0); 207 } 208 209 if (p == 0) 210 { 211 GenericErrInfo GEI; 212 VG_(maybe_record_error)(VG_(get_running_tid)(), 213 GenericErr, 214 VG_(get_IP)(VG_(get_running_tid)()), 215 "Not a semaphore", 216 &GEI); 217 return; 218 } 219 220 clientobj_remove(semaphore, ClientSemaphore); 221} 222 223/** Called before sem_wait(). */ 224void semaphore_pre_wait(const Addr semaphore) 225{ 226 struct semaphore_info* p; 227 228 p = semaphore_get_or_allocate(semaphore); 229 tl_assert(p); 230 tl_assert((int)p->waiters >= 0); 231 p->waiters++; 232 tl_assert(p->waiters > 0); 233} 234 235/** Called after sem_wait() finished. 236 * @note Do not rely on the value of 'waited' -- some glibc versions do 237 * not set it correctly. 238 */ 239void semaphore_post_wait(const DrdThreadId tid, const Addr semaphore, 240 const Bool waited) 241{ 242 struct semaphore_info* p; 243 Segment* sg; 244 245 p = semaphore_get(semaphore); 246 if (s_trace_semaphore) 247 { 248 VG_(message)(Vg_UserMsg, 249 "[%d/%d] semaphore_wait 0x%lx value %u -> %u", 250 VG_(get_running_tid)(), 251 thread_get_running_tid(), 252 semaphore, 253 p ? p->value : 0, 254 p ? p->value - 1 : 0); 255 } 256 tl_assert(p); 257 tl_assert(p->waiters > 0); 258 p->waiters--; 259 tl_assert((int)p->waiters >= 0); 260 tl_assert((int)p->value >= 0); 261 if (p->value == 0) 262 { 263 SemaphoreErrInfo sei = { semaphore }; 264 VG_(maybe_record_error)(VG_(get_running_tid)(), 265 SemaphoreErr, 266 VG_(get_IP)(VG_(get_running_tid)()), 267 "Invalid semaphore", 268 &sei); 269 return; 270 } 271 p->value--; 272 tl_assert((int)p->value >= 0); 273 if (p->waits_to_skip > 0) 274 p->waits_to_skip--; 275 else 276 { 277 sg = segment_pop(p); 278 tl_assert(sg); 279 if (sg) 280 { 281 if (p->last_sem_post_tid != tid 282 && p->last_sem_post_tid != DRD_INVALID_THREADID) 283 { 284 thread_combine_vc2(tid, &sg->vc); 285 } 286 DRD_(sg_put)(sg); 287 thread_new_segment(tid); 288 s_semaphore_segment_creation_count++; 289 } 290 } 291} 292 293/** Called before sem_post(). */ 294void semaphore_pre_post(const DrdThreadId tid, const Addr semaphore) 295{ 296 struct semaphore_info* p; 297 Segment* sg; 298 299 p = semaphore_get_or_allocate(semaphore); 300 p->value++; 301 302 if (s_trace_semaphore) 303 { 304 VG_(message)(Vg_UserMsg, 305 "[%d/%d] semaphore_post 0x%lx value %u -> %u", 306 VG_(get_running_tid)(), 307 thread_get_running_tid(), 308 semaphore, 309 p->value - 1, p->value); 310 } 311 312 p->last_sem_post_tid = tid; 313 thread_new_segment(tid); 314 sg = 0; 315 thread_get_latest_segment(&sg, tid); 316 tl_assert(sg); 317 segment_push(p, sg); 318 s_semaphore_segment_creation_count++; 319} 320 321/** Called after sem_post() finished successfully. */ 322void semaphore_post_post(const DrdThreadId tid, const Addr semaphore, 323 const Bool waited) 324{ 325 /* Note: it is hard to implement the sem_post() wrapper correctly in */ 326 /* case sem_post() returns an error code. This is because handling this */ 327 /* case correctly requires restoring the vector clock associated with */ 328 /* the semaphore to its original value here. In order to do that without */ 329 /* introducing a race condition, extra locking has to be added around */ 330 /* each semaphore call. Such extra locking would have to be added in */ 331 /* drd_intercepts.c. However, it is hard to implement synchronization */ 332 /* in drd_intercepts.c in a portable way without calling already */ 333 /* redirected functions. */ 334} 335 336void semaphore_thread_delete(const DrdThreadId threadid) 337{ } 338 339ULong get_semaphore_segment_creation_count(void) 340{ 341 return s_semaphore_segment_creation_count; 342} 343