threads/154893: pthread_sigmask don't work if mask and oldmask are passed the same pointer

KOSAKI Motohiro kosaki.motohiro at gmail.com
Sat Feb 19 19:54:40 UTC 2011


Hi

> Note that POSIX requires the following prototypes for
> the sigprocmask and pthread_sigmask:
>
> int pthread_sigmask(int how, const sigset_t *restrict set,
>       sigset_t *restrict oset);
> int sigprocmask(int how, const sigset_t *restrict set,
>      sigset_t *restrict oset);

Ouch. right you are.

> The restrict keyword explicitely disallows the case of set == oset,
> so I think the behaviour is undefined by POSIX, and our implementation
> is correct.

I agree.

> On the other hand, pthread_sigmask(3) manpage needs update to add
> restrict, and include/signal.h also ought to be changed.

OK, thanks.


>> Then, if set == oset, set argument was override before use it at (1).
>> To introduce temporary variable fix this issue easily.
> libc_r is unused. Real implementation is in lib/libthr, that already
> has a twist that would not allow the override for case of action !=
> SIG_UNBLOCK. Moreover, the kernel side of sigprocmask(2) implementation
> first copies new set into kernel VA, and only then copies old mask out.

Hmhm.


> Your example does not supply oset == set to the pthread_sigmask,
> meantime. I really do not see anything wrong with the output of
> the program that supposed to illustrate the issue.

Oh, I'm sorry. It's cut-n-paste mistake. I did paste old version
unintensionally.

void* func2(void* arg)
{
        sigset_t old;
        sigset_t add;
        int i;

        sigemptyset(&old);
        pthread_sigmask(SIG_BLOCK, NULL, &old);

        printf("before: ");
        for (i=0; i<4; i++)
                printf(" %08x", old.__bits[i]);
        printf("\n");

        sigemptyset(&add);
        sigaddset(&add, SIGUSR1);
        pthread_sigmask(SIG_BLOCK, &add, &add);
        pthread_sigmask(SIG_BLOCK, NULL, &old);

        printf("after:  ");
        for (i=0; i<4; i++)
                printf(" %08x", old.__bits[i]);
        printf("\n");

        return 0;
}

The result is,

correct case:
before:  00000000 00000000 00000000 00000000
after:   20000000 00000000 00000000 00000000
incorrect case:
before:  00000000 00000000 00000000 00000000
after:   00000000 00000000 00000000 00000000

difference between func and func2 are

-        pthread_sigmask(SIG_BLOCK, &add, NULL);
+        pthread_sigmask(SIG_BLOCK, &add, &add);

That said, To add oset changed sigprocmask() behavior significantly.


> The func() adds SIGUSR1 to the mask with second call to
> pthread_sigmask(SIG_BLOCK, &add, NULL);. Then, third call
> correctly returns SIGUSR1 in the mask.
>
> On the other hand, func2() sets SIGUSR1 as blocked and retrieves
> the previous mask in single atomic action. Since SIGUSR1 was not
> blocked before the call, old sigset correctly indicates it as
> "not blocked".

(snip)

> The only change that I see as needed now is the following cosmetics:
>
> commit 49287c24fc46f342b46db1fae3fe9982bfbf7ed9
> Author: Konstantin Belousov <kostik at pooma.home>
> Date:   Sat Feb 19 20:41:46 2011 +0200
>
>    Add restrict keyword to pthread_sigmask prototype and manpage
>
> diff --git a/include/signal.h b/include/signal.h
> index 4a4cd17..52a611c 100644
> --- a/include/signal.h
> +++ b/include/signal.h
> @@ -69,7 +69,8 @@ int   raise(int);
>  #if __POSIX_VISIBLE || __XSI_VISIBLE
>  int    kill(__pid_t, int);
>  int    pthread_kill(__pthread_t, int);
> -int    pthread_sigmask(int, const __sigset_t *, __sigset_t *);
> +int    pthread_sigmask(int, const __sigset_t *__restrict,
> +           __sigset_t * __restrict);
>  int    sigaction(int, const struct sigaction * __restrict,
>            struct sigaction * __restrict);
>  int    sigaddset(sigset_t *, int);
> diff --git a/share/man/man3/pthread_sigmask.3 b/share/man/man3/pthread_sigmask.3
> index c412543..013ba7c 100644
> --- a/share/man/man3/pthread_sigmask.3
> +++ b/share/man/man3/pthread_sigmask.3
> @@ -26,7 +26,7 @@
>  .\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>  .\"
>  .\" $FreeBSD$
> -.Dd April 27, 2000
> +.Dd February 19, 2011
>  .Dt PTHREAD_SIGMASK 3
>  .Os
>  .Sh NAME
> @@ -38,7 +38,8 @@
>  .In pthread.h
>  .In signal.h
>  .Ft int
> -.Fn pthread_sigmask "int how" "const sigset_t *set" "sigset_t *oset"
> +.Fn pthread_sigmask "int how" "const sigset_t * restrict set" \
> +    "sigset_t * restrict oset"
>  .Sh DESCRIPTION
>  The
>  .Fn pthread_sigmask

Looks good.


More information about the freebsd-threads mailing list