示例#1
0
/*
 * Acquire ticket lock. Increment the tail of the queue and use the original
 * value as the ticket value. Wait until the head of the queue equals the
 * ticket value. The futex used to wait depends on the ticket value in order
 * to avoid that all threads get woken up every time a ticket lock is
 * released. That last effect is sometimes called the "thundering herd"
 * effect.
 *
 * See also Nick Piggin, x86: FIFO ticket spinlocks, Linux kernel mailing list
 * (http://lkml.org/lkml/2007/11/1/125) for more info.
 */
static void acquire_sched_lock(struct sched_lock *p, ThreadId tid, SchedLockKind slk)
{
   unsigned ticket, futex_value;
   volatile unsigned *futex;
   SysRes sres;

   ticket = __sync_fetch_and_add(&p->tail, 1);
   futex = &p->futex[ticket & TL_FUTEX_MASK];
   if (s_debug)
      VG_(printf)("[%d/%d] acquire: ticket %d\n", VG_(getpid)(),
                  VG_(gettid)(), ticket);
   for (;;) {
      futex_value = *futex;
      __sync_synchronize();
      if (ticket == p->head)
         break;
      if (s_debug)
         VG_(printf)("[%d/%d] acquire: ticket %d - waiting until"
                     " futex[%ld] != %d\n", VG_(getpid)(),
                     VG_(gettid)(), ticket, (long)(futex - p->futex),
                     futex_value);
      sres = VG_(do_syscall3)(__NR_futex, (UWord)futex,
                              VKI_FUTEX_WAIT | VKI_FUTEX_PRIVATE_FLAG,
                              futex_value);
      if (sr_isError(sres) && sres._val != VKI_EAGAIN) {
         VG_(printf)("futex_wait() returned error code %ld\n", sres._val);
         vg_assert(False);
      }
   }
   __sync_synchronize();
   INNER_REQUEST(ANNOTATE_RWLOCK_ACQUIRED(p, /*is_w*/1));
   vg_assert(p->owner == 0);
   p->owner = VG_(gettid)();
}
示例#2
0
/* get a token */
void ML_(sema_down)( vg_sema_t *sema, Bool as_LL )
{
   HChar buf[2];
   Int ret;
   Int lwpid = VG_(gettid)();

   vg_assert(sema->owner_lwpid != lwpid); /* can't have it already */
   vg_assert(sema->pipe[0] != sema->pipe[1]);

  again:
   buf[0] = buf[1] = 0;
   ret = VG_(read)(sema->pipe[0], buf, 1);
   INNER_REQUEST(ANNOTATE_RWLOCK_ACQUIRED(sema, /*is_w*/1));

   if (ret != 1) 
      VG_(debugLog)(0, "scheduler", 
                       "VG_(sema_down): read returned %d\n", ret);

   if (ret == -VKI_EINTR)
      goto again;

   vg_assert(ret == 1);		/* should get exactly 1 token */
   vg_assert(buf[0] >= 'A' && buf[0] <= 'Z');
   vg_assert(buf[1] == 0);

   if (sema_char == 'Z') sema_char = 'A'; else sema_char++;

   sema->owner_lwpid = lwpid;
   sema->held_as_LL = as_LL;
}
示例#3
0
static void rwlock_wrlock(rwlock_t* p)
{
  while (1)
  {
    while (__sync_val_compare_and_swap(&p->locked, 0, 1) == 1)
      ;
    if (p->reader_count == 0)
      break;
    pthread_yield();
    __sync_fetch_and_sub(&p->locked, 1);
  }
  p->writer_count++;
  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);
  ANNOTATE_RWLOCK_ACQUIRED(p, 1);
}