/** Called after sem_destroy(). */ void DRD_(semaphore_destroy)(const Addr semaphore) { struct semaphore_info* p; p = semaphore_get(semaphore); if (s_trace_semaphore) { VG_(message)(Vg_UserMsg, "[%d/%d] semaphore_destroy 0x%lx value %u\n", VG_(get_running_tid)(), DRD_(thread_get_running_tid)(), semaphore, p ? p->value : 0); } if (p == 0) { GenericErrInfo GEI = { DRD_(thread_get_running_tid)() }; VG_(maybe_record_error)(VG_(get_running_tid)(), GenericErr, VG_(get_IP)(VG_(get_running_tid)()), "Not a semaphore", &GEI); return; } DRD_(clientobj_remove)(semaphore, ClientSemaphore); }
/** Called after sem_destroy(). */ void semaphore_destroy(const Addr semaphore) { struct semaphore_info* p; if (s_trace_semaphore) { VG_(message)(Vg_UserMsg, "[%d/%d] semaphore_destroy 0x%lx", VG_(get_running_tid)(), thread_get_running_tid(), semaphore); } p = semaphore_get(semaphore); if (p == 0) { GenericErrInfo GEI; VG_(maybe_record_error)(VG_(get_running_tid)(), GenericErr, VG_(get_IP)(VG_(get_running_tid)()), "Not a semaphore", &GEI); return; } clientobj_remove(semaphore, ClientSemaphore); }
/** Called before sem_init(). */ struct semaphore_info* DRD_(semaphore_init)(const Addr semaphore, const Word pshared, const UInt value) { struct semaphore_info* p; Segment* sg; if (s_trace_semaphore) { VG_(message)(Vg_UserMsg, "[%d] sem_init 0x%lx value %u\n", DRD_(thread_get_running_tid)(), semaphore, value); } p = semaphore_get(semaphore); if (p) { const ThreadId vg_tid = VG_(get_running_tid)(); SemaphoreErrInfo SEI = { DRD_(thread_get_running_tid)(), semaphore }; VG_(maybe_record_error)(vg_tid, SemaphoreErr, VG_(get_IP)(vg_tid), "Semaphore reinitialization", &SEI); // Remove all segments from the segment stack. while ((sg = drd_segment_pop(p))) { DRD_(sg_put)(sg); } } else { #if defined(VGO_darwin) const ThreadId vg_tid = VG_(get_running_tid)(); GenericErrInfo GEI = { DRD_(thread_get_running_tid)(), 0 }; VG_(maybe_record_error)(vg_tid, GenericErr, VG_(get_IP)(vg_tid), "sem_init() is not yet supported on Darwin", &GEI); return NULL; #else p = drd_semaphore_get_or_allocate(semaphore); #endif } tl_assert(p); p->waits_to_skip = value; p->value = value; return p; }
/** Called before sem_init(). */ struct semaphore_info* DRD_(semaphore_init)(const Addr semaphore, const Word pshared, const UInt value) { struct semaphore_info* p; Segment* sg; if (s_trace_semaphore) { VG_(message)(Vg_UserMsg, "[%d/%d] semaphore_init 0x%lx value %u\n", VG_(get_running_tid)(), DRD_(thread_get_running_tid)(), semaphore, value); } p = semaphore_get(semaphore); if (p) { const ThreadId vg_tid = VG_(get_running_tid)(); SemaphoreErrInfo SEI = { DRD_(thread_get_running_tid)(), semaphore }; VG_(maybe_record_error)(vg_tid, SemaphoreErr, VG_(get_IP)(vg_tid), "Semaphore reinitialization", &SEI); // Remove all segments from the segment stack. while ((sg = DRD_(segment_pop)(p))) { DRD_(sg_put)(sg); } } else { p = DRD_(semaphore_get_or_allocate)(semaphore); } tl_assert(p); p->waits_to_skip = value; p->value = value; return p; }
/** Called before sem_init(). */ struct semaphore_info* semaphore_init(const Addr semaphore, const Word pshared, const UWord value) { struct semaphore_info* p; if (s_trace_semaphore) { VG_(message)(Vg_UserMsg, "[%d/%d] semaphore_init 0x%lx", VG_(get_running_tid)(), thread_get_running_tid(), semaphore); } if (semaphore_get(semaphore)) { // To do: print an error message that a semaphore is being reinitialized. } p = semaphore_get_or_allocate(semaphore); p->value = value; return p; }
/** Called after sem_wait() finished. * @note Do not rely on the value of 'waited' -- some glibc versions do * not set it correctly. */ void semaphore_post_wait(const DrdThreadId tid, const Addr semaphore, const Bool waited) { struct semaphore_info* p; p = semaphore_get(semaphore); if (s_trace_semaphore) { VG_(message)(Vg_UserMsg, "[%d/%d] semaphore_post_wait 0x%lx", VG_(get_running_tid)(), thread_get_running_tid(), semaphore); } tl_assert(p->waiters > 0); p->waiters--; tl_assert(p->waiters >= 0); tl_assert(p->value >= 0); if (p->value == 0) { SemaphoreErrInfo sei = { semaphore }; VG_(maybe_record_error)(VG_(get_running_tid)(), SemaphoreErr, VG_(get_IP)(VG_(get_running_tid)()), "Invalid semaphore", &sei); return; } p->value--; tl_assert(p->value >= 0); if (p->last_sem_post_tid != tid && p->last_sem_post_tid != DRD_INVALID_THREADID) { tl_assert(p->last_sem_post_segment); thread_combine_vc2(tid, &p->last_sem_post_segment->vc); } thread_new_segment(tid); }
/** Called after sem_destroy(). */ void DRD_(semaphore_destroy)(const Addr semaphore) { struct semaphore_info* p; p = semaphore_get(semaphore); if (s_trace_semaphore) DRD_(trace_msg)("[%d] sem_destroy 0x%lx value %u", DRD_(thread_get_running_tid)(), semaphore, p ? p->value : 0); if (p == 0) { GenericErrInfo GEI = { .tid = DRD_(thread_get_running_tid)(), .addr = semaphore, }; VG_(maybe_record_error)(VG_(get_running_tid)(), GenericErr, VG_(get_IP)(VG_(get_running_tid)()), "Not a semaphore", &GEI); return; }
/** * Called after sem_wait() finished. * @note Do not rely on the value of 'waited' -- some glibc versions do * not set it correctly. */ void DRD_(semaphore_post_wait)(const DrdThreadId tid, const Addr semaphore, const Bool waited) { struct semaphore_info* p; Segment* sg; p = semaphore_get(semaphore); if (s_trace_semaphore) { VG_(message)(Vg_UserMsg, "[%d/%d] semaphore_wait 0x%lx value %u -> %u\n", VG_(get_running_tid)(), DRD_(thread_get_running_tid)(), semaphore, p ? p->value : 0, p ? p->value - 1 : 0); } if (p) { p->waiters--; p->value--; } /* * Note: if another thread destroyed and reinitialized a semaphore while * the current thread was waiting in sem_wait, p->waiters may have been * set to zero by DRD_(semaphore_initialize)() after * DRD_(semaphore_pre_wait)() has finished before * DRD_(semaphore_post_wait)() has been called. */ if (p == NULL || (int)p->value < 0 || (int)p->waiters < 0) { SemaphoreErrInfo sei = { DRD_(thread_get_running_tid)(), semaphore }; VG_(maybe_record_error)(VG_(get_running_tid)(), SemaphoreErr, VG_(get_IP)(VG_(get_running_tid)()), "Invalid semaphore", &sei); return; } if (p->waits_to_skip > 0) p->waits_to_skip--; else { sg = DRD_(segment_pop)(p); tl_assert(sg); if (sg) { if (p->last_sem_post_tid != tid && p->last_sem_post_tid != DRD_INVALID_THREADID) { DRD_(thread_new_segment_and_combine_vc)(tid, sg); } else DRD_(thread_new_segment)(tid); s_semaphore_segment_creation_count++; DRD_(sg_put)(sg); } } }