svn commit: r249566 - in head: lib/libc/gen sys/kern

Jilles Tjoelker jilles at stack.nl
Tue Apr 16 21:15:07 UTC 2013


On Tue, Apr 16, 2013 at 08:26:31PM +0000, John Baldwin wrote:
> Author: jhb
> Date: Tue Apr 16 20:26:31 2013
> New Revision: 249566
> URL: http://svnweb.freebsd.org/changeset/base/249566

> Log:
>   - Document that sem_wait() can fail with EINTR if it is interrupted by a
>     signal.
>   - Fix the old ksem implementation for POSIX semaphores to not restart
>     sem_wait() or sem_timedwait() if interrupted by a signal.

>   MFC after:	1 week

> Modified:
>   head/lib/libc/gen/sem_wait.3
>   head/sys/kern/uipc_sem.c

> Modified: head/lib/libc/gen/sem_wait.3
> ==============================================================================
> --- head/lib/libc/gen/sem_wait.3	Tue Apr 16 20:21:02 2013	(r249565)
> +++ head/lib/libc/gen/sem_wait.3	Tue Apr 16 20:26:31 2013	(r249566)
> @@ -27,7 +27,7 @@
>  .\"
>  .\" $FreeBSD$
>  .\"
> -.Dd February 15, 2000
> +.Dd April 16, 2013
>  .Dt SEM_WAIT 3
>  .Os
>  .Sh NAME
> @@ -75,6 +75,14 @@ points to an invalid semaphore.
>  .El
>  .Pp
>  Additionally,
> +.Fn sem_wait
> +will fail if:
> +.Bl -tag -width Er
> +.Pp
> +.It Bq Er EINTR
> +A signal interrupted this function.
> +.El
> +Additionally,
>  .Fn sem_trywait
>  will fail if:
>  .Bl -tag -width Er
> 
> Modified: head/sys/kern/uipc_sem.c
> ==============================================================================
> --- head/sys/kern/uipc_sem.c	Tue Apr 16 20:21:02 2013	(r249565)
> +++ head/sys/kern/uipc_sem.c	Tue Apr 16 20:26:31 2013	(r249566)
> @@ -846,6 +846,8 @@ kern_sem_wait(struct thread *td, semid_t
>  err:
>  	mtx_unlock(&sem_lock);
>  	fdrop(fp, td);
> +	if (error == ERESTART)
> +		error = EINTR;
>  	DP(("<<< kern_sem_wait leaving, pid=%d, error = %d\n",
>  	    (int)td->td_proc->p_pid, error));
>  	return (error);

It would normally be expected (and required by POSIX) that a signal with
SA_RESTART set does not cause a function to fail with [EINTR], so more
rationale is needed here.

Also, the timeouts passed to these functions are absolute and also are
at the system call level except UMTX_OP_SEM_WAIT which can take a
relative or an absolute timeout but libc passed it an absolute timeout.
So there is no need for a caller to see [EINTR] to avoid overlong
timeouts.

Given the number of times people call sem_wait() without checking the
return value, call sem_wait() and assume any error is fatal or call
sem_timedwait() and assume any error is a timeout, I think it may be
better to go the other way and never fail with [EINTR], just like the
pthread functions. POSIX explicitly permits this: the [EINTR] error for
sem_wait(), sem_trywait() and sem_timedwait() is "may fail" rather than
the usual "shall fail" (note that SA_RESTART overrides such a "shall
fail" unless there is a relative timeout or it is explicitly excluded
with the function).

I realize that this reduces functionality, but relying on [EINTR] here
introduces a race condition anyway (because the signal handler may be
called just before sem_wait() blocks). I suggest pthread cancellation,
not returning from the signal handler or leaving the default
action in place (if it is termination). The racy functionality can be
kept by leaving [EINTR] and [ERESTART] from the sleep function as they
are except for changing [ERESTART] to [EINTR] when UMTX_OP_SEM_WAIT was
passed a relative timeout. Breakage in programs that check sem_wait()'s
return value incorrectly will then be less frequent and only present
when POSIX permits it.

-- 
Jilles Tjoelker


More information about the svn-src-head mailing list