diff --git a/syscall/fs_syscall.c b/syscall/fs_syscall.c index 99dedeca..3e7b921c 100644 --- a/syscall/fs_syscall.c +++ b/syscall/fs_syscall.c @@ -2548,4 +2548,51 @@ int SysPpoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p, cons PointerFree(sigMaskbak); return (ret == -1) ? -get_errno() : ret; } + +int SysPselect6(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + const struct timespec *timeout, const long data[2]) +{ + int ret; + int retVal; + sigset_t_l origMask; + sigset_t_l setl; + + CHECK_ASPACE(readfds, sizeof(fd_set)); + CHECK_ASPACE(writefds, sizeof(fd_set)); + CHECK_ASPACE(exceptfds, sizeof(fd_set)); + CHECK_ASPACE(timeout, sizeof(struct timeval)); + + CPY_FROM_USER(readfds); + CPY_FROM_USER(writefds); + CPY_FROM_USER(exceptfds); + DUP_FROM_USER(timeout, sizeof(struct timeval)); + + ((struct timeval *)timeout)->tv_usec = timeout->tv_nsec / 1000; /* 1000, convert ns to us */ + + if (data != NULL) { + retVal = LOS_ArchCopyFromUser(&(setl.sig[0]), (int *)data[0], sizeof(sigset_t)); + if (retVal != 0) { + ret = -EFAULT; + FREE_DUP(timeout); + return ret; + } + } + + OsSigprocMask(SIG_SETMASK, &setl, &origMask); + ret = do_select(nfds, readfds, writefds, exceptfds, (struct timeval *)timeout, UserPoll); + if (ret < 0) { + /* do not copy parameter back to user mode if do_select failed */ + ret = -get_errno(); + FREE_DUP(timeout); + return ret; + } + OsSigprocMask(SIG_SETMASK, &origMask, NULL); + + CPY_TO_USER(readfds); + CPY_TO_USER(writefds); + CPY_TO_USER(exceptfds); + FREE_DUP(timeout); + + return ret; +} #endif diff --git a/syscall/los_syscall.h b/syscall/los_syscall.h index 106472cb..f50754b7 100644 --- a/syscall/los_syscall.h +++ b/syscall/los_syscall.h @@ -257,6 +257,8 @@ extern int SysIoctl(int fd, int req, void *arg); extern int SysFcntl(int fd, int cmd, void *arg); extern int SysDup2(int fd1, int fd2); extern int SysSelect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); +extern int SysPselect6(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + const struct timespec *timeout, const long data[2]); extern int SysTruncate(const char *path, off_t length); extern int SysFtruncate(int fd, off_t length); extern int SysStatfs(const char *path, struct statfs *buf); diff --git a/syscall/syscall_lookup.h b/syscall/syscall_lookup.h index da1ca1a7..559cb0b5 100644 --- a/syscall/syscall_lookup.h +++ b/syscall/syscall_lookup.h @@ -83,6 +83,7 @@ SYSCALL_HAND_DEF(__NR_fstatat64, SysFstatat64, int, ARG_NUM_4) SYSCALL_HAND_DEF(__NR_fsync, SysFsync, int, ARG_NUM_1) SYSCALL_HAND_DEF(__NR__llseek, SysLseek64, off64_t, ARG_NUM_5) /* current only support 32bit max 4G file */ SYSCALL_HAND_DEF(__NR__newselect, SysSelect, int, ARG_NUM_5) +SYSCALL_HAND_DEF(__NR_pselect6, SysPselect6, int, ARG_NUM_6) SYSCALL_HAND_DEF(__NR_readv, SysReadv, ssize_t, ARG_NUM_3) SYSCALL_HAND_DEF(__NR_writev, SysWritev, ssize_t, ARG_NUM_3) SYSCALL_HAND_DEF(__NR_poll, SysPoll, int, ARG_NUM_3) diff --git a/testsuites/unittest/IO/BUILD.gn b/testsuites/unittest/IO/BUILD.gn index e9095106..7eb948e4 100644 --- a/testsuites/unittest/IO/BUILD.gn +++ b/testsuites/unittest/IO/BUILD.gn @@ -85,6 +85,8 @@ sources_full = [ "full/IO_test_strncasecmp_l_002.cpp", "full/IO_test_ppoll_001.cpp", "full/IO_test_ppoll_002.cpp", + "full/IO_test_pselect_001.cpp", + "full/IO_test_pselect_002.cpp", ] if (LOSCFG_USER_TEST_LEVEL >= TEST_LEVEL_LOW) { diff --git a/testsuites/unittest/IO/It_test_IO.h b/testsuites/unittest/IO/It_test_IO.h index c64683df..5c763ca3 100644 --- a/testsuites/unittest/IO/It_test_IO.h +++ b/testsuites/unittest/IO/It_test_IO.h @@ -130,6 +130,7 @@ extern VOID IO_TEST_GETTEXT_001(VOID); extern VOID IO_TEST_PPOLL_001(void); extern VOID IO_TEST_PPOLL_002(void); extern VOID IO_TEST_PSELECT_001(void); +extern VOID IO_TEST_PSELECT_002(void); extern VOID IO_TEST_STRFMON_L_001(VOID); extern VOID IO_TEST_STRFMON_L_002(VOID); extern VOID IO_TEST_PPOLL_001(VOID); diff --git a/testsuites/unittest/IO/full/IO_test_pselect_001.cpp b/testsuites/unittest/IO/full/IO_test_pselect_001.cpp index 8cfbe3f5..d6cfa95d 100644 --- a/testsuites/unittest/IO/full/IO_test_pselect_001.cpp +++ b/testsuites/unittest/IO/full/IO_test_pselect_001.cpp @@ -36,34 +36,85 @@ #include #include "sys/select.h" +static UINT32 Testcase1(VOID) +{ + static const int TAR_STR_LEN = 12; /* 12, str len */ + int pipeFd[2], ret; /* 2, pipe return 2 file descirpter */ + fd_set reads; + ret = pipe(pipeFd); + ICUNIT_GOTO_EQUAL(ret, 0, ret, EXIT); + ret = write(pipeFd[1], "Hello World", TAR_STR_LEN); + ICUNIT_GOTO_EQUAL(ret, TAR_STR_LEN, ret, EXIT); + FD_ZERO(&reads); + FD_SET(pipeFd[0], &reads); + ret = select(pipeFd[0] + 1, &reads, nullptr, nullptr, nullptr); + ICUNIT_GOTO_EQUAL(ret, 1, ret, EXIT); + ret = FD_ISSET(pipeFd[0], &reads); + ICUNIT_GOTO_NOT_EQUAL(ret, 0, ret, EXIT); + close(pipeFd[0]); + close(pipeFd[1]); + return LOS_OK; +EXIT: + close(pipeFd[0]); + close(pipeFd[1]); + return LOS_NOK; +} + +#define V_SIGMASK 0x5555 static UINT32 testcase(VOID) { fd_set rfds; - //struct timeval tv; struct timespec tv; int retval; + pid_t pid; + int pipeFd[2]; /* 2, pipe id num */ + char buffer[40]; /* 40, buffer size */ + int i = 0; + int status; - /* Watch stdin (fd 0) to see when it has input. */ + sigset_t mask; + + retval = Testcase1(); /* first check select works */ + ICUNIT_GOTO_EQUAL(retval, 0, retval, OUT); + + retval = pipe(pipeFd); + ICUNIT_GOTO_EQUAL(retval, 0, retval, OUT); + + /* Watch fd to see when it has input. */ FD_ZERO(&rfds); - FD_SET(0, &rfds); + FD_SET(pipeFd[0], &rfds); /* Wait up to three seconds. */ - //tv.tv_sec = 3; - //tv.tv_usec = 0; - tv.tv_sec = 3; - tv.tv_nsec = 0; + tv.tv_sec = 3; /* 3, wait timer, second */ + tv.tv_nsec = 5; /* 5, wait timer, nano second */ - retval = pselect(1, &rfds, nullptr, nullptr, &tv, ((long[]){ 0, _NSIG/8 })); + pid = fork(); + if (pid == 0) { + close(pipeFd[1]); - if (retval == -1) { - perror("select()"); - } else if (retval) { - printf("Data is available now.\n"); - } else { /* FD_ISSET(0, &rfds) will be true. */ - printf("No data within three seconds.\n"); + retval = pselect(pipeFd[0] + 1, &rfds, nullptr, nullptr, &tv, &mask); + close(pipeFd[0]); + + if (retval) { + exit(LOS_OK); + } else { + exit(LOS_NOK); + } + } else { + sleep(1); + close(pipeFd[0]); + retval = write(pipeFd[1], "0123456789012345678901234567890123456789", 40); /* write 40 bytes to stdin(fd 0) */ + ICUNIT_GOTO_EQUAL(retval, 40, retval, OUT); + close(pipeFd[1]); + + wait(&status); + status = WEXITSTATUS(status); + ICUNIT_ASSERT_EQUAL(status, LOS_OK, status); } return LOS_OK; +OUT: + return LOS_NOK; } VOID IO_TEST_PSELECT_001(VOID) diff --git a/testsuites/unittest/IO/full/IO_test_pselect_002.cpp b/testsuites/unittest/IO/full/IO_test_pselect_002.cpp new file mode 100644 index 00000000..bf2148b8 --- /dev/null +++ b/testsuites/unittest/IO/full/IO_test_pselect_002.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. 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. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * 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 HOLDER 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 "It_test_IO.h" +#include +#include +#include +#include +#include "sys/select.h" + +static void SigPrint(int sig) +{ + return; +} + +static UINT32 testcase(VOID) +{ + fd_set rfds; + struct timespec tv; + int retval; + pid_t pid; + int pipeFd[2]; /* 2, pipe id num */ + char buffer[40]; /* 40, buffer size */ + + int i = 0; + int status; + + void (*retSig)(int); + sigset_t mask; + + retSig = signal(SIGALRM, SigPrint); + ICUNIT_ASSERT_NOT_EQUAL(retSig, NULL, retSig); + + retSig = signal(SIGUSR1, SigPrint); + ICUNIT_ASSERT_NOT_EQUAL(retSig, NULL, retSig); + + retval = sigemptyset(&mask); + ICUNIT_ASSERT_EQUAL(retval, 0, retval); + + retval = sigaddset(&mask, SIGALRM); + ICUNIT_ASSERT_EQUAL(retval, 0, retval); + + retval = sigaddset(&mask, SIGUSR1); + ICUNIT_ASSERT_EQUAL(retval, 0, retval); + + retval = pipe(pipeFd); + ICUNIT_GOTO_EQUAL(retval, 0, retval, OUT); + + /* Watch fd to see when it has input. */ + FD_ZERO(&rfds); + FD_SET(pipeFd[0], &rfds); + + /* Wait up to three seconds. */ + tv.tv_sec = 3; /* 3, wait timer, second */ + tv.tv_nsec = 5; /* 5, wait timer, nano second */ + + pid = fork(); + if (pid == 0) { + close(pipeFd[1]); + + retval = pselect(pipeFd[0] + 1, &rfds, nullptr, nullptr, &tv, &mask); + + close(pipeFd[0]); + + if (retval != 0) { + exit(LOS_OK); + } else { + exit(LOS_NOK); + } + } else { + sleep(1); + close(pipeFd[0]); + + retval = kill(pid, SIGALRM); + ICUNIT_ASSERT_EQUAL(retval, 0, retval); + + retval = kill(pid, SIGUSR1); + ICUNIT_ASSERT_EQUAL(retval, 0, retval); + close(pipeFd[1]); + + wait(&status); + status = WEXITSTATUS(status); + ICUNIT_ASSERT_EQUAL(status, LOS_OK, status); + } + + return LOS_OK; +OUT: + return LOS_NOK; +} + +VOID IO_TEST_PSELECT_002(VOID) +{ + TEST_ADD_CASE(__FUNCTION__, testcase, TEST_LIB, TEST_LIBC, TEST_LEVEL1, TEST_FUNCTION); +} + diff --git a/testsuites/unittest/IO/io_test.cpp b/testsuites/unittest/IO/io_test.cpp index 1556beb4..5b8f668d 100644 --- a/testsuites/unittest/IO/io_test.cpp +++ b/testsuites/unittest/IO/io_test.cpp @@ -93,6 +93,28 @@ HWTEST_F(IoTest, ItTestIo013, TestSize.Level0) #endif #if defined(LOSCFG_USER_TEST_FULL) +/* * + * @tc.name: IO_TEST_PSELECT_001 + * @tc.desc: function for IoTest + * @tc.type: FUNC + * @tc.require: AR000EEMQ9 + */ +HWTEST_F(IoTest, IO_TEST_PSELECT_001, TestSize.Level0) +{ + IO_TEST_PSELECT_001(); +} + +/* * + * @tc.name: IO_TEST_PSELECT_002 + * @tc.desc: function for IoTest + * @tc.type: FUNC + * @tc.require: AR000EEMQ9 + */ +HWTEST_F(IoTest, IO_TEST_PSELECT_002, TestSize.Level0) +{ + IO_TEST_PSELECT_002(); +} + /* * * @tc.name: IO_TEST_PPOLL_001 * @tc.desc: function for IoTest