/* * Release a ticket lock by incrementing the head of the queue. Only generate * a thread wakeup signal if at least one thread is waiting. If the queue tail * matches the wakeup_ticket value, no threads have to be woken up. * * Note: tail will only be read after head has been incremented since both are * declared as volatile and since the __sync...() functions imply a memory * barrier. */ static void release_sched_lock(struct sched_lock *p, ThreadId tid, SchedLockKind slk) { unsigned wakeup_ticket, futex_value; volatile unsigned *futex; SysRes sres; vg_assert(p->owner != 0); p->owner = 0; INNER_REQUEST(ANNOTATE_RWLOCK_RELEASED(p, /*is_w*/1)); wakeup_ticket = __sync_fetch_and_add(&p->head, 1) + 1; if (p->tail != wakeup_ticket) { futex = &p->futex[wakeup_ticket & TL_FUTEX_MASK]; futex_value = __sync_fetch_and_add(futex, 1); if (s_debug) VG_(printf)("[%d/%d] release: waking up ticket %d (futex[%ld] = %d)" "\n", VG_(getpid)(), VG_(gettid)(), wakeup_ticket, (long)(futex - p->futex), futex_value); sres = VG_(do_syscall3)(__NR_futex, (UWord)futex, VKI_FUTEX_WAKE | VKI_FUTEX_PRIVATE_FLAG, 0x7fffffff); vg_assert(!sr_isError(sres)); } else { if (s_debug) VG_(printf)("[%d/%d] release: no thread is waiting for ticket %d\n", VG_(getpid)(), VG_(gettid)(), wakeup_ticket); } }
static void rwlock_unlock(rwlock_t* p) { while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1) ; if (p->reader_count > 0) { p->reader_count--; ANNOTATE_RWLOCK_RELEASED(p, 0); } else { p->writer_count--; ANNOTATE_RWLOCK_RELEASED(p, 1); } assert(p->reader_count >= 0); assert(p->writer_count >= 0); assert(p->reader_count == 0 || p->writer_count == 0); __sync_fetch_and_sub(&p->locked, 1); }
/* put token back */ void ML_(sema_up)( vg_sema_t *sema, Bool as_LL ) { Int ret; HChar buf[2]; vg_assert(as_LL == sema->held_as_LL); buf[0] = sema_char; buf[1] = 0; vg_assert(sema->owner_lwpid != -1); /* must be initialised */ vg_assert(sema->pipe[0] != sema->pipe[1]); vg_assert(sema->owner_lwpid == VG_(gettid)()); /* must have it */ sema->owner_lwpid = 0; INNER_REQUEST(ANNOTATE_RWLOCK_RELEASED(sema, /*is_w*/1)); ret = VG_(write)(sema->pipe[1], buf, 1); if (ret != 1) VG_(debugLog)(0, "scheduler", "VG_(sema_up):write returned %d\n", ret); vg_assert(ret == 1); }