xref: /kernel/liteos_a/compat/posix/src/mqueue.c (revision 0d163575)
10d163575Sopenharmony_ci/*
20d163575Sopenharmony_ci * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
30d163575Sopenharmony_ci * Copyright (c) 2020-2023 Huawei Device Co., Ltd. All rights reserved.
40d163575Sopenharmony_ci *
50d163575Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification,
60d163575Sopenharmony_ci * are permitted provided that the following conditions are met:
70d163575Sopenharmony_ci *
80d163575Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, this list of
90d163575Sopenharmony_ci *    conditions and the following disclaimer.
100d163575Sopenharmony_ci *
110d163575Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, this list
120d163575Sopenharmony_ci *    of conditions and the following disclaimer in the documentation and/or other materials
130d163575Sopenharmony_ci *    provided with the distribution.
140d163575Sopenharmony_ci *
150d163575Sopenharmony_ci * 3. Neither the name of the copyright holder nor the names of its contributors may be used
160d163575Sopenharmony_ci *    to endorse or promote products derived from this software without specific prior written
170d163575Sopenharmony_ci *    permission.
180d163575Sopenharmony_ci *
190d163575Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
200d163575Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
210d163575Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
220d163575Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
230d163575Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
240d163575Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
250d163575Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
260d163575Sopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
270d163575Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
280d163575Sopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
290d163575Sopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
300d163575Sopenharmony_ci */
310d163575Sopenharmony_ci
320d163575Sopenharmony_ci#include "mqueue.h"
330d163575Sopenharmony_ci#ifdef LOSCFG_FS_VFS
340d163575Sopenharmony_ci#include "fcntl.h"
350d163575Sopenharmony_ci#include "pthread.h"
360d163575Sopenharmony_ci#include "map_error.h"
370d163575Sopenharmony_ci#include "time_posix.h"
380d163575Sopenharmony_ci#include "los_memory.h"
390d163575Sopenharmony_ci#include "los_vm_map.h"
400d163575Sopenharmony_ci#include "los_process_pri.h"
410d163575Sopenharmony_ci#include "fs/file.h"
420d163575Sopenharmony_ci#include "user_copy.h"
430d163575Sopenharmony_ci
440d163575Sopenharmony_ci
450d163575Sopenharmony_ci#define FNONBLOCK   O_NONBLOCK
460d163575Sopenharmony_ci
470d163575Sopenharmony_ci#ifndef LOSCFG_IPC_CONTAINER
480d163575Sopenharmony_ci/* GLOBALS */
490d163575Sopenharmony_ciSTATIC fd_set g_queueFdSet;
500d163575Sopenharmony_ciSTATIC struct mqarray g_queueTable[LOSCFG_BASE_IPC_QUEUE_LIMIT];
510d163575Sopenharmony_ciSTATIC pthread_mutex_t g_mqueueMutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
520d163575Sopenharmony_ciSTATIC struct mqpersonal *g_mqPrivBuf[MAX_MQ_FD];
530d163575Sopenharmony_ci
540d163575Sopenharmony_ci#define IPC_QUEUE_FD_SET g_queueFdSet
550d163575Sopenharmony_ci#define IPC_QUEUE_TABLE  g_queueTable
560d163575Sopenharmony_ci#define IPC_QUEUE_MUTEX  g_mqueueMutex
570d163575Sopenharmony_ci#define IPC_QUEUE_MQ_PRIV_BUF g_mqPrivBuf
580d163575Sopenharmony_ci#endif
590d163575Sopenharmony_ci
600d163575Sopenharmony_ci/* LOCAL FUNCTIONS */
610d163575Sopenharmony_ciSTATIC INLINE INT32 MqNameCheck(const CHAR *mqName)
620d163575Sopenharmony_ci{
630d163575Sopenharmony_ci    if (mqName == NULL) {
640d163575Sopenharmony_ci        errno = EINVAL;
650d163575Sopenharmony_ci        return -1;
660d163575Sopenharmony_ci    }
670d163575Sopenharmony_ci
680d163575Sopenharmony_ci    if (strlen(mqName) == 0) {
690d163575Sopenharmony_ci        errno = EINVAL;
700d163575Sopenharmony_ci        return -1;
710d163575Sopenharmony_ci    }
720d163575Sopenharmony_ci
730d163575Sopenharmony_ci    if (strlen(mqName) > (PATH_MAX - 1)) {
740d163575Sopenharmony_ci        errno = ENAMETOOLONG;
750d163575Sopenharmony_ci        return -1;
760d163575Sopenharmony_ci    }
770d163575Sopenharmony_ci    return 0;
780d163575Sopenharmony_ci}
790d163575Sopenharmony_ci
800d163575Sopenharmony_ciSTATIC INLINE UINT32 GetMqueueCBByID(UINT32 queueID, LosQueueCB **queueCB)
810d163575Sopenharmony_ci{
820d163575Sopenharmony_ci    LosQueueCB *tmpQueueCB = NULL;
830d163575Sopenharmony_ci    if (queueCB == NULL) {
840d163575Sopenharmony_ci        errno = EINVAL;
850d163575Sopenharmony_ci        return LOS_ERRNO_QUEUE_READ_PTR_NULL;
860d163575Sopenharmony_ci    }
870d163575Sopenharmony_ci    tmpQueueCB = GET_QUEUE_HANDLE(queueID);
880d163575Sopenharmony_ci    if ((GET_QUEUE_INDEX(queueID) >= LOSCFG_BASE_IPC_QUEUE_LIMIT) || (tmpQueueCB->queueID != queueID)) {
890d163575Sopenharmony_ci        return LOS_ERRNO_QUEUE_INVALID;
900d163575Sopenharmony_ci    }
910d163575Sopenharmony_ci    *queueCB = tmpQueueCB;
920d163575Sopenharmony_ci
930d163575Sopenharmony_ci    return LOS_OK;
940d163575Sopenharmony_ci}
950d163575Sopenharmony_ci
960d163575Sopenharmony_ciSTATIC INLINE struct mqarray *GetMqueueCBByName(const CHAR *name)
970d163575Sopenharmony_ci{
980d163575Sopenharmony_ci    UINT32 index;
990d163575Sopenharmony_ci    UINT32 mylen = strlen(name);
1000d163575Sopenharmony_ci
1010d163575Sopenharmony_ci    for (index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {
1020d163575Sopenharmony_ci        if ((IPC_QUEUE_TABLE[index].mq_name == NULL) || (strlen(IPC_QUEUE_TABLE[index].mq_name) != mylen)) {
1030d163575Sopenharmony_ci            continue;
1040d163575Sopenharmony_ci        }
1050d163575Sopenharmony_ci
1060d163575Sopenharmony_ci        if (strncmp(name, (const CHAR *)(IPC_QUEUE_TABLE[index].mq_name), mylen) == 0) {
1070d163575Sopenharmony_ci            return &(IPC_QUEUE_TABLE[index]);
1080d163575Sopenharmony_ci        }
1090d163575Sopenharmony_ci    }
1100d163575Sopenharmony_ci    return NULL;
1110d163575Sopenharmony_ci}
1120d163575Sopenharmony_ci
1130d163575Sopenharmony_ciSTATIC INT32 DoMqueueDelete(struct mqarray *mqueueCB)
1140d163575Sopenharmony_ci{
1150d163575Sopenharmony_ci    UINT32 ret;
1160d163575Sopenharmony_ci#ifdef LOSCFG_KERNEL_IPC_PLIMIT
1170d163575Sopenharmony_ci    OsIPCLimitMqFree();
1180d163575Sopenharmony_ci#endif
1190d163575Sopenharmony_ci    if (mqueueCB->mq_name != NULL) {
1200d163575Sopenharmony_ci        LOS_MemFree(OS_SYS_MEM_ADDR, mqueueCB->mq_name);
1210d163575Sopenharmony_ci        mqueueCB->mq_name = NULL;
1220d163575Sopenharmony_ci    }
1230d163575Sopenharmony_ci
1240d163575Sopenharmony_ci    mqueueCB->mqcb = NULL;
1250d163575Sopenharmony_ci    /* When mqueue-list head node needed free ,reset the mode_data */
1260d163575Sopenharmony_ci    mqueueCB->mode_data.data = 0;
1270d163575Sopenharmony_ci    mqueueCB->euid = -1;
1280d163575Sopenharmony_ci    mqueueCB->egid = -1;
1290d163575Sopenharmony_ci    mqueueCB->mq_notify.pid = 0;
1300d163575Sopenharmony_ci
1310d163575Sopenharmony_ci    ret = LOS_QueueDelete(mqueueCB->mq_id);
1320d163575Sopenharmony_ci    switch (ret) {
1330d163575Sopenharmony_ci        case LOS_OK:
1340d163575Sopenharmony_ci            return 0;
1350d163575Sopenharmony_ci        case LOS_ERRNO_QUEUE_NOT_FOUND:
1360d163575Sopenharmony_ci        case LOS_ERRNO_QUEUE_NOT_CREATE:
1370d163575Sopenharmony_ci        case LOS_ERRNO_QUEUE_IN_TSKUSE:
1380d163575Sopenharmony_ci        case LOS_ERRNO_QUEUE_IN_TSKWRITE:
1390d163575Sopenharmony_ci            errno = EAGAIN;
1400d163575Sopenharmony_ci            return -1;
1410d163575Sopenharmony_ci        default:
1420d163575Sopenharmony_ci            errno = EINVAL;
1430d163575Sopenharmony_ci            return -1;
1440d163575Sopenharmony_ci    }
1450d163575Sopenharmony_ci}
1460d163575Sopenharmony_ci
1470d163575Sopenharmony_ciSTATIC int SaveMqueueName(const CHAR *mqName, struct mqarray *mqueueCB)
1480d163575Sopenharmony_ci{
1490d163575Sopenharmony_ci    size_t nameLen;
1500d163575Sopenharmony_ci
1510d163575Sopenharmony_ci    nameLen = strlen(mqName); /* sys_mq_open has checked name and name length */
1520d163575Sopenharmony_ci    mqueueCB->mq_name = (char *)LOS_MemAlloc(OS_SYS_MEM_ADDR, nameLen + 1);
1530d163575Sopenharmony_ci    if (mqueueCB->mq_name == NULL) {
1540d163575Sopenharmony_ci        errno = ENOMEM;
1550d163575Sopenharmony_ci        return LOS_NOK;
1560d163575Sopenharmony_ci    }
1570d163575Sopenharmony_ci
1580d163575Sopenharmony_ci    if (strncpy_s(mqueueCB->mq_name, (nameLen + 1), mqName, nameLen) != EOK) {
1590d163575Sopenharmony_ci        LOS_MemFree(OS_SYS_MEM_ADDR, mqueueCB->mq_name);
1600d163575Sopenharmony_ci        mqueueCB->mq_name = NULL;
1610d163575Sopenharmony_ci        errno = EINVAL;
1620d163575Sopenharmony_ci        return LOS_NOK;
1630d163575Sopenharmony_ci    }
1640d163575Sopenharmony_ci    mqueueCB->mq_name[nameLen] = '\0';
1650d163575Sopenharmony_ci    return LOS_OK;
1660d163575Sopenharmony_ci}
1670d163575Sopenharmony_ci
1680d163575Sopenharmony_ciSTATIC VOID MqueueCBInit(struct mqarray *mqueueCB, const struct mq_attr *attr, INT32 openFlag, UINT32 mode)
1690d163575Sopenharmony_ci{
1700d163575Sopenharmony_ci    mqueueCB->unlinkflag = FALSE;
1710d163575Sopenharmony_ci    mqueueCB->unlink_ref = 0;
1720d163575Sopenharmony_ci    mqueueCB->mq_personal->mq_status = MQ_USE_MAGIC;
1730d163575Sopenharmony_ci    mqueueCB->mq_personal->mq_next = NULL;
1740d163575Sopenharmony_ci    mqueueCB->mq_personal->mq_posixdes = mqueueCB;
1750d163575Sopenharmony_ci    mqueueCB->mq_personal->mq_flags = (INT32)((UINT32)openFlag | ((UINT32)attr->mq_flags & (UINT32)FNONBLOCK));
1760d163575Sopenharmony_ci    mqueueCB->mq_personal->mq_mode = mode;
1770d163575Sopenharmony_ci    mqueueCB->mq_personal->mq_refcount = 0;
1780d163575Sopenharmony_ci    mqueueCB->mq_notify.pid = 0;
1790d163575Sopenharmony_ci}
1800d163575Sopenharmony_ci
1810d163575Sopenharmony_ciSTATIC struct mqpersonal *DoMqueueCreate(const struct mq_attr *attr, const CHAR *mqName, INT32 openFlag, UINT32 mode)
1820d163575Sopenharmony_ci{
1830d163575Sopenharmony_ci    struct mqarray *mqueueCB = NULL;
1840d163575Sopenharmony_ci    UINT32 mqueueID;
1850d163575Sopenharmony_ci
1860d163575Sopenharmony_ci#ifdef LOSCFG_KERNEL_IPC_PLIMIT
1870d163575Sopenharmony_ci    if (OsIPCLimitMqAlloc() != LOS_OK) {
1880d163575Sopenharmony_ci        return (struct mqpersonal *)-1;
1890d163575Sopenharmony_ci    }
1900d163575Sopenharmony_ci#endif
1910d163575Sopenharmony_ci    UINT32 err = LOS_QueueCreate(NULL, attr->mq_maxmsg, &mqueueID, 0, attr->mq_msgsize);
1920d163575Sopenharmony_ci    if (map_errno(err) != ENOERR) {
1930d163575Sopenharmony_ci        goto ERROUT;
1940d163575Sopenharmony_ci    }
1950d163575Sopenharmony_ci
1960d163575Sopenharmony_ci    if (IPC_QUEUE_TABLE[GET_QUEUE_INDEX(mqueueID)].mqcb == NULL) {
1970d163575Sopenharmony_ci        mqueueCB = &(IPC_QUEUE_TABLE[GET_QUEUE_INDEX(mqueueID)]);
1980d163575Sopenharmony_ci        mqueueCB->mq_id = mqueueID;
1990d163575Sopenharmony_ci    }
2000d163575Sopenharmony_ci
2010d163575Sopenharmony_ci    if (mqueueCB == NULL) {
2020d163575Sopenharmony_ci        errno = EINVAL;
2030d163575Sopenharmony_ci        goto ERROUT;
2040d163575Sopenharmony_ci    }
2050d163575Sopenharmony_ci
2060d163575Sopenharmony_ci    if (SaveMqueueName(mqName, mqueueCB) != LOS_OK) {
2070d163575Sopenharmony_ci        goto ERROUT;
2080d163575Sopenharmony_ci    }
2090d163575Sopenharmony_ci
2100d163575Sopenharmony_ci    if (GetMqueueCBByID(mqueueCB->mq_id, &(mqueueCB->mqcb)) != LOS_OK) {
2110d163575Sopenharmony_ci        errno = ENOSPC;
2120d163575Sopenharmony_ci        goto ERROUT;
2130d163575Sopenharmony_ci    }
2140d163575Sopenharmony_ci
2150d163575Sopenharmony_ci    mqueueCB->mq_personal = (struct mqpersonal *)LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(struct mqpersonal));
2160d163575Sopenharmony_ci    if (mqueueCB->mq_personal == NULL) {
2170d163575Sopenharmony_ci        (VOID)LOS_QueueDelete(mqueueCB->mq_id);
2180d163575Sopenharmony_ci        mqueueCB->mqcb->queueHandle = NULL;
2190d163575Sopenharmony_ci        mqueueCB->mqcb = NULL;
2200d163575Sopenharmony_ci        errno = ENOSPC;
2210d163575Sopenharmony_ci        goto ERROUT;
2220d163575Sopenharmony_ci    }
2230d163575Sopenharmony_ci
2240d163575Sopenharmony_ci    MqueueCBInit(mqueueCB, attr, openFlag, mode);
2250d163575Sopenharmony_ci
2260d163575Sopenharmony_ci    return mqueueCB->mq_personal;
2270d163575Sopenharmony_ciERROUT:
2280d163575Sopenharmony_ci
2290d163575Sopenharmony_ci    if ((mqueueCB != NULL) && (mqueueCB->mq_name != NULL)) {
2300d163575Sopenharmony_ci        LOS_MemFree(OS_SYS_MEM_ADDR, mqueueCB->mq_name);
2310d163575Sopenharmony_ci        mqueueCB->mq_name = NULL;
2320d163575Sopenharmony_ci    }
2330d163575Sopenharmony_ci#ifdef LOSCFG_KERNEL_IPC_PLIMIT
2340d163575Sopenharmony_ci    OsIPCLimitMqFree();
2350d163575Sopenharmony_ci#endif
2360d163575Sopenharmony_ci    return (struct mqpersonal *)-1;
2370d163575Sopenharmony_ci}
2380d163575Sopenharmony_ci
2390d163575Sopenharmony_ciSTATIC struct mqpersonal *DoMqueueOpen(struct mqarray *mqueueCB, INT32 openFlag)
2400d163575Sopenharmony_ci{
2410d163575Sopenharmony_ci    struct mqpersonal *privateMqPersonal = NULL;
2420d163575Sopenharmony_ci
2430d163575Sopenharmony_ci    /* already have the same name of g_squeuetable */
2440d163575Sopenharmony_ci    if (mqueueCB->unlinkflag == TRUE) {
2450d163575Sopenharmony_ci        errno = EINVAL;
2460d163575Sopenharmony_ci        goto ERROUT;
2470d163575Sopenharmony_ci    }
2480d163575Sopenharmony_ci    /* alloc mqprivate and add to mqarray */
2490d163575Sopenharmony_ci    privateMqPersonal = (struct mqpersonal *)LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(struct mqpersonal));
2500d163575Sopenharmony_ci    if (privateMqPersonal == NULL) {
2510d163575Sopenharmony_ci        errno = ENOSPC;
2520d163575Sopenharmony_ci        goto ERROUT;
2530d163575Sopenharmony_ci    }
2540d163575Sopenharmony_ci
2550d163575Sopenharmony_ci    privateMqPersonal->mq_next = mqueueCB->mq_personal;
2560d163575Sopenharmony_ci    mqueueCB->mq_personal = privateMqPersonal;
2570d163575Sopenharmony_ci
2580d163575Sopenharmony_ci    privateMqPersonal->mq_posixdes = mqueueCB;
2590d163575Sopenharmony_ci    privateMqPersonal->mq_flags = openFlag;
2600d163575Sopenharmony_ci    privateMqPersonal->mq_status = MQ_USE_MAGIC;
2610d163575Sopenharmony_ci    privateMqPersonal->mq_refcount = 0;
2620d163575Sopenharmony_ci
2630d163575Sopenharmony_ci    return privateMqPersonal;
2640d163575Sopenharmony_ci
2650d163575Sopenharmony_ciERROUT:
2660d163575Sopenharmony_ci    return (struct mqpersonal *)-1;
2670d163575Sopenharmony_ci}
2680d163575Sopenharmony_ci
2690d163575Sopenharmony_ciSTATIC INT32 DoMqueueClose(struct mqpersonal *privateMqPersonal)
2700d163575Sopenharmony_ci{
2710d163575Sopenharmony_ci    struct mqarray *mqueueCB = NULL;
2720d163575Sopenharmony_ci    struct mqpersonal *tmp = NULL;
2730d163575Sopenharmony_ci    INT32 ret;
2740d163575Sopenharmony_ci
2750d163575Sopenharmony_ci    mqueueCB = privateMqPersonal->mq_posixdes;
2760d163575Sopenharmony_ci    if (mqueueCB == NULL || mqueueCB->mq_personal == NULL) {
2770d163575Sopenharmony_ci        errno = EBADF;
2780d163575Sopenharmony_ci        return LOS_NOK;
2790d163575Sopenharmony_ci    }
2800d163575Sopenharmony_ci
2810d163575Sopenharmony_ci    if ((mqueueCB->unlinkflag == TRUE) && (privateMqPersonal->mq_next == NULL)) {
2820d163575Sopenharmony_ci        ret = DoMqueueDelete(mqueueCB);
2830d163575Sopenharmony_ci        if (ret < 0) {
2840d163575Sopenharmony_ci            return ret;
2850d163575Sopenharmony_ci        }
2860d163575Sopenharmony_ci    }
2870d163575Sopenharmony_ci    /* find the personal and remove */
2880d163575Sopenharmony_ci    if (mqueueCB->mq_personal == privateMqPersonal) {
2890d163575Sopenharmony_ci        mqueueCB->mq_personal = privateMqPersonal->mq_next;
2900d163575Sopenharmony_ci    } else {
2910d163575Sopenharmony_ci        for (tmp = mqueueCB->mq_personal; tmp->mq_next != NULL; tmp = tmp->mq_next) {
2920d163575Sopenharmony_ci            if (tmp->mq_next == privateMqPersonal) {
2930d163575Sopenharmony_ci                break;
2940d163575Sopenharmony_ci            }
2950d163575Sopenharmony_ci        }
2960d163575Sopenharmony_ci        if (tmp->mq_next == NULL) {
2970d163575Sopenharmony_ci            errno = EBADF;
2980d163575Sopenharmony_ci            return LOS_NOK;
2990d163575Sopenharmony_ci        }
3000d163575Sopenharmony_ci        tmp->mq_next = privateMqPersonal->mq_next;
3010d163575Sopenharmony_ci    }
3020d163575Sopenharmony_ci    /* flag no use */
3030d163575Sopenharmony_ci    privateMqPersonal->mq_status = 0;
3040d163575Sopenharmony_ci
3050d163575Sopenharmony_ci    /* free the personal */
3060d163575Sopenharmony_ci    (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, privateMqPersonal);
3070d163575Sopenharmony_ci
3080d163575Sopenharmony_ci    return LOS_OK;
3090d163575Sopenharmony_ci}
3100d163575Sopenharmony_ci
3110d163575Sopenharmony_ci/* Translate a sysFd into privateMqPersonal */
3120d163575Sopenharmony_ciSTATIC struct mqpersonal *MqGetPrivDataBuff(mqd_t personal)
3130d163575Sopenharmony_ci{
3140d163575Sopenharmony_ci    INT32 sysFd = (INT32)personal;
3150d163575Sopenharmony_ci    INT32 id = sysFd - MQUEUE_FD_OFFSET;
3160d163575Sopenharmony_ci
3170d163575Sopenharmony_ci    /* Filter illegal id */
3180d163575Sopenharmony_ci    if ((id < 0) || (id >= MAX_MQ_FD)) {
3190d163575Sopenharmony_ci        errno = EBADF;
3200d163575Sopenharmony_ci        return NULL;
3210d163575Sopenharmony_ci    }
3220d163575Sopenharmony_ci    return IPC_QUEUE_MQ_PRIV_BUF[id];
3230d163575Sopenharmony_ci}
3240d163575Sopenharmony_ci
3250d163575Sopenharmony_ci/**
3260d163575Sopenharmony_ci * Alloc sysFd, storage mq private data, set using bit.
3270d163575Sopenharmony_ci *
3280d163575Sopenharmony_ci * @param maxfdp: Maximum allowed application of mqueue sysFd.
3290d163575Sopenharmony_ci * @param fdset: Mqueue sysFd bit map.
3300d163575Sopenharmony_ci * @param privateMqPersonal: Private data.
3310d163575Sopenharmony_ci * @return the index of the new fd; -1 on error
3320d163575Sopenharmony_ci */
3330d163575Sopenharmony_ciSTATIC INT32 MqAllocSysFd(int maxfdp, struct mqpersonal *privateMqPersonal)
3340d163575Sopenharmony_ci{
3350d163575Sopenharmony_ci    INT32 i;
3360d163575Sopenharmony_ci    fd_set *fdset = &IPC_QUEUE_FD_SET;
3370d163575Sopenharmony_ci    for (i = 0; i < maxfdp; i++) {
3380d163575Sopenharmony_ci        /* sysFd: used bit setting, and get the index of swtmrID buffer */
3390d163575Sopenharmony_ci        if (fdset && !(FD_ISSET(i + MQUEUE_FD_OFFSET, fdset))) {
3400d163575Sopenharmony_ci            FD_SET(i + MQUEUE_FD_OFFSET, fdset);
3410d163575Sopenharmony_ci            if (!IPC_QUEUE_MQ_PRIV_BUF[i]) {
3420d163575Sopenharmony_ci                IPC_QUEUE_MQ_PRIV_BUF[i] = privateMqPersonal;
3430d163575Sopenharmony_ci                return i + MQUEUE_FD_OFFSET;
3440d163575Sopenharmony_ci            }
3450d163575Sopenharmony_ci        }
3460d163575Sopenharmony_ci    }
3470d163575Sopenharmony_ci    return -1;
3480d163575Sopenharmony_ci}
3490d163575Sopenharmony_ci
3500d163575Sopenharmony_ciSTATIC VOID MqFreeSysFd(mqd_t personal)
3510d163575Sopenharmony_ci{
3520d163575Sopenharmony_ci    INT32 sysFd = (INT32)personal;
3530d163575Sopenharmony_ci    fd_set *fdset = &IPC_QUEUE_FD_SET;
3540d163575Sopenharmony_ci    if (fdset && FD_ISSET(sysFd, fdset)) {
3550d163575Sopenharmony_ci        FD_CLR(sysFd, fdset);
3560d163575Sopenharmony_ci        IPC_QUEUE_MQ_PRIV_BUF[sysFd - MQUEUE_FD_OFFSET] = NULL;
3570d163575Sopenharmony_ci    }
3580d163575Sopenharmony_ci}
3590d163575Sopenharmony_ci
3600d163575Sopenharmony_ci/* Mqueue fd reference count */
3610d163575Sopenharmony_civoid MqueueRefer(int sysFd)
3620d163575Sopenharmony_ci{
3630d163575Sopenharmony_ci    struct mqarray *mqueueCB = NULL;
3640d163575Sopenharmony_ci    struct mqpersonal *privateMqPersonal = NULL;
3650d163575Sopenharmony_ci
3660d163575Sopenharmony_ci    (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
3670d163575Sopenharmony_ci    /* Get the personal sysFd and reset personal fd -1 */
3680d163575Sopenharmony_ci    privateMqPersonal = MqGetPrivDataBuff((mqd_t)sysFd);
3690d163575Sopenharmony_ci    if (privateMqPersonal == NULL) {
3700d163575Sopenharmony_ci        goto OUT_UNLOCK;
3710d163575Sopenharmony_ci    }
3720d163575Sopenharmony_ci    mqueueCB = privateMqPersonal->mq_posixdes;
3730d163575Sopenharmony_ci    if (mqueueCB == NULL) {
3740d163575Sopenharmony_ci        goto OUT_UNLOCK;
3750d163575Sopenharmony_ci    }
3760d163575Sopenharmony_ci
3770d163575Sopenharmony_ci    privateMqPersonal->mq_refcount++;
3780d163575Sopenharmony_ciOUT_UNLOCK:
3790d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
3800d163575Sopenharmony_ci    return;
3810d163575Sopenharmony_ci}
3820d163575Sopenharmony_ci
3830d163575Sopenharmony_ciSTATIC INT32 MqTryClose(struct mqpersonal *privateMqPersonal)
3840d163575Sopenharmony_ci{
3850d163575Sopenharmony_ci    struct mqarray *mqueueCB = NULL;
3860d163575Sopenharmony_ci    mqueueCB = privateMqPersonal->mq_posixdes;
3870d163575Sopenharmony_ci    if (mqueueCB == NULL) {
3880d163575Sopenharmony_ci        errno = ENFILE;
3890d163575Sopenharmony_ci        return false;
3900d163575Sopenharmony_ci    }
3910d163575Sopenharmony_ci
3920d163575Sopenharmony_ci    if (privateMqPersonal->mq_refcount == 0) {
3930d163575Sopenharmony_ci        return TRUE;
3940d163575Sopenharmony_ci    }
3950d163575Sopenharmony_ci    privateMqPersonal->mq_refcount--;
3960d163575Sopenharmony_ci    return FALSE;
3970d163575Sopenharmony_ci}
3980d163575Sopenharmony_ci
3990d163575Sopenharmony_ci/* Set the mode data bit,for consumer's mode comparing. */
4000d163575Sopenharmony_ciSTATIC INT32 MqueueModeAnalysisSet(struct mqpersonal *privateMqPersonal)
4010d163575Sopenharmony_ci{
4020d163575Sopenharmony_ci    UINT32 mode;
4030d163575Sopenharmony_ci    UINT32 intSave;
4040d163575Sopenharmony_ci    User *user = NULL;
4050d163575Sopenharmony_ci    struct mqarray *mqueueCB = NULL;
4060d163575Sopenharmony_ci
4070d163575Sopenharmony_ci    if ((INT32)(UINTPTR)privateMqPersonal < 0) {
4080d163575Sopenharmony_ci        return -1;
4090d163575Sopenharmony_ci    }
4100d163575Sopenharmony_ci    /* Get mqueueCB of first time creating mqueue */
4110d163575Sopenharmony_ci    mqueueCB = privateMqPersonal->mq_posixdes;
4120d163575Sopenharmony_ci    if (mqueueCB == NULL) {
4130d163575Sopenharmony_ci        errno = ENFILE;
4140d163575Sopenharmony_ci        return -1;
4150d163575Sopenharmony_ci    }
4160d163575Sopenharmony_ci
4170d163575Sopenharmony_ci    mode = mqueueCB->mq_personal->mq_mode;
4180d163575Sopenharmony_ci    /* Set mqueue gid uid */
4190d163575Sopenharmony_ci    SCHEDULER_LOCK(intSave);
4200d163575Sopenharmony_ci    user = OsCurrUserGet();
4210d163575Sopenharmony_ci    mqueueCB->euid = user->effUserID;
4220d163575Sopenharmony_ci    mqueueCB->egid = user->effGid;
4230d163575Sopenharmony_ci    SCHEDULER_UNLOCK(intSave);
4240d163575Sopenharmony_ci
4250d163575Sopenharmony_ci    /* Set mode data bit */
4260d163575Sopenharmony_ci    if (mode & S_IRUSR) {
4270d163575Sopenharmony_ci        mqueueCB->mode_data.usr |= S_IRUSR;
4280d163575Sopenharmony_ci    }
4290d163575Sopenharmony_ci    if (mode & S_IWUSR) {
4300d163575Sopenharmony_ci        mqueueCB->mode_data.usr |= S_IWUSR;
4310d163575Sopenharmony_ci    }
4320d163575Sopenharmony_ci    if (mode & S_IRGRP) {
4330d163575Sopenharmony_ci        mqueueCB->mode_data.grp |= S_IRGRP;
4340d163575Sopenharmony_ci    }
4350d163575Sopenharmony_ci    if (mode & S_IWGRP) {
4360d163575Sopenharmony_ci        mqueueCB->mode_data.grp |= S_IWGRP;
4370d163575Sopenharmony_ci    }
4380d163575Sopenharmony_ci    if (mode & S_IROTH) {
4390d163575Sopenharmony_ci        mqueueCB->mode_data.oth |= S_IROTH;
4400d163575Sopenharmony_ci    }
4410d163575Sopenharmony_ci    if (mode & S_IWOTH) {
4420d163575Sopenharmony_ci        mqueueCB->mode_data.oth |= S_IWOTH;
4430d163575Sopenharmony_ci    }
4440d163575Sopenharmony_ci    return 0;
4450d163575Sopenharmony_ci}
4460d163575Sopenharmony_ci
4470d163575Sopenharmony_ciSTATIC INT32 GetPermissionOfVisitor(struct mqarray *mqueueCB)
4480d163575Sopenharmony_ci{
4490d163575Sopenharmony_ci    uid_t euid;
4500d163575Sopenharmony_ci    gid_t egid;
4510d163575Sopenharmony_ci    UINT32 intSave;
4520d163575Sopenharmony_ci    User *user = NULL;
4530d163575Sopenharmony_ci
4540d163575Sopenharmony_ci    if (mqueueCB == NULL) {
4550d163575Sopenharmony_ci        errno = ENOENT;
4560d163575Sopenharmony_ci        return -EPERM;
4570d163575Sopenharmony_ci    }
4580d163575Sopenharmony_ci
4590d163575Sopenharmony_ci    /* Get the visitor process euid and egid */
4600d163575Sopenharmony_ci    SCHEDULER_LOCK(intSave);
4610d163575Sopenharmony_ci    user = OsCurrUserGet();
4620d163575Sopenharmony_ci    euid = user->effUserID;
4630d163575Sopenharmony_ci    egid = user->effGid;
4640d163575Sopenharmony_ci    SCHEDULER_UNLOCK(intSave);
4650d163575Sopenharmony_ci
4660d163575Sopenharmony_ci    /* root */
4670d163575Sopenharmony_ci    if (euid == 0) {
4680d163575Sopenharmony_ci        return ENOERR;
4690d163575Sopenharmony_ci    }
4700d163575Sopenharmony_ci    if (euid == mqueueCB->euid) { /* usr */
4710d163575Sopenharmony_ci        if (!((mqueueCB->mode_data.usr & S_IRUSR) || (mqueueCB->mode_data.usr & S_IWUSR))) {
4720d163575Sopenharmony_ci            errno = EACCES;
4730d163575Sopenharmony_ci            goto ERR_OUT;
4740d163575Sopenharmony_ci        }
4750d163575Sopenharmony_ci    } else if (egid == mqueueCB->egid) { /* grp */
4760d163575Sopenharmony_ci        if (!((mqueueCB->mode_data.grp & S_IRGRP) || (mqueueCB->mode_data.grp & S_IWGRP))) {
4770d163575Sopenharmony_ci            errno = EACCES;
4780d163575Sopenharmony_ci            goto ERR_OUT;
4790d163575Sopenharmony_ci        }
4800d163575Sopenharmony_ci    } else { /* oth */
4810d163575Sopenharmony_ci        if (!((mqueueCB->mode_data.oth & S_IROTH) || (mqueueCB->mode_data.oth & S_IWOTH))) {
4820d163575Sopenharmony_ci            errno = EACCES;
4830d163575Sopenharmony_ci            goto ERR_OUT;
4840d163575Sopenharmony_ci        }
4850d163575Sopenharmony_ci    }
4860d163575Sopenharmony_ci    return ENOERR;
4870d163575Sopenharmony_ci
4880d163575Sopenharmony_ciERR_OUT:
4890d163575Sopenharmony_ci    return -EPERM;
4900d163575Sopenharmony_ci}
4910d163575Sopenharmony_ci
4920d163575Sopenharmony_ciSTATIC INT32 GetMqueueAttr(struct mq_attr *defaultAttr, struct mq_attr *attr)
4930d163575Sopenharmony_ci{
4940d163575Sopenharmony_ci    if (attr != NULL) {
4950d163575Sopenharmony_ci        if (LOS_ArchCopyFromUser(defaultAttr, attr, sizeof(struct mq_attr))) {
4960d163575Sopenharmony_ci            errno = EFAULT;
4970d163575Sopenharmony_ci            return -1;
4980d163575Sopenharmony_ci        }
4990d163575Sopenharmony_ci        if ((defaultAttr->mq_maxmsg < 0) || (defaultAttr->mq_maxmsg > (long int)USHRT_MAX) ||
5000d163575Sopenharmony_ci            (defaultAttr->mq_msgsize < 0) || (defaultAttr->mq_msgsize > (long int)(USHRT_MAX - sizeof(UINT32)))) {
5010d163575Sopenharmony_ci            errno = EINVAL;
5020d163575Sopenharmony_ci            return -1;
5030d163575Sopenharmony_ci        }
5040d163575Sopenharmony_ci    }
5050d163575Sopenharmony_ci    return 0;
5060d163575Sopenharmony_ci}
5070d163575Sopenharmony_ci
5080d163575Sopenharmony_cimqd_t mq_open(const char *mqName, int openFlag, ...)
5090d163575Sopenharmony_ci{
5100d163575Sopenharmony_ci    struct mqarray *mqueueCB = NULL;
5110d163575Sopenharmony_ci    struct mqpersonal *privateMqPersonal = (struct mqpersonal *)-1;
5120d163575Sopenharmony_ci    struct mq_attr *attr = NULL;
5130d163575Sopenharmony_ci    struct mq_attr defaultAttr = { 0, MQ_MAX_MSG_NUM, MQ_MAX_MSG_LEN, 0 };
5140d163575Sopenharmony_ci    va_list ap;
5150d163575Sopenharmony_ci    int sysFd;
5160d163575Sopenharmony_ci    mqd_t mqFd = -1;
5170d163575Sopenharmony_ci    unsigned int mode = 0;
5180d163575Sopenharmony_ci
5190d163575Sopenharmony_ci    if (MqNameCheck(mqName) == -1) {
5200d163575Sopenharmony_ci        return (mqd_t)-1;
5210d163575Sopenharmony_ci    }
5220d163575Sopenharmony_ci
5230d163575Sopenharmony_ci    (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
5240d163575Sopenharmony_ci    mqueueCB = GetMqueueCBByName(mqName);
5250d163575Sopenharmony_ci    if ((UINT32)openFlag & (UINT32)O_CREAT) {
5260d163575Sopenharmony_ci        if (mqueueCB != NULL) {
5270d163575Sopenharmony_ci            if (((UINT32)openFlag & (UINT32)O_EXCL)) {
5280d163575Sopenharmony_ci                errno = EEXIST;
5290d163575Sopenharmony_ci                goto OUT;
5300d163575Sopenharmony_ci            }
5310d163575Sopenharmony_ci            privateMqPersonal = DoMqueueOpen(mqueueCB, openFlag);
5320d163575Sopenharmony_ci        } else {
5330d163575Sopenharmony_ci            va_start(ap, openFlag);
5340d163575Sopenharmony_ci            mode = va_arg(ap, unsigned int);
5350d163575Sopenharmony_ci            attr = va_arg(ap, struct mq_attr *);
5360d163575Sopenharmony_ci            va_end(ap);
5370d163575Sopenharmony_ci
5380d163575Sopenharmony_ci            if (GetMqueueAttr(&defaultAttr, attr)) {
5390d163575Sopenharmony_ci                goto OUT;
5400d163575Sopenharmony_ci            }
5410d163575Sopenharmony_ci            privateMqPersonal = DoMqueueCreate(&defaultAttr, mqName, openFlag, mode);
5420d163575Sopenharmony_ci        }
5430d163575Sopenharmony_ci        /* Set mode data bit ,just for the first node */
5440d163575Sopenharmony_ci        if (MqueueModeAnalysisSet(privateMqPersonal)) {
5450d163575Sopenharmony_ci            if ((INT32)(UINTPTR)privateMqPersonal > 0) {
5460d163575Sopenharmony_ci                (VOID)DoMqueueClose(privateMqPersonal);
5470d163575Sopenharmony_ci            }
5480d163575Sopenharmony_ci            goto OUT;
5490d163575Sopenharmony_ci        }
5500d163575Sopenharmony_ci    } else {
5510d163575Sopenharmony_ci        if (GetPermissionOfVisitor(mqueueCB)) {
5520d163575Sopenharmony_ci            goto OUT;
5530d163575Sopenharmony_ci        }
5540d163575Sopenharmony_ci        privateMqPersonal = DoMqueueOpen(mqueueCB, openFlag);
5550d163575Sopenharmony_ci    }
5560d163575Sopenharmony_ci
5570d163575Sopenharmony_ci    if ((INT32)(UINTPTR)privateMqPersonal > 0) {
5580d163575Sopenharmony_ci        /* alloc sysFd */
5590d163575Sopenharmony_ci        sysFd = MqAllocSysFd(MAX_MQ_FD, privateMqPersonal);
5600d163575Sopenharmony_ci        if (sysFd == -1) {
5610d163575Sopenharmony_ci            /* there are no more mq sysFd to use, close the personal */
5620d163575Sopenharmony_ci            (VOID)DoMqueueClose(privateMqPersonal);
5630d163575Sopenharmony_ci            errno = ENFILE;
5640d163575Sopenharmony_ci        }
5650d163575Sopenharmony_ci        mqFd = (mqd_t)sysFd;
5660d163575Sopenharmony_ci    }
5670d163575Sopenharmony_ciOUT:
5680d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
5690d163575Sopenharmony_ci    return mqFd;
5700d163575Sopenharmony_ci}
5710d163575Sopenharmony_ci
5720d163575Sopenharmony_ciint mq_close(mqd_t personal)
5730d163575Sopenharmony_ci{
5740d163575Sopenharmony_ci    INT32 ret = -1;
5750d163575Sopenharmony_ci    struct mqpersonal *privateMqPersonal = NULL;
5760d163575Sopenharmony_ci
5770d163575Sopenharmony_ci    (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
5780d163575Sopenharmony_ci
5790d163575Sopenharmony_ci    /* Get the personal sysFd and reset personal fd -1 */
5800d163575Sopenharmony_ci    privateMqPersonal = MqGetPrivDataBuff(personal);
5810d163575Sopenharmony_ci    if (privateMqPersonal == NULL) {
5820d163575Sopenharmony_ci        goto OUT_UNLOCK;
5830d163575Sopenharmony_ci    }
5840d163575Sopenharmony_ci
5850d163575Sopenharmony_ci    if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {
5860d163575Sopenharmony_ci        errno = EBADF;
5870d163575Sopenharmony_ci        goto OUT_UNLOCK;
5880d163575Sopenharmony_ci    }
5890d163575Sopenharmony_ci
5900d163575Sopenharmony_ci    if (!MqTryClose(privateMqPersonal)) {
5910d163575Sopenharmony_ci        ret = 0;
5920d163575Sopenharmony_ci        goto OUT_UNLOCK;
5930d163575Sopenharmony_ci    }
5940d163575Sopenharmony_ci
5950d163575Sopenharmony_ci    ret = DoMqueueClose(privateMqPersonal);
5960d163575Sopenharmony_ci    if (ret < 0) {
5970d163575Sopenharmony_ci        goto OUT_UNLOCK;
5980d163575Sopenharmony_ci    }
5990d163575Sopenharmony_ci    MqFreeSysFd(personal);
6000d163575Sopenharmony_ci
6010d163575Sopenharmony_ciOUT_UNLOCK:
6020d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
6030d163575Sopenharmony_ci    return ret;
6040d163575Sopenharmony_ci}
6050d163575Sopenharmony_ci
6060d163575Sopenharmony_ciint OsMqGetAttr(mqd_t personal, struct mq_attr *mqAttr)
6070d163575Sopenharmony_ci{
6080d163575Sopenharmony_ci    struct mqarray *mqueueCB = NULL;
6090d163575Sopenharmony_ci    struct mqpersonal *privateMqPersonal = NULL;
6100d163575Sopenharmony_ci
6110d163575Sopenharmony_ci    (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
6120d163575Sopenharmony_ci    privateMqPersonal = MqGetPrivDataBuff(personal);
6130d163575Sopenharmony_ci    if (privateMqPersonal == NULL) {
6140d163575Sopenharmony_ci        (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
6150d163575Sopenharmony_ci        return -1;
6160d163575Sopenharmony_ci    }
6170d163575Sopenharmony_ci
6180d163575Sopenharmony_ci    if (mqAttr == NULL) {
6190d163575Sopenharmony_ci        errno = EINVAL;
6200d163575Sopenharmony_ci        (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
6210d163575Sopenharmony_ci        return -1;
6220d163575Sopenharmony_ci    }
6230d163575Sopenharmony_ci
6240d163575Sopenharmony_ci    if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {
6250d163575Sopenharmony_ci        errno = EBADF;
6260d163575Sopenharmony_ci        (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
6270d163575Sopenharmony_ci        return -1;
6280d163575Sopenharmony_ci    }
6290d163575Sopenharmony_ci
6300d163575Sopenharmony_ci    mqueueCB = privateMqPersonal->mq_posixdes;
6310d163575Sopenharmony_ci    mqAttr->mq_maxmsg = mqueueCB->mqcb->queueLen;
6320d163575Sopenharmony_ci    mqAttr->mq_msgsize = mqueueCB->mqcb->queueSize - sizeof(UINT32);
6330d163575Sopenharmony_ci    mqAttr->mq_curmsgs = mqueueCB->mqcb->readWriteableCnt[OS_QUEUE_READ];
6340d163575Sopenharmony_ci    mqAttr->mq_flags = privateMqPersonal->mq_flags;
6350d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
6360d163575Sopenharmony_ci    return 0;
6370d163575Sopenharmony_ci}
6380d163575Sopenharmony_ci
6390d163575Sopenharmony_ciint OsMqSetAttr(mqd_t personal, const struct mq_attr *mqSetAttr, struct mq_attr *mqOldAttr)
6400d163575Sopenharmony_ci{
6410d163575Sopenharmony_ci    struct mqpersonal *privateMqPersonal = NULL;
6420d163575Sopenharmony_ci
6430d163575Sopenharmony_ci    (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
6440d163575Sopenharmony_ci    privateMqPersonal = MqGetPrivDataBuff(personal);
6450d163575Sopenharmony_ci    if (privateMqPersonal == NULL) {
6460d163575Sopenharmony_ci        (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
6470d163575Sopenharmony_ci        return -1;
6480d163575Sopenharmony_ci    }
6490d163575Sopenharmony_ci
6500d163575Sopenharmony_ci    if (mqSetAttr == NULL) {
6510d163575Sopenharmony_ci        errno = EINVAL;
6520d163575Sopenharmony_ci        (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
6530d163575Sopenharmony_ci        return -1;
6540d163575Sopenharmony_ci    }
6550d163575Sopenharmony_ci
6560d163575Sopenharmony_ci    if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {
6570d163575Sopenharmony_ci        errno = EBADF;
6580d163575Sopenharmony_ci        (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
6590d163575Sopenharmony_ci        return -1;
6600d163575Sopenharmony_ci    }
6610d163575Sopenharmony_ci
6620d163575Sopenharmony_ci    if (mqOldAttr != NULL) {
6630d163575Sopenharmony_ci        (VOID)OsMqGetAttr(personal, mqOldAttr);
6640d163575Sopenharmony_ci    }
6650d163575Sopenharmony_ci
6660d163575Sopenharmony_ci    privateMqPersonal->mq_flags = (INT32)((UINT32)privateMqPersonal->mq_flags & (UINT32)(~FNONBLOCK)); /* clear */
6670d163575Sopenharmony_ci    if (((UINT32)mqSetAttr->mq_flags & (UINT32)FNONBLOCK) == (UINT32)FNONBLOCK) {
6680d163575Sopenharmony_ci        privateMqPersonal->mq_flags = (INT32)((UINT32)privateMqPersonal->mq_flags | (UINT32)FNONBLOCK);
6690d163575Sopenharmony_ci    }
6700d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
6710d163575Sopenharmony_ci    return 0;
6720d163575Sopenharmony_ci}
6730d163575Sopenharmony_ci
6740d163575Sopenharmony_ciint mq_getsetattr(mqd_t mqd, const struct mq_attr *new, struct mq_attr *old)
6750d163575Sopenharmony_ci{
6760d163575Sopenharmony_ci    if (new == NULL) {
6770d163575Sopenharmony_ci        return OsMqGetAttr(mqd, old);
6780d163575Sopenharmony_ci    }
6790d163575Sopenharmony_ci    return OsMqSetAttr(mqd, new, old);
6800d163575Sopenharmony_ci}
6810d163575Sopenharmony_ci
6820d163575Sopenharmony_ciint mq_unlink(const char *mqName)
6830d163575Sopenharmony_ci{
6840d163575Sopenharmony_ci    INT32 ret = 0;
6850d163575Sopenharmony_ci    struct mqarray *mqueueCB = NULL;
6860d163575Sopenharmony_ci
6870d163575Sopenharmony_ci    if (MqNameCheck(mqName) == -1) {
6880d163575Sopenharmony_ci        return -1;
6890d163575Sopenharmony_ci    }
6900d163575Sopenharmony_ci
6910d163575Sopenharmony_ci    (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
6920d163575Sopenharmony_ci    mqueueCB = GetMqueueCBByName(mqName);
6930d163575Sopenharmony_ci    if (mqueueCB == NULL) {
6940d163575Sopenharmony_ci        errno = ENOENT;
6950d163575Sopenharmony_ci        goto ERROUT_UNLOCK;
6960d163575Sopenharmony_ci    }
6970d163575Sopenharmony_ci
6980d163575Sopenharmony_ci    if (mqueueCB->mq_personal != NULL) {
6990d163575Sopenharmony_ci        mqueueCB->unlinkflag = TRUE;
7000d163575Sopenharmony_ci    } else if (mqueueCB->unlink_ref == 0) {
7010d163575Sopenharmony_ci        ret = DoMqueueDelete(mqueueCB);
7020d163575Sopenharmony_ci    }
7030d163575Sopenharmony_ci
7040d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
7050d163575Sopenharmony_ci    return ret;
7060d163575Sopenharmony_ci
7070d163575Sopenharmony_ciERROUT_UNLOCK:
7080d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
7090d163575Sopenharmony_ci    return -1;
7100d163575Sopenharmony_ci}
7110d163575Sopenharmony_ci
7120d163575Sopenharmony_ciSTATIC INT32 ConvertTimeout(long flags, const struct timespec *absTimeout, UINT64 *ticks)
7130d163575Sopenharmony_ci{
7140d163575Sopenharmony_ci    if ((UINT32)flags & (UINT32)FNONBLOCK) {
7150d163575Sopenharmony_ci        *ticks = LOS_NO_WAIT;
7160d163575Sopenharmony_ci        return 0;
7170d163575Sopenharmony_ci    }
7180d163575Sopenharmony_ci
7190d163575Sopenharmony_ci    if (absTimeout == NULL) {
7200d163575Sopenharmony_ci        *ticks = LOS_WAIT_FOREVER;
7210d163575Sopenharmony_ci        return 0;
7220d163575Sopenharmony_ci    }
7230d163575Sopenharmony_ci
7240d163575Sopenharmony_ci    if (!ValidTimeSpec(absTimeout)) {
7250d163575Sopenharmony_ci        errno = EINVAL;
7260d163575Sopenharmony_ci        return -1;
7270d163575Sopenharmony_ci    }
7280d163575Sopenharmony_ci
7290d163575Sopenharmony_ci    *ticks = OsTimeSpec2Tick(absTimeout);
7300d163575Sopenharmony_ci    return 0;
7310d163575Sopenharmony_ci}
7320d163575Sopenharmony_ci
7330d163575Sopenharmony_ciSTATIC INLINE BOOL MqParamCheck(mqd_t personal, const char *msg, size_t msgLen)
7340d163575Sopenharmony_ci{
7350d163575Sopenharmony_ci    if (personal < 0) {
7360d163575Sopenharmony_ci        return FALSE;
7370d163575Sopenharmony_ci    }
7380d163575Sopenharmony_ci
7390d163575Sopenharmony_ci    if ((msg == NULL) || (msgLen == 0)) {
7400d163575Sopenharmony_ci        errno = EINVAL;
7410d163575Sopenharmony_ci        return FALSE;
7420d163575Sopenharmony_ci    }
7430d163575Sopenharmony_ci    return TRUE;
7440d163575Sopenharmony_ci}
7450d163575Sopenharmony_ci
7460d163575Sopenharmony_ci/*
7470d163575Sopenharmony_ci * Send realtime a signal to process which registered itself
7480d163575Sopenharmony_ci * successfully by mq_notify.
7490d163575Sopenharmony_ci */
7500d163575Sopenharmony_cistatic void MqSendNotify(struct mqarray *mqueueCB)
7510d163575Sopenharmony_ci{
7520d163575Sopenharmony_ci    struct mqnotify *mqnotify = &mqueueCB->mq_notify;
7530d163575Sopenharmony_ci
7540d163575Sopenharmony_ci    if ((mqnotify->pid) && (mqueueCB->mqcb->readWriteableCnt[OS_QUEUE_READ] == 0)) {
7550d163575Sopenharmony_ci        siginfo_t info;
7560d163575Sopenharmony_ci
7570d163575Sopenharmony_ci        switch (mqnotify->notify.sigev_notify) {
7580d163575Sopenharmony_ci            case SIGEV_SIGNAL:
7590d163575Sopenharmony_ci                /* sends signal */
7600d163575Sopenharmony_ci                /* Create the siginfo structure */
7610d163575Sopenharmony_ci                info.si_signo = mqnotify->notify.sigev_signo;
7620d163575Sopenharmony_ci                info.si_code = SI_MESGQ;
7630d163575Sopenharmony_ci                info.si_value = mqnotify->notify.sigev_value;
7640d163575Sopenharmony_ci                OsDispatch(mqnotify->pid, &info, OS_USER_KILL_PERMISSION);
7650d163575Sopenharmony_ci                break;
7660d163575Sopenharmony_ci            case SIGEV_NONE:
7670d163575Sopenharmony_ci            default:
7680d163575Sopenharmony_ci                break;
7690d163575Sopenharmony_ci        }
7700d163575Sopenharmony_ci        /* after notification unregisters process */
7710d163575Sopenharmony_ci        mqnotify->pid = 0;
7720d163575Sopenharmony_ci    }
7730d163575Sopenharmony_ci}
7740d163575Sopenharmony_ci
7750d163575Sopenharmony_ci#define OS_MQ_GOTO_ERROUT_UNLOCK_IF(expr, errcode) \
7760d163575Sopenharmony_ci    if (expr) {                        \
7770d163575Sopenharmony_ci        errno = errcode;                 \
7780d163575Sopenharmony_ci        goto ERROUT_UNLOCK;                     \
7790d163575Sopenharmony_ci    }
7800d163575Sopenharmony_ci#define OS_MQ_GOTO_ERROUT_IF(expr, errcode) \
7810d163575Sopenharmony_ci    if (expr) {                        \
7820d163575Sopenharmony_ci        errno = errcode;                 \
7830d163575Sopenharmony_ci        goto ERROUT;                     \
7840d163575Sopenharmony_ci    }
7850d163575Sopenharmony_ciint mq_timedsend(mqd_t personal, const char *msg, size_t msgLen, unsigned int msgPrio,
7860d163575Sopenharmony_ci                 const struct timespec *absTimeout)
7870d163575Sopenharmony_ci{
7880d163575Sopenharmony_ci    UINT32 mqueueID, err;
7890d163575Sopenharmony_ci    UINT64 absTicks;
7900d163575Sopenharmony_ci    struct mqarray *mqueueCB = NULL;
7910d163575Sopenharmony_ci    struct mqpersonal *privateMqPersonal = NULL;
7920d163575Sopenharmony_ci
7930d163575Sopenharmony_ci    OS_MQ_GOTO_ERROUT_IF(!MqParamCheck(personal, msg, msgLen), errno);
7940d163575Sopenharmony_ci    OS_MQ_GOTO_ERROUT_IF(msgPrio > (MQ_PRIO_MAX - 1), EINVAL);
7950d163575Sopenharmony_ci
7960d163575Sopenharmony_ci    (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
7970d163575Sopenharmony_ci    privateMqPersonal = MqGetPrivDataBuff(personal);
7980d163575Sopenharmony_ci
7990d163575Sopenharmony_ci    OS_MQ_GOTO_ERROUT_UNLOCK_IF(privateMqPersonal == NULL || privateMqPersonal->mq_status != MQ_USE_MAGIC, EBADF);
8000d163575Sopenharmony_ci
8010d163575Sopenharmony_ci    mqueueCB = privateMqPersonal->mq_posixdes;
8020d163575Sopenharmony_ci    OS_MQ_GOTO_ERROUT_UNLOCK_IF(msgLen > (size_t)(mqueueCB->mqcb->queueSize - sizeof(UINT32)), EMSGSIZE);
8030d163575Sopenharmony_ci
8040d163575Sopenharmony_ci    OS_MQ_GOTO_ERROUT_UNLOCK_IF((((UINT32)privateMqPersonal->mq_flags & (UINT32)O_WRONLY) != (UINT32)O_WRONLY) &&
8050d163575Sopenharmony_ci                                (((UINT32)privateMqPersonal->mq_flags & (UINT32)O_RDWR) != (UINT32)O_RDWR),
8060d163575Sopenharmony_ci                                EBADF);
8070d163575Sopenharmony_ci
8080d163575Sopenharmony_ci    OS_MQ_GOTO_ERROUT_UNLOCK_IF(ConvertTimeout(privateMqPersonal->mq_flags, absTimeout, &absTicks) == -1, errno);
8090d163575Sopenharmony_ci    mqueueID = mqueueCB->mq_id;
8100d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
8110d163575Sopenharmony_ci
8120d163575Sopenharmony_ci    if (LOS_ListEmpty(&mqueueCB->mqcb->readWriteList[OS_QUEUE_READ])) {
8130d163575Sopenharmony_ci        MqSendNotify(mqueueCB);
8140d163575Sopenharmony_ci    }
8150d163575Sopenharmony_ci
8160d163575Sopenharmony_ci    err = LOS_QueueWriteCopy(mqueueID, (VOID *)msg, (UINT32)msgLen, (UINT32)absTicks);
8170d163575Sopenharmony_ci    if (map_errno(err) != ENOERR) {
8180d163575Sopenharmony_ci        goto ERROUT;
8190d163575Sopenharmony_ci    }
8200d163575Sopenharmony_ci    return 0;
8210d163575Sopenharmony_ciERROUT_UNLOCK:
8220d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
8230d163575Sopenharmony_ciERROUT:
8240d163575Sopenharmony_ci    return -1;
8250d163575Sopenharmony_ci}
8260d163575Sopenharmony_ci
8270d163575Sopenharmony_cissize_t mq_timedreceive(mqd_t personal, char *msg, size_t msgLen, unsigned int *msgPrio,
8280d163575Sopenharmony_ci                        const struct timespec *absTimeout)
8290d163575Sopenharmony_ci{
8300d163575Sopenharmony_ci    UINT32 mqueueID, err;
8310d163575Sopenharmony_ci    UINT32 receiveLen;
8320d163575Sopenharmony_ci    UINT64 absTicks;
8330d163575Sopenharmony_ci    struct mqarray *mqueueCB = NULL;
8340d163575Sopenharmony_ci    struct mqpersonal *privateMqPersonal = NULL;
8350d163575Sopenharmony_ci
8360d163575Sopenharmony_ci    if (!MqParamCheck(personal, msg, msgLen)) {
8370d163575Sopenharmony_ci        goto ERROUT;
8380d163575Sopenharmony_ci    }
8390d163575Sopenharmony_ci
8400d163575Sopenharmony_ci    if (msgPrio != NULL) {
8410d163575Sopenharmony_ci        *msgPrio = 0;
8420d163575Sopenharmony_ci    }
8430d163575Sopenharmony_ci
8440d163575Sopenharmony_ci    (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
8450d163575Sopenharmony_ci    privateMqPersonal = MqGetPrivDataBuff(personal);
8460d163575Sopenharmony_ci    if (privateMqPersonal == NULL || privateMqPersonal->mq_status != MQ_USE_MAGIC) {
8470d163575Sopenharmony_ci        errno = EBADF;
8480d163575Sopenharmony_ci        goto ERROUT_UNLOCK;
8490d163575Sopenharmony_ci    }
8500d163575Sopenharmony_ci
8510d163575Sopenharmony_ci    mqueueCB = privateMqPersonal->mq_posixdes;
8520d163575Sopenharmony_ci    if (msgLen < (size_t)(mqueueCB->mqcb->queueSize - sizeof(UINT32))) {
8530d163575Sopenharmony_ci        errno = EMSGSIZE;
8540d163575Sopenharmony_ci        goto ERROUT_UNLOCK;
8550d163575Sopenharmony_ci    }
8560d163575Sopenharmony_ci
8570d163575Sopenharmony_ci    if (((UINT32)privateMqPersonal->mq_flags & (UINT32)O_WRONLY) == (UINT32)O_WRONLY) {
8580d163575Sopenharmony_ci        errno = EBADF;
8590d163575Sopenharmony_ci        goto ERROUT_UNLOCK;
8600d163575Sopenharmony_ci    }
8610d163575Sopenharmony_ci
8620d163575Sopenharmony_ci    if (ConvertTimeout(privateMqPersonal->mq_flags, absTimeout, &absTicks) == -1) {
8630d163575Sopenharmony_ci        goto ERROUT_UNLOCK;
8640d163575Sopenharmony_ci    }
8650d163575Sopenharmony_ci
8660d163575Sopenharmony_ci    receiveLen = msgLen;
8670d163575Sopenharmony_ci    mqueueID = mqueueCB->mq_id;
8680d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
8690d163575Sopenharmony_ci
8700d163575Sopenharmony_ci    err = LOS_QueueReadCopy(mqueueID, (VOID *)msg, &receiveLen, (UINT32)absTicks);
8710d163575Sopenharmony_ci    if (map_errno(err) == ENOERR) {
8720d163575Sopenharmony_ci        return (ssize_t)receiveLen;
8730d163575Sopenharmony_ci    } else {
8740d163575Sopenharmony_ci        goto ERROUT;
8750d163575Sopenharmony_ci    }
8760d163575Sopenharmony_ci
8770d163575Sopenharmony_ciERROUT_UNLOCK:
8780d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
8790d163575Sopenharmony_ciERROUT:
8800d163575Sopenharmony_ci    return -1;
8810d163575Sopenharmony_ci}
8820d163575Sopenharmony_ci
8830d163575Sopenharmony_ci/* not support the prio */
8840d163575Sopenharmony_ciint mq_send(mqd_t personal, const char *msg_ptr, size_t msg_len, unsigned int msg_prio)
8850d163575Sopenharmony_ci{
8860d163575Sopenharmony_ci    return mq_timedsend(personal, msg_ptr, msg_len, msg_prio, NULL);
8870d163575Sopenharmony_ci}
8880d163575Sopenharmony_ci
8890d163575Sopenharmony_cissize_t mq_receive(mqd_t personal, char *msg_ptr, size_t msg_len, unsigned int *msg_prio)
8900d163575Sopenharmony_ci{
8910d163575Sopenharmony_ci    return mq_timedreceive(personal, msg_ptr, msg_len, msg_prio, NULL);
8920d163575Sopenharmony_ci}
8930d163575Sopenharmony_ci
8940d163575Sopenharmony_ciSTATIC INLINE BOOL MqNotifyParamCheck(mqd_t personal, const struct sigevent *sigev)
8950d163575Sopenharmony_ci{
8960d163575Sopenharmony_ci    if (personal < 0) {
8970d163575Sopenharmony_ci        errno = EBADF;
8980d163575Sopenharmony_ci        goto ERROUT;
8990d163575Sopenharmony_ci    }
9000d163575Sopenharmony_ci
9010d163575Sopenharmony_ci    if (sigev != NULL) {
9020d163575Sopenharmony_ci        if (sigev->sigev_notify != SIGEV_NONE && sigev->sigev_notify != SIGEV_SIGNAL) {
9030d163575Sopenharmony_ci            errno = EINVAL;
9040d163575Sopenharmony_ci            goto ERROUT;
9050d163575Sopenharmony_ci        }
9060d163575Sopenharmony_ci        if (sigev->sigev_notify == SIGEV_SIGNAL && !GOOD_SIGNO(sigev->sigev_signo)) {
9070d163575Sopenharmony_ci            errno = EINVAL;
9080d163575Sopenharmony_ci            goto ERROUT;
9090d163575Sopenharmony_ci        }
9100d163575Sopenharmony_ci    }
9110d163575Sopenharmony_ci
9120d163575Sopenharmony_ci    return TRUE;
9130d163575Sopenharmony_ciERROUT:
9140d163575Sopenharmony_ci    return FALSE;
9150d163575Sopenharmony_ci}
9160d163575Sopenharmony_ci
9170d163575Sopenharmony_ciint OsMqNotify(mqd_t personal, const struct sigevent *sigev)
9180d163575Sopenharmony_ci{
9190d163575Sopenharmony_ci    struct mqarray *mqueueCB = NULL;
9200d163575Sopenharmony_ci    struct mqnotify *mqnotify = NULL;
9210d163575Sopenharmony_ci    struct mqpersonal *privateMqPersonal = NULL;
9220d163575Sopenharmony_ci
9230d163575Sopenharmony_ci    if (!MqNotifyParamCheck(personal, sigev)) {
9240d163575Sopenharmony_ci        goto ERROUT;
9250d163575Sopenharmony_ci    }
9260d163575Sopenharmony_ci
9270d163575Sopenharmony_ci    (VOID)pthread_mutex_lock(&IPC_QUEUE_MUTEX);
9280d163575Sopenharmony_ci    privateMqPersonal = MqGetPrivDataBuff(personal);
9290d163575Sopenharmony_ci    if (privateMqPersonal == NULL) {
9300d163575Sopenharmony_ci        goto OUT_UNLOCK;
9310d163575Sopenharmony_ci    }
9320d163575Sopenharmony_ci
9330d163575Sopenharmony_ci    if (privateMqPersonal->mq_status != MQ_USE_MAGIC) {
9340d163575Sopenharmony_ci        errno = EBADF;
9350d163575Sopenharmony_ci        goto OUT_UNLOCK;
9360d163575Sopenharmony_ci    }
9370d163575Sopenharmony_ci
9380d163575Sopenharmony_ci    mqueueCB = privateMqPersonal->mq_posixdes;
9390d163575Sopenharmony_ci    mqnotify = &mqueueCB->mq_notify;
9400d163575Sopenharmony_ci
9410d163575Sopenharmony_ci    if (sigev == NULL) {
9420d163575Sopenharmony_ci        if (mqnotify->pid == LOS_GetCurrProcessID()) {
9430d163575Sopenharmony_ci            mqnotify->pid = 0;
9440d163575Sopenharmony_ci        }
9450d163575Sopenharmony_ci    } else if (mqnotify->pid != 0) {
9460d163575Sopenharmony_ci        errno = EBUSY;
9470d163575Sopenharmony_ci        goto OUT_UNLOCK;
9480d163575Sopenharmony_ci    } else {
9490d163575Sopenharmony_ci        switch (sigev->sigev_notify) {
9500d163575Sopenharmony_ci            case SIGEV_NONE:
9510d163575Sopenharmony_ci                mqnotify->notify.sigev_notify = SIGEV_NONE;
9520d163575Sopenharmony_ci                break;
9530d163575Sopenharmony_ci            case SIGEV_SIGNAL:
9540d163575Sopenharmony_ci                mqnotify->notify.sigev_signo = sigev->sigev_signo;
9550d163575Sopenharmony_ci                mqnotify->notify.sigev_value = sigev->sigev_value;
9560d163575Sopenharmony_ci                mqnotify->notify.sigev_notify = SIGEV_SIGNAL;
9570d163575Sopenharmony_ci                break;
9580d163575Sopenharmony_ci            default:
9590d163575Sopenharmony_ci                break;
9600d163575Sopenharmony_ci        }
9610d163575Sopenharmony_ci
9620d163575Sopenharmony_ci        mqnotify->pid = LOS_GetCurrProcessID();
9630d163575Sopenharmony_ci    }
9640d163575Sopenharmony_ci
9650d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
9660d163575Sopenharmony_ci    return 0;
9670d163575Sopenharmony_ciOUT_UNLOCK:
9680d163575Sopenharmony_ci    (VOID)pthread_mutex_unlock(&IPC_QUEUE_MUTEX);
9690d163575Sopenharmony_ciERROUT:
9700d163575Sopenharmony_ci    return -1;
9710d163575Sopenharmony_ci}
9720d163575Sopenharmony_ci
9730d163575Sopenharmony_ciVOID OsMqueueCBDestroy(struct mqarray *queueTable)
9740d163575Sopenharmony_ci{
9750d163575Sopenharmony_ci    if (queueTable == NULL) {
9760d163575Sopenharmony_ci        return;
9770d163575Sopenharmony_ci    }
9780d163575Sopenharmony_ci
9790d163575Sopenharmony_ci    for (UINT32 index = 0; index < LOSCFG_BASE_IPC_QUEUE_LIMIT; index++) {
9800d163575Sopenharmony_ci        struct mqarray *mqueueCB = &(queueTable[index]);
9810d163575Sopenharmony_ci        if (mqueueCB->mq_name == NULL) {
9820d163575Sopenharmony_ci            continue;
9830d163575Sopenharmony_ci        }
9840d163575Sopenharmony_ci        (VOID)DoMqueueClose(mqueueCB->mq_personal);
9850d163575Sopenharmony_ci    }
9860d163575Sopenharmony_ci}
9870d163575Sopenharmony_ci#endif
988