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