Bunch of pthread questions

I’ve got a few questions about pthreads:

  1. What is the proper way to handle EAGAIN errors from mutexes
    (muticies) and condvars? Do we wrap a while loop and spin on them?
    Sleep? Is it even possible to get this error? Right now I’m doing:

do {
error = pthread_mutex_lock (&lock);
} while (error == EAGAIN);

  1. If I want to destroy a condvar with threads blocked on it, I would do
    the following:

/* All threads in question use this mutex /
pthread_mutex_lock (&lock);
pthread_cond_broadcast (&cond);
/
Are the threads all off the condvar??? /
pthread_cond_destroy (&cond); /
EOK or EBUSY??? */
pthread_mutex_unlock (&lock);

My question is whether the broadcast boots all threads off the condvar
immediately or just the first one which signals the next which signals
the next, etc…? In one case, the above code should work as intended,
in the other, I would get an EBUSY on the destroy.

  1. If I manually allocate a stack for a thread, is there a way I can
    make the thread free it’s stack when it dies? The problem is, releasing
    the stack too soon will cause an insidious memory fault / scribbler. How
    does NTO pull it off with the automatically allocated stacks?

Daryl Low

lodar@postoffice.pacbell.net wrote:

I’ve got a few questions about pthreads:

  1. What is the proper way to handle EAGAIN errors from mutexes
    (muticies) and condvars? Do we wrap a while loop and spin on them?
    Sleep? Is it even possible to get this error? Right now I’m doing:

do {
error = pthread_mutex_lock (&lock);
} while (error == EAGAIN);

That’s the usual way. And yes, it can actually happen.

  1. If I want to destroy a condvar with threads blocked on it, I would do
    the following:

/* All threads in question use this mutex /
pthread_mutex_lock (&lock);
pthread_cond_broadcast (&cond);
/
Are the threads all off the condvar??? /
pthread_cond_destroy (&cond); /
EOK or EBUSY??? */
pthread_mutex_unlock (&lock);

My question is whether the broadcast boots all threads off the condvar
immediately or just the first one which signals the next which signals
the next, etc…? In one case, the above code should work as intended,
in the other, I would get an EBUSY on the destroy.

pthread_cond_wait() unlocks the mutex when called AND locks the mutex
again before returning. Which means, only one of threads called it will
wake up, since they all will want to lock the same mutex. So, after a
broadcast threads will wake up serially and only if/when other threads
are nice enough to unlock it.

  1. If I manually allocate a stack for a thread, is there a way I can
    make the thread free it’s stack when it dies? The problem is, releasing
    the stack too soon will cause an insidious memory fault / scribbler. How
    does NTO pull it off with the automatically allocated stacks?

don’t know.

  • igor

In article <39CE7D9D.14EC79CE@postoffice.pacbell.net>,
<lodar@pacbell.net> wrote:

I’ve got a few questions about pthreads:

  1. What is the proper way to handle EAGAIN errors from mutexes
    (muticies) and condvars? Do we wrap a while loop and spin on them?
    Sleep? Is it even possible to get this error? Right now I’m doing:

do {
error = pthread_mutex_lock (&lock);
} while (error == EAGAIN);

Hmm. I have never seen an EAGAIN with a mutex. It isn’t supposed
to be a valid return (under POSIX, IEEE 1003.1-200x is slightly different).
There are only two situations for which I could imagine EAGAIN being returned:

  1. You use recursive mutexes and you have exceeded the maximum
    recursion level.

(I strongly recommend never using recursive mutexes, due to the
increased likelihood of deadlock. Perhaps that’s why I’ve never
seen it.)

  1. You are using a mutex for the first time, and the kernel can’t
    create a shadow structure for the mutex.

NB. This shouldn’t happen – because an EAGAIN should have
been returned on pthread_mutex_init – but if you use
a statically allocated mutex (i.e. with static or extern
storage class, initialized to PTHREAD_MUTEX_INITIALIZER)
the spec is almost silent on how it should behave if there aren’t
enough kernel resources.

NBB. Failure in this case should return EINVAL on the
pthread_mutex_lock, although I can’t guarantee this is the case.

  1. If I want to destroy a condvar with threads blocked on it, I would do
    the following:

/* All threads in question use this mutex /
pthread_mutex_lock (&lock);
pthread_cond_broadcast (&cond);
/
Are the threads all off the condvar??? /
pthread_cond_destroy (&cond); /
EOK or EBUSY??? */
pthread_mutex_unlock (&lock);

My question is whether the broadcast boots all threads off the condvar
immediately or just the first one which signals the next which signals
the next, etc…? In one case, the above code should work as intended,
in the other, I would get an EBUSY on the destroy.

As Igor said, none of the the other threads will awaken until you
unlock the mutex. After that, all of them will get the signal, but
when they get to run is dependent on competition for the mutex.
Note, however, that they will all go from COND_WAIT to MUTEX_WAIT,
so in theory, what you are doing is safe and any subsequent access to
that condvar would return EINVAL.

You can test this. Immediately before and immediately after performing
the broadcast, but before releasing the mutex, do procfs calls to get the
status of each thread, or do a pidin from another shell. Any threads
that were in COND_WAIT for the condvar before should be in MUTEX_WAIT
on the current thread. If that is the case, the implementation is
correct.

  1. If I manually allocate a stack for a thread, is there a way I can
    make the thread free it’s stack when it dies? The problem is, releasing
    the stack too soon will cause an insidious memory fault / scribbler. How
    does NTO pull it off with the automatically allocated stacks?

Only with a reaper, since there will still be accesses to state information
on the stack during pthread_exit(), pthread_cancel(), or pthread_join().
If all your threads were joinable, you could unmap the stack after the
pthread_join(). With detached threads it’s more difficult, since the thread
would have to notify the reaper immediately before exiting.
The reaper would then have to wait until the thread was truly dead and unmap
the stack after consulting its own table of mapped stacks.

The kernel can handle stacks more easily, since it will unmap a detached
thread’s stack after all cancellation cleanup handlers and thread-specific
data destructors have been called inside pthread_exit(). Likewise
for joinable threads, it will unmap the stack after the return value
has been provided to the thread that called pthread_join(), which
in turn happens after cleanup.

Daryl Low

Steve Furr email: furr@qnx.com
QNX Software Systems, Ltd.

Steve Furr wrote:

In article <> 39CE7D9D.14EC79CE@postoffice.pacbell.net> >,
lodar@pacbell.net> > wrote:
I’ve got a few questions about pthreads:

  1. What is the proper way to handle EAGAIN errors from mutexes
    (muticies) and condvars? Do we wrap a while loop and spin on them?
    Sleep? Is it even possible to get this error? Right now I’m doing:

do {
error = pthread_mutex_lock (&lock);
} while (error == EAGAIN);

Hmm. I have never seen an EAGAIN with a mutex. It isn’t supposed
to be a valid return (under POSIX, IEEE 1003.1-200x is slightly different).
There are only two situations for which I could imagine EAGAIN being returned:

  1. You use recursive mutexes and you have exceeded the maximum
    recursion level.

(I strongly recommend never using recursive mutexes, due to the
increased likelihood of deadlock. Perhaps that’s why I’ve never
seen it.)

  1. You are using a mutex for the first time, and the kernel can’t
    create a shadow structure for the mutex.

NB. This shouldn’t happen – because an EAGAIN should have
been returned on pthread_mutex_init – but if you use
a statically allocated mutex (i.e. with static or extern
storage class, initialized to PTHREAD_MUTEX_INITIALIZER)
the spec is almost silent on how it should behave if there aren’t
enough kernel resources.

NBB. Failure in this case should return EINVAL on the
pthread_mutex_lock, although I can’t guarantee this is the case.

What happens if you’re in MUTEX waiting for another thread to unlock it,
and signal arrives?
It can also arrive when you’re in CONDVAR or SEM and POSIX books indeed
recommend wrapping those calls into loops.

  • igor