xref: /kernel/liteos_m/kal/posix/src/poll.c (revision 3d8536b4)
13d8536b4Sopenharmony_ci/*
23d8536b4Sopenharmony_ci * Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved.
33d8536b4Sopenharmony_ci *
43d8536b4Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
53d8536b4Sopenharmony_ci * are permitted provided that the following conditions are met:
63d8536b4Sopenharmony_ci *
73d8536b4Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, this list of
83d8536b4Sopenharmony_ci *    conditions and the following disclaimer.
93d8536b4Sopenharmony_ci *
103d8536b4Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, this list
113d8536b4Sopenharmony_ci *    of conditions and the following disclaimer in the documentation and/or other materials
123d8536b4Sopenharmony_ci *    provided with the distribution.
133d8536b4Sopenharmony_ci *
143d8536b4Sopenharmony_ci * 3. Neither the name of the copyright holder nor the names of its contributors may be used
153d8536b4Sopenharmony_ci *    to endorse or promote products derived from this software without specific prior written
163d8536b4Sopenharmony_ci *    permission.
173d8536b4Sopenharmony_ci *
183d8536b4Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
193d8536b4Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
203d8536b4Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
213d8536b4Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
223d8536b4Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
233d8536b4Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
243d8536b4Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
253d8536b4Sopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
263d8536b4Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
273d8536b4Sopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
283d8536b4Sopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
293d8536b4Sopenharmony_ci */
303d8536b4Sopenharmony_ci
313d8536b4Sopenharmony_ci#include "poll.h"
323d8536b4Sopenharmony_ci#include <sys/time.h>
333d8536b4Sopenharmony_ci#include <time.h>
343d8536b4Sopenharmony_ci#include "securec.h"
353d8536b4Sopenharmony_ci#include "poll_impl.h"
363d8536b4Sopenharmony_ci#include "los_interrupt.h"
373d8536b4Sopenharmony_ci#include "los_memory.h"
383d8536b4Sopenharmony_ci
393d8536b4Sopenharmony_ciVOID PollWaitQueueInit(struct PollWaitQueue *waitQueue)
403d8536b4Sopenharmony_ci{
413d8536b4Sopenharmony_ci    if (waitQueue == NULL) {
423d8536b4Sopenharmony_ci        return;
433d8536b4Sopenharmony_ci    }
443d8536b4Sopenharmony_ci    LOS_ListInit(&waitQueue->queue);
453d8536b4Sopenharmony_ci}
463d8536b4Sopenharmony_ci
473d8536b4Sopenharmony_ciSTATIC INLINE VOID SetAddPollWaitFlag(struct PollTable *table, BOOL addQueueFlag)
483d8536b4Sopenharmony_ci{
493d8536b4Sopenharmony_ci    table->addQueueFlag = addQueueFlag;
503d8536b4Sopenharmony_ci}
513d8536b4Sopenharmony_ci
523d8536b4Sopenharmony_ciSTATIC VOID DestroyPollWait(struct PollTable *table)
533d8536b4Sopenharmony_ci{
543d8536b4Sopenharmony_ci    UINT32 intSave;
553d8536b4Sopenharmony_ci    struct PollWaitNode *waitNode = table->node;
563d8536b4Sopenharmony_ci
573d8536b4Sopenharmony_ci    intSave = LOS_IntLock();
583d8536b4Sopenharmony_ci    LOS_ListDelete(&waitNode->node);
593d8536b4Sopenharmony_ci    LOS_IntRestore(intSave);
603d8536b4Sopenharmony_ci
613d8536b4Sopenharmony_ci    (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, waitNode);
623d8536b4Sopenharmony_ci    if (LOS_SemDelete(table->sem) != LOS_OK) {
633d8536b4Sopenharmony_ci        PRINT_ERR("destroy poll sem failed!\n");
643d8536b4Sopenharmony_ci    }
653d8536b4Sopenharmony_ci}
663d8536b4Sopenharmony_ci
673d8536b4Sopenharmony_ciSTATIC VOID AddPollWaitQueue(struct PollWaitQueue *waitQueue, struct PollTable *table)
683d8536b4Sopenharmony_ci{
693d8536b4Sopenharmony_ci    UINT32 intSave;
703d8536b4Sopenharmony_ci    struct PollWaitNode *waitNode = LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(struct PollWaitNode));
713d8536b4Sopenharmony_ci    if (waitNode == NULL) {
723d8536b4Sopenharmony_ci        return;
733d8536b4Sopenharmony_ci    }
743d8536b4Sopenharmony_ci
753d8536b4Sopenharmony_ci    intSave = LOS_IntLock();
763d8536b4Sopenharmony_ci    waitNode->table = table;
773d8536b4Sopenharmony_ci    LOS_ListAdd(&waitQueue->queue, &waitNode->node);
783d8536b4Sopenharmony_ci    table->node = waitNode;
793d8536b4Sopenharmony_ci    LOS_IntRestore(intSave);
803d8536b4Sopenharmony_ci}
813d8536b4Sopenharmony_ci
823d8536b4Sopenharmony_ciSTATIC INT32 WaitSemTime(struct PollTable *table, UINT32 timeout)
833d8536b4Sopenharmony_ci{
843d8536b4Sopenharmony_ci    if (timeout != 0) {
853d8536b4Sopenharmony_ci        return LOS_SemPend(table->sem, LOS_MS2Tick(timeout));
863d8536b4Sopenharmony_ci    } else {
873d8536b4Sopenharmony_ci        return LOS_SemPend(table->sem, LOS_WAIT_FOREVER);
883d8536b4Sopenharmony_ci    }
893d8536b4Sopenharmony_ci}
903d8536b4Sopenharmony_ci
913d8536b4Sopenharmony_ciSTATIC INT32 QueryFds(struct pollfd *fds, nfds_t nfds, struct PollTable *table)
923d8536b4Sopenharmony_ci{
933d8536b4Sopenharmony_ci    UINT32 i;
943d8536b4Sopenharmony_ci    INT32 ret;
953d8536b4Sopenharmony_ci    INT32 count = 0;
963d8536b4Sopenharmony_ci
973d8536b4Sopenharmony_ci    if (((nfds != 0) && (fds == NULL)) || (table == NULL)) {
983d8536b4Sopenharmony_ci        errno = EINVAL;
993d8536b4Sopenharmony_ci        return -1;
1003d8536b4Sopenharmony_ci    }
1013d8536b4Sopenharmony_ci
1023d8536b4Sopenharmony_ci    for (i = 0; i < nfds; i++) {
1033d8536b4Sopenharmony_ci        struct pollfd *tmpFds = &fds[i];
1043d8536b4Sopenharmony_ci        if (tmpFds->fd < 0) {
1053d8536b4Sopenharmony_ci            errno = EBADF;
1063d8536b4Sopenharmony_ci            return -1;
1073d8536b4Sopenharmony_ci        }
1083d8536b4Sopenharmony_ci        table->event = tmpFds->events | POLLERR | POLLHUP;
1093d8536b4Sopenharmony_ci
1103d8536b4Sopenharmony_ci        ret = PollQueryFd(tmpFds->fd, table);
1113d8536b4Sopenharmony_ci        if (ret < 0) {
1123d8536b4Sopenharmony_ci            errno = -ret;
1133d8536b4Sopenharmony_ci            return -1;
1143d8536b4Sopenharmony_ci        }
1153d8536b4Sopenharmony_ci
1163d8536b4Sopenharmony_ci        tmpFds->revents = (tmpFds->events | POLLERR | POLLHUP) & (PollEvent)ret;
1173d8536b4Sopenharmony_ci        if (tmpFds->revents != 0) {
1183d8536b4Sopenharmony_ci            count++;
1193d8536b4Sopenharmony_ci            SetAddPollWaitFlag(table, FALSE);
1203d8536b4Sopenharmony_ci        }
1213d8536b4Sopenharmony_ci    }
1223d8536b4Sopenharmony_ci
1233d8536b4Sopenharmony_ci    return count;
1243d8536b4Sopenharmony_ci}
1253d8536b4Sopenharmony_ci
1263d8536b4Sopenharmony_ciVOID PollNotify(struct PollWaitQueue *waitQueue, PollEvent event)
1273d8536b4Sopenharmony_ci{
1283d8536b4Sopenharmony_ci    UINT32 intSave;
1293d8536b4Sopenharmony_ci    struct PollWaitNode *waitNode = NULL;
1303d8536b4Sopenharmony_ci
1313d8536b4Sopenharmony_ci    if (waitQueue == NULL) {
1323d8536b4Sopenharmony_ci        return;
1333d8536b4Sopenharmony_ci    }
1343d8536b4Sopenharmony_ci
1353d8536b4Sopenharmony_ci    intSave = LOS_IntLock();
1363d8536b4Sopenharmony_ci    LOS_DL_LIST_FOR_EACH_ENTRY(waitNode, &waitQueue->queue, struct PollWaitNode, node) {
1373d8536b4Sopenharmony_ci        if (!event || (event & waitNode->table->event)) {
1383d8536b4Sopenharmony_ci            if (LOS_SemPost(waitNode->table->sem) != LOS_OK) {
1393d8536b4Sopenharmony_ci                PRINT_ERR("poll notify sem post failed!\n");
1403d8536b4Sopenharmony_ci            }
1413d8536b4Sopenharmony_ci        }
1423d8536b4Sopenharmony_ci    }
1433d8536b4Sopenharmony_ci    LOS_IntRestore(intSave);
1443d8536b4Sopenharmony_ci}
1453d8536b4Sopenharmony_ci
1463d8536b4Sopenharmony_ciVOID PollWait(struct PollWaitQueue *waitQueue, struct PollTable *table)
1473d8536b4Sopenharmony_ci{
1483d8536b4Sopenharmony_ci    if ((waitQueue == NULL) || (table == NULL)) {
1493d8536b4Sopenharmony_ci        return;
1503d8536b4Sopenharmony_ci    }
1513d8536b4Sopenharmony_ci
1523d8536b4Sopenharmony_ci    if (table->addQueueFlag == TRUE) {
1533d8536b4Sopenharmony_ci        AddPollWaitQueue(waitQueue, table);
1543d8536b4Sopenharmony_ci    }
1553d8536b4Sopenharmony_ci}
1563d8536b4Sopenharmony_ci
1573d8536b4Sopenharmony_ciSTATIC INLINE INT32 PollTimedWait(struct pollfd *fds, nfds_t nfds, struct PollTable *table, INT32 timeout)
1583d8536b4Sopenharmony_ci{
1593d8536b4Sopenharmony_ci    struct timespec startTime = {0};
1603d8536b4Sopenharmony_ci    struct timespec curTime = {0};
1613d8536b4Sopenharmony_ci    INT32 left, last;
1623d8536b4Sopenharmony_ci    INT32 ret;
1633d8536b4Sopenharmony_ci    INT32 count = 0;
1643d8536b4Sopenharmony_ci
1653d8536b4Sopenharmony_ci    if (timeout > 0) {
1663d8536b4Sopenharmony_ci        clock_gettime(CLOCK_REALTIME, &startTime);
1673d8536b4Sopenharmony_ci    }
1683d8536b4Sopenharmony_ci
1693d8536b4Sopenharmony_ci    left = timeout;
1703d8536b4Sopenharmony_ci    while (count == 0) {
1713d8536b4Sopenharmony_ci        if (timeout < 0) {
1723d8536b4Sopenharmony_ci            ret = WaitSemTime(table, 0);
1733d8536b4Sopenharmony_ci            if (ret != 0) {
1743d8536b4Sopenharmony_ci                break;
1753d8536b4Sopenharmony_ci            }
1763d8536b4Sopenharmony_ci        } else if (left <= 0) {
1773d8536b4Sopenharmony_ci            break;
1783d8536b4Sopenharmony_ci        } else {
1793d8536b4Sopenharmony_ci            clock_gettime(CLOCK_REALTIME, &curTime);
1803d8536b4Sopenharmony_ci            last = (INT32)((curTime.tv_sec - startTime.tv_sec) * OS_SYS_MS_PER_SECOND +
1813d8536b4Sopenharmony_ci                   (curTime.tv_nsec - startTime.tv_nsec) / (OS_SYS_NS_PER_SECOND / OS_SYS_MS_PER_SECOND));
1823d8536b4Sopenharmony_ci            if (last >= timeout) {
1833d8536b4Sopenharmony_ci                break;
1843d8536b4Sopenharmony_ci            } else {
1853d8536b4Sopenharmony_ci                left = timeout - last;
1863d8536b4Sopenharmony_ci            }
1873d8536b4Sopenharmony_ci
1883d8536b4Sopenharmony_ci            ret = WaitSemTime(table, left);
1893d8536b4Sopenharmony_ci            if (ret == LOS_ERRNO_SEM_TIMEOUT) {
1903d8536b4Sopenharmony_ci                errno = ETIMEDOUT;
1913d8536b4Sopenharmony_ci                break;
1923d8536b4Sopenharmony_ci            }
1933d8536b4Sopenharmony_ci        }
1943d8536b4Sopenharmony_ci        count = QueryFds(fds, nfds, table);
1953d8536b4Sopenharmony_ci    }
1963d8536b4Sopenharmony_ci
1973d8536b4Sopenharmony_ci    return count;
1983d8536b4Sopenharmony_ci}
1993d8536b4Sopenharmony_ci
2003d8536b4Sopenharmony_ciint poll(struct pollfd *fds, nfds_t nfds, int timeout)
2013d8536b4Sopenharmony_ci{
2023d8536b4Sopenharmony_ci    struct PollTable table = {0};
2033d8536b4Sopenharmony_ci    INT32 count;
2043d8536b4Sopenharmony_ci
2053d8536b4Sopenharmony_ci    if (LOS_SemCreate(0, &table.sem) != LOS_OK) {
2063d8536b4Sopenharmony_ci        errno = EINVAL;
2073d8536b4Sopenharmony_ci        return -1;
2083d8536b4Sopenharmony_ci    }
2093d8536b4Sopenharmony_ci
2103d8536b4Sopenharmony_ci    SetAddPollWaitFlag(&table, ((timeout == 0) ? FALSE : TRUE));
2113d8536b4Sopenharmony_ci
2123d8536b4Sopenharmony_ci    count = QueryFds(fds, nfds, &table);
2133d8536b4Sopenharmony_ci    if (count != 0) {
2143d8536b4Sopenharmony_ci        goto DONE;
2153d8536b4Sopenharmony_ci    }
2163d8536b4Sopenharmony_ci
2173d8536b4Sopenharmony_ci    if (timeout == 0) {
2183d8536b4Sopenharmony_ci        goto DONE;
2193d8536b4Sopenharmony_ci    }
2203d8536b4Sopenharmony_ci
2213d8536b4Sopenharmony_ci    SetAddPollWaitFlag(&table, FALSE);
2223d8536b4Sopenharmony_ci
2233d8536b4Sopenharmony_ci    count = PollTimedWait(fds, nfds, &table, timeout);
2243d8536b4Sopenharmony_ci
2253d8536b4Sopenharmony_ciDONE:
2263d8536b4Sopenharmony_ci    DestroyPollWait(&table);
2273d8536b4Sopenharmony_ci    return count;
2283d8536b4Sopenharmony_ci}
229