Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <alpine.LNX.2.00.1408280026590.6544@monopod.intra.ispras.ru>
Date: Thu, 28 Aug 2014 01:06:36 +0400 (MSK)
From: Alexander Monakov <amonakov@...ras.ru>
To: musl@...ts.openwall.com
Subject: Re: sem_getvalue conformance considerations



On Wed, 27 Aug 2014, Alexander Monakov wrote:

> On IRC Rich noted that I've too conveniently elided cancellation, so here's how
> I think cancellation handler should look like:

s/cancellation handler/"unwait" procedure/: returning with EINTR is botched in
my earlier mail and should employ the same procedure to undo state change

>   val = sem->val[0];
>   while (val < 0) {
>     /* We believe we are a waiter that no sem_post has "seen".  */
>     oldval = val;
>     if ((val = a_cas(sem->val, val, val+1)) == oldval)
>       return;
>   }
>   /* We are a waiter, and a non-negative val[0] indicates that one sem_post
>    * noticed us.  Consume the corresponding wake count increment.  */
>   a_dec(sem->val+1);

A plain atomic decrement on wake count like above is not correct.  However:

1. I think it's correct as long as no new waiters appear while we are
performing unwait.  If new waiters are matched by new posts it's ok; we only
care if the amount of new waiters is higher than the amount of new posts, as
then we are risking to cause a missing wake for one of those, or setting wake
count to -1 if they all consume wakes before we do the increment.

2. Thus it needs a fancy atomic op: decrement val[1] if val[0] is still equal
to "val" we retrieved earlier.  Otherwise, retry from the beginning.

Futhermore, doing the above in a true atomic fashion might not be required!
Isn't it okay to decrement wake count, and if we observe new waiters,
increment it back and cause a futex wake?  Thus:

retry:
  val = sem->val[0];
  while (val < 0) {
    /* We believe we are a waiter that no sem_post has "seen".  */
    oldval = val;
    if ((val = a_cas(sem->val, val, val+1)) == oldval)
      return;
  }
  /* We are a waiter, and a non-negative val[0] indicates that one sem_post
   * noticed us.  Consume the corresponding wake count increment.  */
  a_dec(sem->val+1);
  if (val > sem->val[0]) {
    /* New waiters appeared.  Avoid causing a missing wake and restart.  We
     * don't enter here if more new posts are posted than new waiters come. */
    a_inc(sem->val+1);
    futex_wake(sem->val+1, 1);
    goto retry;
  }


Alexander

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.