diff --git a/compat/posix/include/time_posix.h b/compat/posix/include/time_posix.h index 6f8f537d..df5b3dd7 100644 --- a/compat/posix/include/time_posix.h +++ b/compat/posix/include/time_posix.h @@ -42,6 +42,13 @@ extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ +struct ksigevent { + union sigval sigev_value; + int sigev_signo; + int sigev_notify; + int sigev_tid; +}; + /* internal functions */ STATIC INLINE BOOL ValidTimeSpec(const struct timespec *tp) { @@ -78,6 +85,8 @@ STATIC INLINE VOID OsTick2TimeSpec(struct timespec *tp, UINT32 tick) tp->tv_nsec = (long)(ns % OS_SYS_NS_PER_SECOND); } +int OsTimerCreate(clockid_t, struct ksigevent *__restrict, timer_t *__restrict); + #ifdef __cplusplus #if __cplusplus } diff --git a/compat/posix/src/time.c b/compat/posix/src/time.c index b94c6a2a..25ce2086 100644 --- a/compat/posix/src/time.c +++ b/compat/posix/src/time.c @@ -693,45 +693,60 @@ int clock_nanosleep(clockid_t clk, int flags, const struct timespec *req, struct typedef struct { int sigev_signo; - UINT32 pid; + pid_t pid; + unsigned int tid; union sigval sigev_value; } swtmr_proc_arg; static VOID SwtmrProc(UINTPTR tmrArg) { - unsigned int intSave; - int sig; + INT32 sig, ret; + UINT32 intSave; pid_t pid; siginfo_t info; - swtmr_proc_arg *arg = (swtmr_proc_arg *)tmrArg; - if (arg == NULL) { - return; - } + LosTaskCB *stcb = NULL; - sig = arg->sigev_signo + 1; + swtmr_proc_arg *arg = (swtmr_proc_arg *)tmrArg; + OS_GOTO_EXIT_IF(arg == NULL, EINVAL); + + sig = arg->sigev_signo; pid = arg->pid; - /* Make sure that the para is valid */ - if (!GOOD_SIGNO(sig) || pid <= 0) { - return; - } - if (OS_PID_CHECK_INVALID(pid)) { - return; - } + OS_GOTO_EXIT_IF(!GOOD_SIGNO(sig), EINVAL); /* Create the siginfo structure */ info.si_signo = sig; info.si_code = SI_TIMER; info.si_value.sival_ptr = arg->sigev_value.sival_ptr; - /* Send the signal */ - SCHEDULER_LOCK(intSave); - OsDispatch(pid, &info, OS_USER_KILL_PERMISSION); - SCHEDULER_UNLOCK(intSave); + /* Send signals to threads or processes */ + if (arg->tid > 0) { + /* Make sure that the para is valid */ + OS_GOTO_EXIT_IF(OS_TID_CHECK_INVALID(arg->tid), EINVAL); + stcb = OsGetTaskCB(arg->tid); + ret = OsUserProcessOperatePermissionsCheck(stcb, stcb->processID); + OS_GOTO_EXIT_IF(ret != LOS_OK, -ret); + /* Dispatch the signal to thread, bypassing normal task group thread + * dispatch rules. */ + SCHEDULER_LOCK(intSave); + ret = OsTcbDispatch(stcb, &info); + SCHEDULER_UNLOCK(intSave); + OS_GOTO_EXIT_IF(ret != LOS_OK, -ret); + } else { + /* Make sure that the para is valid */ + OS_GOTO_EXIT_IF(pid <= 0 || OS_PID_CHECK_INVALID(pid), EINVAL); + /* Dispatch the signal to process */ + SCHEDULER_LOCK(intSave); + OsDispatch(pid, &info, OS_USER_KILL_PERMISSION); + SCHEDULER_UNLOCK(intSave); + } + return; +EXIT: + PRINT_ERR("Dsipatch signals failed!, ret: %d\r\n", ret); return; } -int timer_create(clockid_t clockID, struct sigevent *evp, timer_t *timerID) +int OsTimerCreate(clockid_t clockID, struct ksigevent *evp, timer_t *timerID) { UINT32 ret; UINT16 swtmrID; @@ -761,7 +776,9 @@ int timer_create(clockid_t clockID, struct sigevent *evp, timer_t *timerID) errno = ENOMEM; return -1; } - arg->sigev_signo = signo - 1; + + arg->tid = evp ? evp->sigev_tid : 0; + arg->sigev_signo = signo; arg->pid = LOS_GetCurrProcessID(); arg->sigev_value.sival_ptr = evp ? evp->sigev_value.sival_ptr : NULL; ret = LOS_SwtmrCreate(1, LOS_SWTMR_MODE_ONCE, SwtmrProc, &swtmrID, (UINTPTR)arg); @@ -1016,14 +1033,14 @@ int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue /* To avoid creating an invalid timer after the timer has already been create */ if (processCB->timerID == (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID) { - ret = timer_create(CLOCK_REALTIME, NULL, &timerID); + ret = OsTimerCreate(CLOCK_REALTIME, NULL, &timerID); if (ret != LOS_OK) { return ret; } } /* The initialization of this global timer must be in spinlock - * timer_create cannot be located in spinlock. + * OsTimerCreate cannot be located in spinlock. */ SCHEDULER_LOCK(intSave); if (processCB->timerID == (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID) { diff --git a/kernel/base/core/los_task.c b/kernel/base/core/los_task.c index 353b3f33..8361459c 100644 --- a/kernel/base/core/los_task.c +++ b/kernel/base/core/los_task.c @@ -1478,16 +1478,25 @@ LITE_OS_SEC_TEXT VOID OsExecDestroyTaskGroup(VOID) } UINT32 OsUserTaskOperatePermissionsCheck(LosTaskCB *taskCB) +{ + return OsUserProcessOperatePermissionsCheck(taskCB, OsCurrProcessGet()->processID); +} + +UINT32 OsUserProcessOperatePermissionsCheck(LosTaskCB *taskCB, UINT32 processID) { if (taskCB == NULL) { return LOS_EINVAL; } + if (processID == OS_INVALID_VALUE) { + return OS_INVALID_VALUE; + } + if (taskCB->taskStatus & OS_TASK_STATUS_UNUSED) { return LOS_EINVAL; } - if (OsCurrProcessGet()->processID != taskCB->processID) { + if (processID != taskCB->processID) { return LOS_EPERM; } diff --git a/kernel/base/include/los_task_pri.h b/kernel/base/include/los_task_pri.h index f3c6c2be..a4fdf7d3 100644 --- a/kernel/base/include/los_task_pri.h +++ b/kernel/base/include/los_task_pri.h @@ -542,6 +542,8 @@ extern VOID OsTaskExitGroup(UINT32 status); extern VOID OsTaskToExit(LosTaskCB *taskCB, UINT32 status); extern VOID OsExecDestroyTaskGroup(VOID); extern UINT32 OsUserTaskOperatePermissionsCheck(LosTaskCB *taskCB); +extern UINT32 OsUserProcessOperatePermissionsCheck(LosTaskCB *taskCB, UINT32 processID); +extern INT32 OsTcbDispatch(LosTaskCB *stcb, siginfo_t *info); extern VOID OsWriteResourceEvent(UINT32 events); extern VOID OsWriteResourceEventUnsafe(UINT32 events); extern UINT32 OsResourceFreeTaskCreate(VOID); diff --git a/syscall/los_syscall.h b/syscall/los_syscall.h index 786a1d18..71a6d5c6 100644 --- a/syscall/los_syscall.h +++ b/syscall/los_syscall.h @@ -39,6 +39,7 @@ #include "fs/fs.h" #include "syscall.h" #include "sysinfo.h" +#include "time_posix.h" #ifdef LOSCFG_KERNEL_DYNLOAD #include "los_exec_elf.h" #endif @@ -172,7 +173,7 @@ extern clock_t SysTimes(struct tms *buf); extern time_t SysTime(time_t *tloc); extern int SysSetiTimer(int which, const struct itimerval *value, struct itimerval *ovalue); extern int SysGetiTimer(int which, struct itimerval *value); -extern int SysTimerCreate(clockid_t clockID, struct sigevent *evp, timer_t *timerID); +extern int SysTimerCreate(clockid_t clockID, struct ksigevent *evp, timer_t *timerID); extern int SysTimerGettime(timer_t timerID, struct itimerspec *value); extern int SysTimerGetoverrun(timer_t timerID); extern int SysTimerDelete(timer_t timerID); diff --git a/syscall/time_syscall.c b/syscall/time_syscall.c index 10ef483c..e433e2de 100644 --- a/syscall/time_syscall.c +++ b/syscall/time_syscall.c @@ -39,6 +39,7 @@ #include "los_signal.h" #include "los_memory.h" #include "los_strncpy_from_user.h" +#include "time_posix.h" #ifdef LOSCFG_FS_VFS int SysUtime(const char *path, const struct utimbuf *ptimes) @@ -156,23 +157,23 @@ int SysGetiTimer(int which, struct itimerval *value) return ret; } -int SysTimerCreate(clockid_t clockID, struct sigevent *evp, timer_t *timerID) +int SysTimerCreate(clockid_t clockID, struct ksigevent *evp, timer_t *timerID) { int ret; timer_t stimerID; - struct sigevent sevp; + struct ksigevent ksevp; if (timerID == NULL) { errno = EINVAL; return -EINVAL; } - if (evp && LOS_ArchCopyFromUser(&sevp, evp, sizeof(struct sigevent))) { + if (evp && LOS_ArchCopyFromUser(&ksevp, evp, sizeof(struct ksigevent))) { errno = EFAULT; return -EFAULT; } - ret = timer_create(clockID, evp ? &sevp : NULL, &stimerID); + ret = OsTimerCreate(clockID, evp ? &ksevp : NULL, &stimerID); if (ret < 0) { return -get_errno(); } diff --git a/testsuites/unittest/time/timer/BUILD.gn b/testsuites/unittest/time/timer/BUILD.gn index b69eb76f..12f75900 100644 --- a/testsuites/unittest/time/timer/BUILD.gn +++ b/testsuites/unittest/time/timer/BUILD.gn @@ -46,6 +46,7 @@ sources_smoke = [ "smoke/timer_test_002.cpp", "smoke/timer_test_003.cpp", "smoke/timer_test_004.cpp", + "smoke/timer_test_005.cpp", "smoke/timer_test_tzset_001.cpp", "smoke/timer_test_tzset_002.cpp", ] diff --git a/testsuites/unittest/time/timer/lt_timer_test.h b/testsuites/unittest/time/timer/lt_timer_test.h index 0d90396a..1c5ab9a0 100644 --- a/testsuites/unittest/time/timer/lt_timer_test.h +++ b/testsuites/unittest/time/timer/lt_timer_test.h @@ -41,6 +41,7 @@ void TimerTest001(void); void TimerTest002(void); void TimerTest003(void); void TimerTest004(void); +void TimerTest005(void); void TIME_TEST_TZSET_001(void); void TIME_TEST_TZSET_002(void); diff --git a/testsuites/unittest/time/timer/smoke/timer_test_001.cpp b/testsuites/unittest/time/timer/smoke/timer_test_001.cpp index f339da22..f888c497 100644 --- a/testsuites/unittest/time/timer/smoke/timer_test_001.cpp +++ b/testsuites/unittest/time/timer/smoke/timer_test_001.cpp @@ -42,7 +42,7 @@ static int g_sigHdlCnt; static int g_overRunCnt; static timer_t g_timerID; -static void SigHandler(int sig) +static void SigHandler01(int sig) { g_sigHdlCnt++; g_overRunCnt += timer_getoverrun(g_timerID); @@ -52,7 +52,7 @@ static void SigHandler(int sig) static int TimerTest(void) { int interval = 3; // 3, seconds - timer_t timerid; + timer_t timerid01, timerid02; struct sigevent sev; struct itimerspec its; sigset_t mask; @@ -60,7 +60,7 @@ static int TimerTest(void) int ret; sa.sa_flags = 0; - sa.sa_handler = SigHandler; + sa.sa_handler = SigHandler01; sigemptyset(&sa.sa_mask); ret = sigaction(SIG, &sa, nullptr); LogPrintln("sigaction %d: %d", SIG, ret); @@ -76,12 +76,12 @@ static int TimerTest(void) /* Create the timer */ sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIG; - sev.sigev_value.sival_ptr = &timerid; - ret = timer_create(CLOCKID, &sev, &timerid); - LogPrintln("timer_create %p: %d", timerid, ret); + sev.sigev_value.sival_ptr = &timerid01; + ret = timer_create(CLOCKID, &sev, &timerid01); + LogPrintln("timer_create %p: %d", timerid01, ret); ICUNIT_ASSERT_EQUAL(ret, 0, ret); - g_timerID = timerid; + g_timerID = timerid01; /* Start the timer */ its.it_value.tv_sec = 0; @@ -89,23 +89,39 @@ static int TimerTest(void) its.it_interval.tv_sec = its.it_value.tv_sec; its.it_interval.tv_nsec = its.it_value.tv_nsec; - ret = timer_settime(timerid, 0, &its, nullptr); - LogPrintln("timer_settime %p: %d", timerid, ret); + ret = timer_settime(timerid01, 0, &its, nullptr); + LogPrintln("timer_settime %p: %d", timerid01, ret); ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + /* Test of evp is NULL */ + ret = timer_create(CLOCKID, NULL, &timerid02); + LogPrintln("timer_settime %p: %d", timerid02, ret); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + its.it_value.tv_sec = 1; + its.it_value.tv_nsec = 0; + its.it_interval.tv_sec = its.it_value.tv_sec; + its.it_interval.tv_nsec = its.it_value.tv_nsec; + + ret = timer_settime(timerid02, 0, &its, nullptr); + LogPrintln("timer_settime %p: %d", timerid02, ret); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + sleep(6); /* Sleep for a while */ LogPrintln("sleep %ds", interval); sleep(interval); // timer signal is blocked, this sleep should not be interrupted ICUNIT_ASSERT_EQUAL(g_sigHdlCnt, 0, g_sigHdlCnt); /* Get the timer's time */ - ret = timer_gettime(timerid, &its); - LogPrintln("timer_gettime %p: %d", timerid, ret); + ret = timer_gettime(timerid01, &its); + LogPrintln("timer_gettime %p: %d", timerid01, ret); ICUNIT_ASSERT_EQUAL(ret, 0, ret); /* Get the timer's overruns */ - ret = timer_getoverrun(timerid); - LogPrintln("timer_getoverrun %p: %d", timerid, ret); + ret = timer_getoverrun(timerid01); + LogPrintln("timer_getoverrun %p: %d", timerid01, ret); ICUNIT_ASSERT_NOT_EQUAL(ret, -1, ret); // before timer deliver, return value of timer_getoverrun is unspecified LogPrintln("unblock signal %d", SIG); @@ -124,8 +140,12 @@ static int TimerTest(void) sleep(interval); // this sleep may be interrupted by the timer LogPrintln("sleep time over, g_sigHdlCnt = %d", g_sigHdlCnt); - ret = timer_delete(timerid); - LogPrintln("timer_delete %p %d", timerid, ret); + ret = timer_delete(timerid01); + LogPrintln("timer_delete %p %d", timerid01, ret); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ret = timer_delete(timerid02); + LogPrintln("timer_delete %p %d", timerid02, ret); ICUNIT_ASSERT_EQUAL(ret, 0, ret); ICUNIT_ASSERT_NOT_EQUAL(g_sigHdlCnt, 0, g_sigHdlCnt); diff --git a/testsuites/unittest/time/timer/smoke/timer_test_005.cpp b/testsuites/unittest/time/timer/smoke/timer_test_005.cpp new file mode 100644 index 00000000..4c739f74 --- /dev/null +++ b/testsuites/unittest/time/timer/smoke/timer_test_005.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 +#include +#include +#include +#include "osTest.h" +#include +#include +#include "lt_timer_test.h" + +static int g_sigHdlCnt01; +static int g_sigHdlCnt02; +static int g_sigHdlCnt03; + +static void TempSigHandler(union sigval v) +{ + LogPrintln("This is TempSigHandler ...\r\n"); + (*(void(*)(void))(v.sival_ptr))(); +} + +static void TempSigHandler01(void) +{ + g_sigHdlCnt01++; +} + +static void TempSigHandler02(void) +{ + g_sigHdlCnt02++; +} + +static int TimerTest(void) +{ + timer_t timerid01, timerid02, timerid03; + struct sigevent sev; + struct itimerspec its; + int ret; + int i; + + (void)memset(&sev, 0, sizeof(struct sigevent)); + sev.sigev_notify = SIGEV_THREAD; + sev.sigev_notify_function = TempSigHandler; + sev.sigev_value.sival_ptr = (void *)TempSigHandler01; + + /* Start the timer */ + its.it_value.tv_sec = 3; // 3, timer time 3 seconds. + its.it_value.tv_nsec = 0; + its.it_interval.tv_sec = its.it_value.tv_sec; + its.it_interval.tv_nsec = its.it_value.tv_nsec; + ret = timer_create(CLOCK_REALTIME, &sev, &timerid01); + LogPrintln("timer_settime %p: %d", timerid01, ret); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ret = timer_settime(timerid01, 0, &its, nullptr); + LogPrintln("timer_create %p: %d", timerid01, ret); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + its.it_value.tv_sec = 4; // 4, timer time 4 seconds. + its.it_value.tv_nsec = 0; + its.it_interval.tv_sec = its.it_value.tv_sec; + its.it_interval.tv_nsec = its.it_value.tv_nsec; + + sev.sigev_value.sival_ptr = (void *)TempSigHandler02; + ret = timer_create(CLOCK_REALTIME, &sev, &timerid02); + LogPrintln("timer_settime %p: %d", timerid02, ret); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ret = timer_settime(timerid02, 0, &its, nullptr); + LogPrintln("timer_settime %p: %d", timerid02, ret); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + its.it_value.tv_sec = 5; // 5, timer time 5 seconds. + its.it_value.tv_nsec = 0; + its.it_interval.tv_sec = its.it_value.tv_sec; + its.it_interval.tv_nsec = its.it_value.tv_nsec; + + sleep(20); // 20, sleep seconds for timer. + ret = timer_delete(timerid01); + LogPrintln("timer_delete %p %d", timerid01, ret); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ret = timer_delete(timerid02); + LogPrintln("timer_delete %p %d", timerid02, ret); + ICUNIT_ASSERT_EQUAL(ret, 0, ret); + + ICUNIT_ASSERT_NOT_EQUAL(g_sigHdlCnt01, 0, g_sigHdlCnt01); + ICUNIT_ASSERT_NOT_EQUAL(g_sigHdlCnt02, 0, g_sigHdlCnt02); + return 0; + +} + +void TimerTest005(void) +{ + TEST_ADD_CASE(__FUNCTION__, TimerTest, TEST_POSIX, TEST_SWTMR, TEST_LEVEL0, TEST_FUNCTION); +} diff --git a/testsuites/unittest/time/timer/time_timer_test.cpp b/testsuites/unittest/time/timer/time_timer_test.cpp index fc4cc94a..3384ff70 100644 --- a/testsuites/unittest/time/timer/time_timer_test.cpp +++ b/testsuites/unittest/time/timer/time_timer_test.cpp @@ -86,5 +86,16 @@ HWTEST_F(TimeTimerTest, TimerTest003, TestSize.Level0) { TimerTest004(); // TODO: musl sigaction handler have only one param. }*/ + +/* * + * @tc.name: TimerTest005 + * @tc.desc: function for timer_create SIGEV_THREAD. + * @tc.type: FUNC + * @tc.require: AR000EEMQ9 + */ +HWTEST_F(TimeTimerTest, TimerTest005, TestSize.Level0) +{ + TimerTest005(); +} #endif } // namespace OHOS