Re: [PATCH] Futexes IV (Fast Lightweight Userspace Semaphores)

Peter Wächtler
2002-03-25T11:56:52Z

Rusty Russell wrote:

> On Mon, 25 Mar 2002 13:28:44 +1100
> Rusty Russell <rusty@rustcorp.com.au> wrote:
>
>>So the summary is: futexes not sufficient to implement pthreads
>>locking.
>>
>
> So let's go back to the more generic "exporting waitqueues to userspace" idea,
> with a twist: we use a userspace address as the identifier on the waitq, which
> gives us a unique identifier, but the kernel never actually derefs the
> pointer. (And in my prior kernel code I optimized it so that waking did an
> implicit remove; not sure it's a win, so assumed that was removed here).
>
> This gives code as below (Peter, Martin, please check):
>
> /* Assume we have the following operations:
>
> uwaitq_add(void *uaddr);
> uwaitq_remove(void *uaddr);
> uwaitq_wake(void *uaddr, int wake_all_flag);
> uwaitq_wait(relative timeout);
> */
> typedef struct
> {
> int counter;
> } pthread_mutex_t;
>
> typedef struct
> {
> int condition;
> } pthread_cond_t;
>

> int pthread_cond_signal(pthread_cond_t *cond)
> {
> return uwaitq_wake(cond, 0 /* WAKE_ONE */);
> }
>
> int pthread_cond_broadcast(pthread_cond_t *cond)
> {
> return uwaitq_wake(cond, 1 /* WAKE_ALL */);
> }
>
> static int __pthread_cond_wait(pthread_cond_t *cond,
> pthread_mutex_t *mutex,
> const struct timespec *reltime)
> {
> int ret;
>
> uwaitq_add(cond);
> futex_up(&mutex, 1);

Here another thread gets scheduled, calling signal/broadcast.
Since the former thread is already on the queue -> well done ;-)

> while ((ret = uwaitq_wait(reltime)) == 0 || errno == EINTR);
> uwaitq_remove(cond);
> futex_down(&mutex, NULL);
> return ret;
> }

I assume that uwaitq_wait() will modify the reltime (which is legal)
if signalled. Otherwise we would wait 2*retime, and so on

Then we have to be careful about errno and the return values:

static int __pthread_cond_wait(pthread_cond_t *cond,
pthread_mutex_t *mutex,
const struct timespec *reltime)
{
int ret;

!
if (uwaitq_add(cond) == -1)
+
return -1;
!
if (futex_up(&mutex, 1) == -1){
+
uwaitq_remove(cond);
+
return -1;
+
}
!
while ((ret = uwaitq_wait(cond,reltime)) == -1 && errno == EINTR);
+
saverrno=errno;
uwaitq_remove(cond);
futex_down(&mutex, NULL);
+
if (ret == -1){
+
if (saverrno == ENOENT)
+
return 0; /* there was a sig/broadc before we went to sleep*/
+
errno=saverrno;
+
return -1;
+
}
return 0;
}

I assume that uwaitq_wait() will return -1 and errno==ENOENT or similar
if we are not on the queue (anymore), -1 and ETIMEDOUT on timeout,
-1 and EINVAL on illegal cond or reltime ,zero on wakeup?