am 0d3700d9: Merge "Only have one copy of the kernel_sigset_t hack, and add more tests."
				
					
				
			* commit '0d3700d957debe841c385f66a8026ca8b3755815': Only have one copy of the kernel_sigset_t hack, and add more tests.
This commit is contained in:
		@@ -222,7 +222,6 @@ libc_common_src_files := \
 | 
			
		||||
	bionic/signame.c \
 | 
			
		||||
	bionic/sigsetmask.c \
 | 
			
		||||
	bionic/sigsuspend.c \
 | 
			
		||||
	bionic/sigwait.c \
 | 
			
		||||
	bionic/sleep.c \
 | 
			
		||||
	bionic/statfs.c \
 | 
			
		||||
	bionic/strcoll.c \
 | 
			
		||||
@@ -281,10 +280,12 @@ libc_bionic_src_files := \
 | 
			
		||||
    bionic/__memcpy_chk.cpp \
 | 
			
		||||
    bionic/__memmove_chk.cpp \
 | 
			
		||||
    bionic/__memset_chk.cpp \
 | 
			
		||||
    bionic/pthread_sigmask.cpp \
 | 
			
		||||
    bionic/raise.cpp \
 | 
			
		||||
    bionic/__set_errno.cpp \
 | 
			
		||||
    bionic/setlocale.cpp \
 | 
			
		||||
    bionic/signalfd.cpp \
 | 
			
		||||
    bionic/sigwait.cpp \
 | 
			
		||||
    bionic/__strcat_chk.cpp \
 | 
			
		||||
    bionic/__strcpy_chk.cpp \
 | 
			
		||||
    bionic/strerror.cpp \
 | 
			
		||||
 
 | 
			
		||||
@@ -2099,58 +2099,6 @@ int pthread_kill(pthread_t tid, int sig)
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Despite the fact that our kernel headers define sigset_t explicitly
 | 
			
		||||
 * as a 32-bit integer, the kernel system call really expects a 64-bit
 | 
			
		||||
 * bitmap for the signal set, or more exactly an array of two-32-bit
 | 
			
		||||
 * values (see $KERNEL/arch/$ARCH/include/asm/signal.h for details).
 | 
			
		||||
 *
 | 
			
		||||
 * Unfortunately, we cannot fix the sigset_t definition without breaking
 | 
			
		||||
 * the C library ABI, so perform a little runtime translation here.
 | 
			
		||||
 */
 | 
			
		||||
typedef union {
 | 
			
		||||
    sigset_t   bionic;
 | 
			
		||||
    uint32_t   kernel[2];
 | 
			
		||||
} kernel_sigset_t;
 | 
			
		||||
 | 
			
		||||
/* this is a private syscall stub */
 | 
			
		||||
extern int __rt_sigprocmask(int, const kernel_sigset_t *, kernel_sigset_t *, size_t);
 | 
			
		||||
 | 
			
		||||
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
 | 
			
		||||
{
 | 
			
		||||
    /* pthread_sigmask must return the error code, but the syscall
 | 
			
		||||
     * will set errno instead and return 0/-1
 | 
			
		||||
     */
 | 
			
		||||
    int ret, old_errno = errno;
 | 
			
		||||
 | 
			
		||||
    /* We must convert *set into a kernel_sigset_t */
 | 
			
		||||
    kernel_sigset_t  in_set, *in_set_ptr;
 | 
			
		||||
    kernel_sigset_t  out_set;
 | 
			
		||||
 | 
			
		||||
    in_set.kernel[0] = in_set.kernel[1] = 0;
 | 
			
		||||
    out_set.kernel[0] = out_set.kernel[1] = 0;
 | 
			
		||||
 | 
			
		||||
    /* 'in_set_ptr' is the second parameter to __rt_sigprocmask. It must be NULL
 | 
			
		||||
     * if 'set' is NULL to ensure correct semantics (which in this case would
 | 
			
		||||
     * be to ignore 'how' and return the current signal set into 'oset'.
 | 
			
		||||
     */
 | 
			
		||||
    if (set == NULL) {
 | 
			
		||||
        in_set_ptr = NULL;
 | 
			
		||||
    } else {
 | 
			
		||||
        in_set.bionic = *set;
 | 
			
		||||
        in_set_ptr = &in_set;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = __rt_sigprocmask(how, in_set_ptr, &out_set, sizeof(kernel_sigset_t));
 | 
			
		||||
    if (ret < 0)
 | 
			
		||||
        ret = errno;
 | 
			
		||||
 | 
			
		||||
    if (oset)
 | 
			
		||||
        *oset = out_set.bionic;
 | 
			
		||||
 | 
			
		||||
    errno = old_errno;
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int pthread_getcpuclockid(pthread_t  tid, clockid_t  *clockid)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										62
									
								
								libc/bionic/pthread_sigmask.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								libc/bionic/pthread_sigmask.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2008 The Android Open Source Project
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 *  * Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 *  * Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in
 | 
			
		||||
 *    the documentation and/or other materials provided with the
 | 
			
		||||
 *    distribution.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | 
			
		||||
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | 
			
		||||
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
			
		||||
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 | 
			
		||||
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
			
		||||
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 | 
			
		||||
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 | 
			
		||||
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | 
			
		||||
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 | 
			
		||||
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
 | 
			
		||||
#include <private/kernel_sigset_t.h>
 | 
			
		||||
 | 
			
		||||
extern "C" int __rt_sigprocmask(int, const kernel_sigset_t*, kernel_sigset_t*, size_t);
 | 
			
		||||
 | 
			
		||||
int pthread_sigmask(int how, const sigset_t* iset, sigset_t* oset) {
 | 
			
		||||
  int old_errno = errno;
 | 
			
		||||
 | 
			
		||||
  // 'in_set_ptr' is the second parameter to __rt_sigprocmask. It must be NULL
 | 
			
		||||
  // if 'set' is NULL to ensure correct semantics (which in this case would
 | 
			
		||||
  // be to ignore 'how' and return the current signal set into 'oset').
 | 
			
		||||
  kernel_sigset_t in_set;
 | 
			
		||||
  kernel_sigset_t* in_set_ptr = NULL;
 | 
			
		||||
  if (iset != NULL) {
 | 
			
		||||
    in_set.set(iset);
 | 
			
		||||
    in_set_ptr = &in_set;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  kernel_sigset_t out_set;
 | 
			
		||||
  int result = __rt_sigprocmask(how, in_set_ptr, &out_set, sizeof(out_set));
 | 
			
		||||
  if (result < 0) {
 | 
			
		||||
    result = errno;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (oset != NULL) {
 | 
			
		||||
    *oset = out_set.bionic;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  errno = old_errno;
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
@@ -28,27 +28,11 @@
 | 
			
		||||
 | 
			
		||||
#include <sys/signalfd.h>
 | 
			
		||||
 | 
			
		||||
/* Despite the fact that our kernel headers define sigset_t explicitly
 | 
			
		||||
 * as a 32-bit integer, the kernel system call really expects a 64-bit
 | 
			
		||||
 * bitmap for the signal set, or more exactly an array of two-32-bit
 | 
			
		||||
 * values (see $KERNEL/arch/$ARCH/include/asm/signal.h for details).
 | 
			
		||||
 *
 | 
			
		||||
 * Unfortunately, we cannot fix the sigset_t definition without breaking
 | 
			
		||||
 * the C library ABI, so perform a little runtime translation here.
 | 
			
		||||
 */
 | 
			
		||||
typedef union {
 | 
			
		||||
    sigset_t   bionic;
 | 
			
		||||
    uint32_t   kernel[2];
 | 
			
		||||
} kernel_sigset_t;
 | 
			
		||||
#include <private/kernel_sigset_t.h>
 | 
			
		||||
 | 
			
		||||
extern "C" int signalfd4(int fd, kernel_sigset_t *mask, size_t sizemask, int flags);
 | 
			
		||||
extern "C" int signalfd4(int fd, kernel_sigset_t* mask, size_t sizemask, int flags);
 | 
			
		||||
 | 
			
		||||
int signalfd(int fd, const sigset_t *mask, int flags)
 | 
			
		||||
{
 | 
			
		||||
    kernel_sigset_t in_set;
 | 
			
		||||
    in_set.kernel[0] = in_set.kernel[1] = 0;
 | 
			
		||||
 | 
			
		||||
    in_set.bionic = *mask;
 | 
			
		||||
 | 
			
		||||
    return signalfd4(fd, &in_set, sizeof(in_set), flags);
 | 
			
		||||
int signalfd(int fd, const sigset_t* mask, int flags) {
 | 
			
		||||
  kernel_sigset_t in_set(mask);
 | 
			
		||||
  return signalfd4(fd, &in_set, sizeof(in_set), flags);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,59 +25,29 @@
 | 
			
		||||
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <signal.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
 | 
			
		||||
int __rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, const struct timespec *uts, size_t sigsetsize);
 | 
			
		||||
#include <private/kernel_sigset_t.h>
 | 
			
		||||
 | 
			
		||||
/* ok, this is really subtle: <asm/signal.h> defines sigset_t differently
 | 
			
		||||
 * when you're in the kernel or in the C library.
 | 
			
		||||
 *
 | 
			
		||||
 * in the kernel, this is an array of 2 32-bit unsigned longs
 | 
			
		||||
 * in the C library, this is a single 32-bit unsigned long
 | 
			
		||||
 *
 | 
			
		||||
 * moreover, the kernel implementation of rt_sigtimedwait doesn't
 | 
			
		||||
 * accept anything except kernel-sized signal sets (probably a bug !)
 | 
			
		||||
 *
 | 
			
		||||
 * we thus need to create a fake kernel sigset !!
 | 
			
		||||
 */
 | 
			
		||||
extern "C" int __rt_sigtimedwait(const sigset_t* uthese, siginfo_t* uinfo, const struct timespec* uts, size_t sigsetsize);
 | 
			
		||||
 | 
			
		||||
int sigwait(const sigset_t *set, int *sig)
 | 
			
		||||
{
 | 
			
		||||
    int  ret;
 | 
			
		||||
#ifdef __mips__
 | 
			
		||||
    /* use a union to get rid of aliasing warnings. On MIPS sigset_t is 128 bits */
 | 
			
		||||
    union {
 | 
			
		||||
      sigset_t       kernel_sigset;
 | 
			
		||||
      sigset_t       dummy_sigset;
 | 
			
		||||
    } u;
 | 
			
		||||
    u.dummy_sigset = *set;
 | 
			
		||||
#else
 | 
			
		||||
    /* use a union to get rid of aliasing warnings */
 | 
			
		||||
    union {
 | 
			
		||||
      unsigned long  kernel_sigset[2];
 | 
			
		||||
      sigset_t       dummy_sigset;
 | 
			
		||||
    } u;
 | 
			
		||||
 | 
			
		||||
    u.kernel_sigset[0] = *set;
 | 
			
		||||
    u.kernel_sigset[1] = 0;  /* no real-time signals supported ? */
 | 
			
		||||
#endif
 | 
			
		||||
    for (;;)
 | 
			
		||||
    {
 | 
			
		||||
     /* __rt_sigtimedwait can return EAGAIN or EINTR, we need to loop
 | 
			
		||||
      * around them since sigwait is only allowed to return EINVAL
 | 
			
		||||
      */
 | 
			
		||||
      ret = __rt_sigtimedwait ( &u.dummy_sigset, NULL, NULL, sizeof(u.kernel_sigset));
 | 
			
		||||
      if (ret >= 0)
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
      if (errno != EAGAIN && errno != EINTR)
 | 
			
		||||
        return errno;
 | 
			
		||||
int sigwait(const sigset_t* set, int* sig) {
 | 
			
		||||
  kernel_sigset_t sigset(set);
 | 
			
		||||
  while (true) {
 | 
			
		||||
    // __rt_sigtimedwait can return EAGAIN or EINTR, we need to loop
 | 
			
		||||
    // around them since sigwait is only allowed to return EINVAL.
 | 
			
		||||
    int result = __rt_sigtimedwait(sigset.get(), NULL, NULL, sizeof(sigset));
 | 
			
		||||
    if (result >= 0) {
 | 
			
		||||
      *sig = result;
 | 
			
		||||
      return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *sig = ret;
 | 
			
		||||
    return 0;
 | 
			
		||||
    if (errno != EAGAIN && errno != EINTR) {
 | 
			
		||||
      return errno;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										52
									
								
								libc/private/kernel_sigset_t.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								libc/private/kernel_sigset_t.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2013 The Android Open Source Project
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef LIBC_PRIVATE_KERNEL_SIGSET_T_H_
 | 
			
		||||
#define LIBC_PRIVATE_KERNEL_SIGSET_T_H_
 | 
			
		||||
 | 
			
		||||
// Our sigset_t is wrong for ARM and x86. It's 32-bit but the kernel expects 64 bits.
 | 
			
		||||
// This means we can't support real-time signals correctly until we can change the ABI.
 | 
			
		||||
// In the meantime, we can use this union to pass an appropriately-sized block of memory
 | 
			
		||||
// to the kernel, at the cost of not being able to refer to real-time signals.
 | 
			
		||||
union kernel_sigset_t {
 | 
			
		||||
  kernel_sigset_t() {
 | 
			
		||||
    clear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  kernel_sigset_t(const sigset_t* value) {
 | 
			
		||||
    clear();
 | 
			
		||||
    set(value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void clear() {
 | 
			
		||||
    memset(this, 0, sizeof(*this));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void set(const sigset_t* value) {
 | 
			
		||||
    bionic = *value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  sigset_t* get() {
 | 
			
		||||
    return &bionic;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  sigset_t bionic;
 | 
			
		||||
#ifndef __mips__
 | 
			
		||||
  uint32_t kernel[2];
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -126,3 +126,31 @@ TEST(pthread_DeathTest, pthread_bug_37410) {
 | 
			
		||||
  EXPECT_EXIT(TestBug37410(), ::testing::ExitedWithCode(0), "");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void* SignalHandlerFn(void* arg) {
 | 
			
		||||
  sigset_t wait_set;
 | 
			
		||||
  sigfillset(&wait_set);
 | 
			
		||||
  return reinterpret_cast<void*>(sigwait(&wait_set, reinterpret_cast<int*>(arg)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(pthread, pthread_sigmask) {
 | 
			
		||||
  // Block SIGUSR1.
 | 
			
		||||
  sigset_t set;
 | 
			
		||||
  sigemptyset(&set);
 | 
			
		||||
  sigaddset(&set, SIGUSR1);
 | 
			
		||||
  ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &set, NULL));
 | 
			
		||||
 | 
			
		||||
  // Spawn a thread that calls sigwait and tells us what it received.
 | 
			
		||||
  pthread_t signal_thread;
 | 
			
		||||
  int received_signal = -1;
 | 
			
		||||
  ASSERT_EQ(0, pthread_create(&signal_thread, NULL, SignalHandlerFn, &received_signal));
 | 
			
		||||
 | 
			
		||||
  // Send that thread SIGUSR1.
 | 
			
		||||
  pthread_kill(signal_thread, SIGUSR1);
 | 
			
		||||
 | 
			
		||||
  // See what it got.
 | 
			
		||||
  void* join_result;
 | 
			
		||||
  ASSERT_EQ(0, pthread_join(signal_thread, &join_result));
 | 
			
		||||
  ASSERT_EQ(SIGUSR1, received_signal);
 | 
			
		||||
  ASSERT_EQ(0, reinterpret_cast<int>(join_result));
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -101,3 +101,27 @@ TEST(signal, raise_invalid) {
 | 
			
		||||
  ASSERT_EQ(-1, raise(-1));
 | 
			
		||||
  ASSERT_EQ(EINVAL, errno);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void HandleSIGALRM(int signal_number) {
 | 
			
		||||
  ASSERT_EQ(SIGALRM, signal_number);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
TEST(signal, sigwait) {
 | 
			
		||||
  struct sigaction action;
 | 
			
		||||
  sigemptyset(&action.sa_mask);
 | 
			
		||||
  action.sa_flags = 0;
 | 
			
		||||
  action.sa_handler = HandleSIGALRM;
 | 
			
		||||
  sigaction(SIGALRM, &action, NULL);
 | 
			
		||||
 | 
			
		||||
  sigset_t wait_set;
 | 
			
		||||
  sigemptyset(&wait_set);
 | 
			
		||||
  sigaddset(&wait_set, SIGALRM);
 | 
			
		||||
 | 
			
		||||
  alarm(1);
 | 
			
		||||
 | 
			
		||||
  int received_signal;
 | 
			
		||||
  errno = 0;
 | 
			
		||||
  ASSERT_EQ(0, sigwait(&wait_set, &received_signal));
 | 
			
		||||
  ASSERT_EQ(0, errno);
 | 
			
		||||
  ASSERT_EQ(SIGALRM, received_signal);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user