From 4890222e7c284cfc93d8712264ba65d7c4252309 Mon Sep 17 00:00:00 2001 From: JerryH Date: Fri, 14 Jan 2022 10:10:11 +0800 Subject: [PATCH] feature: Support pipe and poll interfaces. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持pipe管道驱动,支持poll多文件描述符检测接口。 Signed-off-by: JerryH Change-Id: Ida1f29709affbc91a26b8518e4a77b8e5469be19 --- components/fs/vfs/los_fs.c | 46 +++ kal/posix/BUILD.gn | 5 + kal/posix/Kconfig | 7 + kal/posix/include/pipe_impl.h | 61 +++ kal/posix/include/poll_impl.h | 74 ++++ kal/posix/src/pipe.c | 700 ++++++++++++++++++++++++++++++++++ kal/posix/src/poll.c | 224 +++++++++++ kernel/include/los_config.h | 8 + kernel/src/los_init.c | 12 + kernel/src/los_task.c | 8 +- 10 files changed, 1139 insertions(+), 6 deletions(-) create mode 100644 kal/posix/include/pipe_impl.h create mode 100644 kal/posix/include/poll_impl.h create mode 100644 kal/posix/src/pipe.c create mode 100644 kal/posix/src/poll.c diff --git a/components/fs/vfs/los_fs.c b/components/fs/vfs/los_fs.c index 71a05b6c..c3987758 100644 --- a/components/fs/vfs/los_fs.c +++ b/components/fs/vfs/los_fs.c @@ -60,6 +60,24 @@ #define RANDOM_DEV_PATH "/dev/random" #endif +#if (LOSCFG_POSIX_PIPE_API == 1) +#include "pipe_impl.h" +#ifdef LOSCFG_RANDOM_DEV +#define PIPE_DEV_FD (RANDOM_DEV_FD + 1) +#else +#define PIPE_DEV_FD (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS) +#endif + +int PollQueryFd(int fd, struct PollTable *table) +{ + if (fd >= PIPE_DEV_FD) { + return PipePoll(fd, table); + } + + return -ENODEV; +} +#endif + #define FREE_AND_SET_NULL(ptr) do { \ free(ptr); \ ptr = NULL; \ @@ -285,6 +303,13 @@ int LOS_Open(const char *path, int oflag, ...) } FREE_AND_SET_NULL(canonicalPath); #endif + +#if (LOSCFG_POSIX_PIPE_API == 1) + if ((path != NULL) && !strncmp(path, PIPE_DEV_PATH, strlen(PIPE_DEV_PATH))) { + return PipeOpen(path, oflag, PIPE_DEV_FD); + } +#endif + if (g_fs == NULL) { errno = ENODEV; return FS_FAILURE; @@ -308,6 +333,13 @@ int LOS_Close(int fd) return closesocket(fd); } #endif + +#if (LOSCFG_POSIX_PIPE_API == 1) + if (fd >= PIPE_DEV_FD) { + return PipeClose(fd); + } +#endif + if (g_fs == NULL) { errno = ENODEV; return FS_FAILURE; @@ -346,6 +378,13 @@ ssize_t LOS_Read(int fd, void *buf, size_t nbyte) return recv(fd, buf, nbyte, 0); } #endif + +#if (LOSCFG_POSIX_PIPE_API == 1) + if (fd >= PIPE_DEV_FD) { + return PipeRead(fd, buf, nbyte); + } +#endif + if (g_fs == NULL) { errno = ENODEV; return FS_FAILURE; @@ -370,6 +409,13 @@ ssize_t LOS_Write(int fd, const void *buf, size_t nbyte) return send(fd, buf, nbyte, 0); } #endif + +#if (LOSCFG_POSIX_PIPE_API == 1) + if (fd >= PIPE_DEV_FD) { + return PipeWrite(fd, buf, nbyte); + } +#endif + if (g_fs == NULL) { errno = ENODEV; return FS_FAILURE; diff --git a/kal/posix/BUILD.gn b/kal/posix/BUILD.gn index 54f81159..69f7950c 100644 --- a/kal/posix/BUILD.gn +++ b/kal/posix/BUILD.gn @@ -57,6 +57,11 @@ kernel_module(module_name) { if (defined(LOSCFG_POSIX_MQUEUE_API)) { sources += [ "src/mqueue.c" ] } + + if (defined(LOSCFG_POSIX_PIPE_API)) { + sources += [ "src/pipe.c" ] + sources += [ "src/poll.c" ] + } } config("public") { diff --git a/kal/posix/Kconfig b/kal/posix/Kconfig index 95cb3bdf..a57e6169 100644 --- a/kal/posix/Kconfig +++ b/kal/posix/Kconfig @@ -59,4 +59,11 @@ config POSIX_MQUEUE_API help Answer Y to enable LiteOS support POSIX Mqueue API. + +config POSIX_PIPE_API + bool "Enable POSIX Pipe API" + default y + help + Answer Y to enable LiteOS support POSIX Pipe API. + endif # POSIX_API diff --git a/kal/posix/include/pipe_impl.h b/kal/posix/include/pipe_impl.h new file mode 100644 index 00000000..f35cbcd0 --- /dev/null +++ b/kal/posix/include/pipe_impl.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022-2022 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. + */ + +#ifndef _PIPE_IMPL_H +#define _PIPE_IMPL_H + +#include +#include +#include "los_config.h" +#include "poll_impl.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#define PIPE_DEV_PATH "/dev/pipe" + +UINT32 OsPipeInit(VOID); +INT32 PipeOpen(const CHAR *path, INT32 openFlag, INT32 minFd); +INT32 PipeClose(INT32 fd); +INT32 PipeRead(INT32 fd, VOID *buf, size_t len); +INT32 PipeWrite(INT32 fd, const VOID *buf, size_t len); +INT32 PipeUnlink(const CHAR *path); +INT32 PipePoll(INT32 fd, struct PollTable *table); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* _PIPE_IMPL_H */ diff --git a/kal/posix/include/poll_impl.h b/kal/posix/include/poll_impl.h new file mode 100644 index 00000000..eabe66ff --- /dev/null +++ b/kal/posix/include/poll_impl.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022-2022 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. + */ + +#ifndef _POLL_IMPL_H +#define _POLL_IMPL_H + +#include "los_config.h" +#include "los_list.h" +#include "los_sem.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +typedef UINT32 PollEvent; + +struct PollWaitQueue { + LOS_DL_LIST queue; +}; + +struct PollTable; +struct PollWaitNode { + LOS_DL_LIST node; + struct PollTable *table; +}; + +struct PollTable { + struct PollWaitNode *node; + PollEvent event; + UINT32 sem; + BOOL addQueueFlag; +}; + +VOID PollWaitQueueInit(struct PollWaitQueue *waitQueue); +VOID PollNotify(struct PollWaitQueue *waitQueue, PollEvent event); +VOID PollWait(struct PollWaitQueue *waitQueue, struct PollTable *table); +INT32 PollQueryFd(INT32 fd, struct PollTable *table); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif /* _POLL_IMPL_H */ diff --git a/kal/posix/src/pipe.c b/kal/posix/src/pipe.c new file mode 100644 index 00000000..0950b242 --- /dev/null +++ b/kal/posix/src/pipe.c @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2022-2022 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 "securec.h" +#include "los_fs.h" +#include "los_list.h" +#include "los_mux.h" +#include "los_sem.h" +#include "los_debug.h" +#include "los_memory.h" +#include "pipe_impl.h" + +#if (LOSCFG_POSIX_PIPE_API == 1) + +#define PIPE_DEV_NUM 32 +#define PIPE_FD_NUM (PIPE_DEV_NUM << 1) +#define PIPE_DEV_NAME_MAX 32 +#define PIPE_DEV_FD_BITMAP_LEN ((PIPE_FD_NUM >> 5) + 1) +#define PIPE_DEV_BUF_SIZE 1024 +#define PIPE_READ 1 +#define PIPE_WRITE 2 + +#define PIPE_DEV_LOCK(mutex) do { \ + UINT32 __ret = LOS_MuxPend(mutex, LOS_WAIT_FOREVER); \ + if (__ret != LOS_OK) { \ + PRINT_ERR("pipe device lock error, ret = %x\n", __ret); \ + } \ +} while (0) + +#define PIPE_DEV_UNLOCK(mutex) do { \ + UINT32 __ret = LOS_MuxPost(mutex); \ + if (__ret != LOS_OK) { \ + PRINT_ERR("pipe device unlock error, ret = %x\n", __ret); \ + } \ +} while (0) + +#define PIPE_RW_WAIT(sem) do { \ + LosSemCB *__sem = GET_SEM(sem); \ + while (__sem->semCount != 0) { \ + UINT32 __ret = LOS_SemPend(__sem->semID, LOS_WAIT_FOREVER); \ + if (__ret != LOS_OK) { \ + PRINT_ERR("pipe device R/W sem wait error, ret = %x\n", __ret); \ + } \ + } \ +} while (0) + +#define PIPE_RW_POST(sem) do { \ + LosSemCB *__sem = GET_SEM(sem); \ + while (__sem->semCount == 0) { \ + UINT32 __ret = LOS_SemPost(__sem->semID); \ + if (__ret != LOS_OK) { \ + PRINT_ERR("pipe device R/W sem post error, ret = %x\n", __ret); \ + } \ + } \ +} while (0) + +struct PipeDev { + CHAR devName[PIPE_DEV_NAME_MAX]; + UINT32 num; + UINT32 mutex; + LOS_DL_LIST list; + UINT32 readSem; + UINT32 writeSem; + UINT8 *ringBuffer; + size_t bufferSize; + size_t readIndex; + size_t writeIndex; + BOOL roll; + UINT32 readerCnt; + UINT32 writerCnt; + UINT32 ref; + struct PollWaitQueue wq; +}; + +struct PipeFdDev { + struct PipeDev *dev; + BOOL openFlag; +}; + +STATIC LOS_DL_LIST g_devList = {&g_devList, &g_devList}; +STATIC UINT32 g_devListMutex = LOSCFG_BASE_IPC_MUX_LIMIT; + +STATIC UINT32 g_devNumBitmap = 0; +STATIC UINT32 g_devFdBitmap[PIPE_DEV_FD_BITMAP_LEN] = {0}; +STATIC struct PipeFdDev g_devFd[PIPE_FD_NUM] = {0}; +STATIC UINT32 g_devFdMutex = LOSCFG_BASE_IPC_MUX_LIMIT; +STATIC INT32 g_devStartFd = 0; + +STATIC INT32 PipeDevNumAlloc(VOID) +{ + UINT32 temp = g_devNumBitmap; + INT32 devNum = 0; + + while (temp & 0x1) { + devNum++; + temp = temp >> 1; + } + + if (devNum >= PIPE_DEV_NUM) { + return -1; + } + g_devNumBitmap |= 1U << devNum; + + return devNum; +} + +STATIC VOID PipeDevNumFree(INT32 devNum) +{ + if ((devNum < 0) || (devNum >= PIPE_DEV_NUM)) { + return; + } + g_devNumBitmap &= ~(1U << devNum); +} + +STATIC struct PipeDev *PipeDevFind(const CHAR *path) +{ + struct PipeDev *dev = NULL; + + (VOID)LOS_MuxPend(g_devListMutex, LOS_WAIT_FOREVER); + if (!LOS_ListEmpty(&g_devList)) { + LOS_DL_LIST_FOR_EACH_ENTRY(dev, &g_devList, struct PipeDev, list) { + if (!strncmp(dev->devName, path, PIPE_DEV_NAME_MAX)) { + (VOID)LOS_MuxPost(g_devListMutex); + return dev; + } + } + } + (VOID)LOS_MuxPost(g_devListMutex); + return NULL; +} + +STATIC size_t PipeRingbufferRead(struct PipeDev *dev, VOID *buf, size_t len) +{ + size_t nbytes; + + if (dev->readIndex < dev->writeIndex) { + nbytes = dev->writeIndex - dev->readIndex; + } else if (dev->readIndex > dev->writeIndex) { + nbytes = dev->bufferSize - dev->readIndex; + } else { + if (dev->roll == FALSE) { + return 0; + } else { + nbytes = dev->bufferSize - dev->readIndex; + } + } + nbytes = (nbytes > len) ? len : nbytes; + (VOID)memcpy_s((char *)buf, len, dev->ringBuffer + dev->readIndex, nbytes); + dev->readIndex += nbytes; + if (dev->readIndex >= dev->bufferSize) { + dev->readIndex = 0; + dev->roll = FALSE; + } + + return nbytes; +} + +STATIC size_t PipeRingbufferWrite(struct PipeDev *dev, VOID *buf, size_t len) +{ + size_t nbytes; + + if (dev->readIndex < dev->writeIndex) { + nbytes = dev->bufferSize - dev->writeIndex; + } else if (dev->readIndex > dev->writeIndex) { + nbytes = dev->readIndex - dev->writeIndex; + } else { + if (dev->roll == TRUE) { + return 0; + } else { + nbytes = dev->bufferSize - dev->writeIndex; + } + } + + nbytes = (nbytes > len) ? len : nbytes; + (VOID)memcpy_s(dev->ringBuffer + dev->writeIndex, dev->bufferSize + - dev->writeIndex, buf, nbytes); + dev->writeIndex += nbytes; + if (dev->writeIndex >= dev->bufferSize) { + dev->roll = TRUE; + dev->writeIndex = 0; + } + + return nbytes; +} + +STATIC INT32 PipeDevRegister(CHAR *devName, UINT32 len) +{ + INT32 ret; + INT32 num = PipeDevNumAlloc(); + if (num < 0) { + return -ENODEV; + } + + struct PipeDev *devTemp = NULL; + struct PipeDev *dev = LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(struct PipeDev)); + if (dev == NULL) { + ret = -ENOMEM; + goto ERROR; + } + (VOID)memset_s(dev, sizeof(struct PipeDev), 0, sizeof(struct PipeDev)); + (VOID)snprintf_s(dev->devName, PIPE_DEV_NAME_MAX, PIPE_DEV_NAME_MAX - 1, "%s%d", PIPE_DEV_PATH, num); + (VOID)memcpy_s(devName, len, dev->devName, strlen(dev->devName)); + + devTemp = PipeDevFind(dev->devName); + if (devTemp != NULL) { + ret = -EEXIST; + goto ERROR; + } + + ret = LOS_MuxCreate(&dev->mutex); + if (ret != LOS_OK) { + ret = -ENOSPC; + goto ERROR; + } + + ret = LOS_SemCreate(0, &dev->readSem); + if (ret != LOS_OK) { + (VOID)LOS_MuxDelete(dev->mutex); + ret = -ENOSPC; + goto ERROR; + } + + ret = LOS_SemCreate(0, &dev->writeSem); + if (ret != LOS_OK) { + (VOID)LOS_MuxDelete(dev->mutex); + (VOID)LOS_SemDelete(dev->readSem); + ret = -ENOSPC; + goto ERROR; + } + + dev->num = num; + PollWaitQueueInit(&dev->wq); + + (VOID)LOS_MuxPend(g_devListMutex, LOS_WAIT_FOREVER); + LOS_ListAdd(&g_devList, &dev->list); + (VOID)LOS_MuxPost(g_devListMutex); + + return ENOERR; +ERROR: + if (dev != NULL) { + (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, dev); + } + PipeDevNumFree(num); + return ret; +} + +STATIC INT32 PipeDevUnregister(struct PipeDev *dev) +{ + BOOL findFlag = FALSE; + + (VOID)LOS_MuxPend(g_devListMutex, LOS_WAIT_FOREVER); + if (LOS_ListEmpty(&g_devList)) { + (VOID)LOS_MuxPost(g_devListMutex); + return -ENODEV; + } + + struct PipeDev *tmpDev = NULL; + LOS_DL_LIST_FOR_EACH_ENTRY(tmpDev, &g_devList, struct PipeDev, list) { + if (tmpDev == dev) { + LOS_ListDelete(&dev->list); + findFlag = TRUE; + break; + } + } + (VOID)LOS_MuxPost(g_devListMutex); + + if (findFlag != TRUE) { + return -ENODEV; + } + + PipeDevNumFree(dev->num); + (VOID)LOS_MuxDelete(dev->mutex); + (VOID)LOS_SemDelete(dev->readSem); + (VOID)LOS_SemDelete(dev->writeSem); + (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, dev->ringBuffer); + dev->ringBuffer = NULL; + (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, dev); + + return ENOERR; +} + +STATIC INT32 PipeDevFdAlloc(VOID) +{ + UINT32 i = 0; + INT32 fd = 0; + + while (g_devFdBitmap[i] & (1U << fd)) { + fd++; + if (fd == 32) { /* 32: bit index max is 32. */ + i++; + fd = 0; + } + + if (i == PIPE_DEV_FD_BITMAP_LEN) { + return -1; + } + } + g_devFdBitmap[i] |= (1U << fd); + return (fd + (i << 5)); /* 5: i is the multiple of 32. */ +} + +STATIC VOID PipeDevFdFree(INT32 fd) +{ + g_devFdBitmap[fd >> 5] &= ~(1U << (fd & 0x1F)); /* 5: fd is the multiple of 32. */ +} + +STATIC VOID PipePollNotify(struct PipeDev *dev, PollEvent event) +{ + struct PollWaitQueue *waitQueue = &dev->wq; + + if (event & POLLERR) { + event &= ~(POLLIN | POLLOUT); + } + + PollNotify(waitQueue, event); +} + +INT32 PipeOpen(const CHAR *path, INT32 openFlag, INT32 minFd) +{ + struct PipeDev *dev = NULL; + INT32 fd = -1; + + if (path == NULL) { + errno = EINVAL; + return -1; + } + + if ((openFlag != O_RDONLY) && (openFlag != O_WRONLY)) { + errno = EINVAL; + return -1; + } + + dev = PipeDevFind(path); + if (dev == NULL) { + errno = ENODEV; + return -1; + } + + fd = PipeDevFdAlloc(); + if (fd < 0) { + errno = EBUSY; + return -1; + } + + (VOID)LOS_MuxPend(g_devFdMutex, LOS_WAIT_FOREVER); + g_devFd[fd].dev = dev; + g_devFd[fd].openFlag = openFlag; + g_devStartFd = minFd; + (VOID)LOS_MuxPost(g_devFdMutex); + + PIPE_DEV_LOCK(dev->mutex); + if (openFlag == O_RDONLY) { + dev->readerCnt++; + } else if (openFlag == O_WRONLY) { + dev->writerCnt++; + } + dev->ref++; + + if (dev->ringBuffer == NULL) { + dev->ringBuffer = LOS_MemAlloc(OS_SYS_MEM_ADDR, PIPE_DEV_BUF_SIZE); + if (dev->ringBuffer == NULL) { + PIPE_DEV_UNLOCK(dev->mutex); + errno = ENOMEM; + goto ERROR; + } + dev->bufferSize = PIPE_DEV_BUF_SIZE; + } + PIPE_DEV_UNLOCK(dev->mutex); + + return (fd + minFd); +ERROR: + if (dev->ringBuffer != NULL) { + (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, dev->ringBuffer); + dev->ringBuffer = NULL; + } + + PipeDevFdFree(fd); + return -1; +} + +STATIC INLINE struct PipeFdDev *PipeFdDevGet(INT32 fd) +{ + if (fd < g_devStartFd) { + return NULL; + } + + fd -= g_devStartFd; + if (fd >= PIPE_FD_NUM) { + return NULL; + } + return &g_devFd[fd]; +} + +STATIC struct PipeDev *PipeFd2Dev(INT32 fd) +{ + struct PipeFdDev *devFd = PipeFdDevGet(fd); + + return (devFd != NULL) ? devFd->dev : NULL; +} + +INT32 PipeClose(INT32 fd) +{ + struct PipeDev *dev = NULL; + UINT32 openFlag; + + (VOID)LOS_MuxPend(g_devFdMutex, LOS_WAIT_FOREVER); + dev = PipeFd2Dev(fd); + if (dev == NULL) { + errno = ENODEV; + goto ERROR; + } + fd -= g_devStartFd; + openFlag = g_devFd[fd].openFlag; + g_devFd[fd].dev = NULL; + g_devFd[fd].openFlag = FALSE; + PipeDevFdFree(fd); + (VOID)LOS_MuxPost(g_devFdMutex); + + PIPE_DEV_LOCK(dev->mutex); + if (openFlag == O_RDONLY) { + dev->readerCnt--; + } + + if (openFlag == O_WRONLY) { + dev->writerCnt--; + } + + if (dev->readerCnt == 0) { + PIPE_RW_POST(dev->writeSem); + PipePollNotify(dev, POLLOUT); + } + + if (dev->writerCnt == 0) { + PIPE_RW_POST(dev->readSem); + PipePollNotify(dev, POLLIN); + } + + if (--dev->ref == 0) { + PIPE_DEV_UNLOCK(dev->mutex); + (VOID)PipeDevUnregister(dev); + } else { + PIPE_DEV_UNLOCK(dev->mutex); + } + + return ENOERR; +ERROR: + (VOID)LOS_MuxPost(g_devFdMutex); + return -1; +} + +STATIC INLINE BOOL PipeWriterIsWaiting(UINT32 sem) +{ + LosSemCB *semCB = GET_SEM(sem); + UINT32 num = 0; + + while (semCB->semCount == 0) { + UINT32 ret = LOS_SemPost(semCB->semID); + if (ret != LOS_OK) { + PRINT_ERR("pipe device write sem post error, ret = %x\n", ret); + } + num++; + } + return (num <= 1) ? FALSE : TRUE; +} + +STATIC struct PipeDev *PipeDevGet(INT32 fd) +{ + struct PipeDev *dev = NULL; + + (VOID)LOS_MuxPend(g_devFdMutex, LOS_WAIT_FOREVER); + dev = PipeFd2Dev(fd); + (VOID)LOS_MuxPost(g_devFdMutex); + + return dev; +} + +INT32 PipeRead(INT32 fd, VOID *buf, size_t len) +{ + struct PipeDev *dev = NULL; + INT32 ret; + size_t nread = 0; + size_t tmpLen; + + if ((buf == NULL) || (len == 0)) { + errno = EINVAL; + return -1; + } + + dev = PipeDevGet(fd); + if (dev == NULL) { + errno = ENODEV; + return -1; + } + + PIPE_DEV_LOCK(dev->mutex); + if ((dev->readIndex == dev->writeIndex) && + (dev->roll == FALSE)) { + PIPE_DEV_UNLOCK(dev->mutex); + + ret = LOS_SemPend(dev->readSem, LOS_WAIT_FOREVER); + if (ret != LOS_OK) { + errno = EINVAL; + goto ERROR; + } + PIPE_DEV_LOCK(dev->mutex); + } + + while (nread < len) { + tmpLen = PipeRingbufferRead(dev, (CHAR *)buf + nread, len - nread); + if (tmpLen == 0) { + PIPE_RW_WAIT(dev->readSem); + /* No writer operates at present, which indicates that the write operation may have ended */ + if (!PipeWriterIsWaiting(dev->writeSem)) { + PipePollNotify(dev, POLLOUT); + PIPE_DEV_UNLOCK(dev->mutex); + return nread; + } + PipePollNotify(dev, POLLOUT); + + PIPE_DEV_UNLOCK(dev->mutex); + ret = LOS_SemPend(dev->readSem, LOS_WAIT_FOREVER); + if (ret != LOS_OK) { + errno = EINVAL; + goto ERROR; + } + PIPE_DEV_LOCK(dev->mutex); + } + nread += tmpLen; + } + PIPE_RW_POST(dev->writeSem); + PIPE_DEV_UNLOCK(dev->mutex); + PipePollNotify(dev, POLLOUT); + + return nread; +ERROR: + return -1; +} + +INT32 PipeWrite(INT32 fd, const VOID *buf, size_t len) +{ + struct PipeDev *dev = NULL; + INT32 ret; + size_t nwrite = 0; + size_t tmpLen; + + if ((buf == NULL) || (len == 0)) { + errno = EINVAL; + return -1; + } + + dev = PipeDevGet(fd); + if (dev == NULL) { + errno = ENODEV; + return -1; + } + + PIPE_DEV_LOCK(dev->mutex); + while (nwrite < len) { + tmpLen = PipeRingbufferWrite(dev, (char *)buf + nwrite, len - nwrite); + if (tmpLen == 0) { + PIPE_RW_POST(dev->readSem); + PipePollNotify(dev, POLLIN); + PIPE_RW_WAIT(dev->writeSem); + + PIPE_DEV_UNLOCK(dev->mutex); + ret = LOS_SemPend(dev->writeSem, LOS_WAIT_FOREVER); + if (ret != LOS_OK) { + errno = EINVAL; + goto ERROR; + } + PIPE_DEV_LOCK(dev->mutex); + } + nwrite += tmpLen; + } + PIPE_RW_POST(dev->readSem); + PipePollNotify(dev, POLLIN); + PIPE_DEV_UNLOCK(dev->mutex); + + return nwrite; +ERROR: + return -1; +} + +INT32 PipePoll(INT32 fd, struct PollTable *table) +{ + struct PipeDev *dev = NULL; + struct PipeFdDev *devFd = NULL; + UINT32 openFlag; + INT32 mask; + size_t nbytes; + PollEvent event = 0; + + if (table == NULL) { + errno = EINVAL; + return -1; + } + + (VOID)LOS_MuxPend(g_devFdMutex, LOS_WAIT_FOREVER); + devFd = PipeFdDevGet(fd); + if (devFd == NULL) { + (VOID)LOS_MuxPost(g_devFdMutex); + errno = ENODEV; + return -1; + } + openFlag = devFd->openFlag; + dev = devFd->dev; + (VOID)LOS_MuxPost(g_devFdMutex); + + PIPE_DEV_LOCK(dev->mutex); + if (dev->readIndex == dev->writeIndex) { + if (dev->roll == TRUE) { + nbytes = dev->bufferSize; + } else { + nbytes = 0; + } + } else if (dev->writeIndex > dev->readIndex) { + nbytes = dev->writeIndex - dev->readIndex; + } else { + nbytes = dev->bufferSize - dev->readIndex + dev->writeIndex; + } + + if (((openFlag & O_WRONLY) != 0) && (nbytes < (dev->bufferSize - 1))) { + event |= POLLOUT; + } + + if (((openFlag & O_WRONLY) == 0) && (nbytes > 0)) { + event |= POLLIN; + } + + mask = event & table->event; + if (mask == 0) { + PollWait(&dev->wq, table); + } + PIPE_DEV_UNLOCK(dev->mutex); + + return mask; +} + +int pipe(int filedes[2]) +{ + INT32 ret; + CHAR devName[PIPE_DEV_NAME_MAX] = {0}; + + ret = PipeDevRegister(devName, PIPE_DEV_NAME_MAX); + if (ret < 0) { + errno = -ret; + return -1; + } + + filedes[0] = open(devName, O_RDONLY); + filedes[1] = open(devName, O_WRONLY); + + return ENOERR; +} + +UINT32 OsPipeInit(VOID) +{ + UINT32 ret; + + ret = LOS_MuxCreate(&g_devListMutex); + if (ret != LOS_OK) { + return ret; + } + + ret = LOS_MuxCreate(&g_devFdMutex); + if (ret != LOS_OK) { + LOS_MuxDelete(g_devListMutex); + return ret; + } + + return LOS_OK; +} +#endif diff --git a/kal/posix/src/poll.c b/kal/posix/src/poll.c new file mode 100644 index 00000000..18c2fd94 --- /dev/null +++ b/kal/posix/src/poll.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2022-2022 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 "poll.h" +#include +#include +#include "securec.h" +#include "poll_impl.h" +#include "los_interrupt.h" +#include "los_memory.h" + +VOID PollWaitQueueInit(struct PollWaitQueue *waitQueue) +{ + if (waitQueue == NULL) { + return; + } + LOS_ListInit(&waitQueue->queue); +} + +STATIC INLINE VOID SetAddPollWaitFlag(struct PollTable *table, BOOL addQueueFlag) +{ + table->addQueueFlag = addQueueFlag; +} + +STATIC VOID DestroyPollWait(struct PollTable *table) +{ + UINT32 intSave; + struct PollWaitNode *waitNode = table->node; + + intSave = LOS_IntLock(); + LOS_ListDelete(&waitNode->node); + LOS_IntRestore(intSave); + + (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, waitNode); + if (LOS_SemDelete(table->sem) != LOS_OK) { + PRINT_ERR("destroy poll sem failed!\n"); + } +} + +STATIC VOID AddPollWaitQueue(struct PollWaitQueue *waitQueue, struct PollTable *table) +{ + UINT32 intSave; + struct PollWaitNode *waitNode = LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(struct PollWaitNode)); + if (waitNode == NULL) { + return; + } + + intSave = LOS_IntLock(); + waitNode->table = table; + LOS_ListAdd(&waitQueue->queue, &waitNode->node); + table->node = waitNode; + LOS_IntRestore(intSave); +} + +STATIC INT32 WaitSemTime(struct PollTable *table, UINT32 timeout) +{ + if (timeout != 0) { + return LOS_SemPend(table->sem, LOS_MS2Tick(timeout)); + } else { + return LOS_SemPend(table->sem, LOS_WAIT_FOREVER); + } +} + +STATIC INT32 QueryFds(struct pollfd *fds, nfds_t nfds, struct PollTable *table) +{ + UINT32 i; + INT32 ret; + INT32 count = 0; + + if (((nfds != 0) && (fds == NULL)) || (table == NULL)) { + errno = EINVAL; + return -1; + } + + for (i = 0; i < nfds; i++) { + struct pollfd *tmpFds = &fds[i]; + if (tmpFds->fd < 0) { + errno = EBADF; + return -1; + } + table->event = tmpFds->events | POLLERR | POLLHUP; + + ret = PollQueryFd(tmpFds->fd, table); + if (ret < 0) { + errno = -ret; + return -1; + } + + tmpFds->revents = (tmpFds->events | POLLERR | POLLHUP) & (PollEvent)ret; + if (tmpFds->revents != 0) { + count++; + SetAddPollWaitFlag(table, FALSE); + } + } + + return count; +} + +VOID PollNotify(struct PollWaitQueue *waitQueue, PollEvent event) +{ + UINT32 intSave; + struct PollWaitNode *waitNode = NULL; + + intSave = LOS_IntLock(); + LOS_DL_LIST_FOR_EACH_ENTRY(waitNode, &waitQueue->queue, struct PollWaitNode, node) { + if (!event || (event & waitNode->table->event)) { + if (LOS_SemPost(waitNode->table->sem) != LOS_OK) { + PRINT_ERR("poll notify sem post failed!\n"); + } + } + } + LOS_IntRestore(intSave); +} + +VOID PollWait(struct PollWaitQueue *waitQueue, struct PollTable *table) +{ + if ((waitQueue == NULL) || (table == NULL)) { + return; + } + + if (table->addQueueFlag == TRUE) { + AddPollWaitQueue(waitQueue, table); + } +} + +STATIC INLINE INT32 PollTimedWait(struct pollfd *fds, nfds_t nfds, struct PollTable *table, INT32 timeout) +{ + struct timespec startTime = {0}; + struct timespec curTime = {0}; + INT32 left, last; + INT32 ret; + INT32 count = 0; + + if (timeout > 0) { + clock_gettime(CLOCK_REALTIME, &startTime); + } + + left = timeout; + while (count == 0) { + if (timeout < 0) { + ret = WaitSemTime(table, 0); + if (ret != 0) { + break; + } + } else if (left <= 0) { + break; + } else if (left > 0) { + clock_gettime(CLOCK_REALTIME, &curTime); + last = (INT32)((curTime.tv_sec - startTime.tv_sec) * OS_SYS_MS_PER_SECOND + + (curTime.tv_nsec - startTime.tv_nsec) / (OS_SYS_NS_PER_SECOND / OS_SYS_MS_PER_SECOND)); + if (last >= timeout) { + break; + } else { + left = timeout - last; + } + + ret = WaitSemTime(table, left); + if (ret == LOS_ERRNO_SEM_TIMEOUT) { + errno = ETIMEDOUT; + break; + } + } + count = QueryFds(fds, nfds, table); + } + + return count; +} + +int poll(struct pollfd *fds, nfds_t nfds, int timeout) +{ + struct PollTable table = {0}; + INT32 count; + + if (LOS_SemCreate(0, &table.sem) != LOS_OK) { + errno = EINVAL; + return -1; + } + + SetAddPollWaitFlag(&table, ((timeout == 0) ? FALSE : TRUE)); + + count = QueryFds(fds, nfds, &table); + if (count != 0) { + goto DONE; + } + + if (timeout == 0) { + goto DONE; + } + + SetAddPollWaitFlag(&table, FALSE); + + count = PollTimedWait(fds, nfds, &table, timeout); + +DONE: + DestroyPollWait(&table); + return count; +} diff --git a/kernel/include/los_config.h b/kernel/include/los_config.h index 54e5402e..5298c719 100644 --- a/kernel/include/los_config.h +++ b/kernel/include/los_config.h @@ -649,6 +649,14 @@ extern UINT8 *m_aucSysMem0; #define LOSCFG_TASK_DELETE_EXTENSION_HOOK(taskCB) #endif +/** + * @ingroup los_config + * Configuration item to enable pipe device. + */ +#ifndef LOSCFG_PIPE_DEV +#define LOSCFG_POSIX_PIPE_API 0 +#endif + #ifdef __cplusplus #if __cplusplus } diff --git a/kernel/src/los_init.c b/kernel/src/los_init.c index 27e83130..2a47fc88 100644 --- a/kernel/src/los_init.c +++ b/kernel/src/los_init.c @@ -74,6 +74,10 @@ #include "los_lmk.h" #endif +#if (LOSCFG_POSIX_PIPE_API == 1) +#include "pipe_impl.h" +#endif + /***************************************************************************** Function : LOS_Reboot Description : system exception, die in here, wait for watchdog. @@ -238,6 +242,14 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_KernelInit(VOID) } #endif +#if (LOSCFG_POSIX_PIPE_API == 1) + ret = OsPipeInit(); + if (ret != LOS_OK) { + PRINT_ERR("Pipe init failed!\n"); + return ret; + } +#endif + return LOS_OK; } diff --git a/kernel/src/los_task.c b/kernel/src/los_task.c index 8632df9f..3ada9de5 100644 --- a/kernel/src/los_task.c +++ b/kernel/src/los_task.c @@ -721,8 +721,8 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreateOnly(UINT32 *taskID, TSK_INIT_PARAM_S intSave = LOS_IntLock(); if (LOS_ListEmpty(&g_losFreeTask)) { - retVal = LOS_ERRNO_TSK_TCB_UNAVAILABLE; - OS_GOTO_ERREND(); + LOS_IntRestore(intSave); + return LOS_ERRNO_TSK_TCB_UNAVAILABLE; } taskCB = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&g_losFreeTask)); @@ -761,10 +761,6 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreateOnly(UINT32 *taskID, TSK_INIT_PARAM_S *taskID = taskCB->taskID; OsHookCall(LOS_HOOK_TYPE_TASK_CREATE, taskCB); return retVal; - -LOS_ERREND: - LOS_IntRestore(intSave); - return retVal; } /*****************************************************************************