更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
ipc_syscall.c
浏览该文件的文档.
1/*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include "syscall_pub.h"
33#include "mqueue.h"
34#include <errno.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include "time_posix.h"
38#include "user_copy.h"
39#include "los_signal.h"
40#include "los_process_pri.h"
42#include "fs/file.h"
43
44#define MQUEUE_FD_U2K(id) \
45 do { \
46 int sysFd = GetAssociatedSystemFd((INTPTR)(id)); \
47 (id) = (mqd_t)sysFd; \
48 } while (0)
49#define MQUEUE_FD_K2U(id) \
50 do { \
51 int procFd = AllocAndAssocProcessFd((INTPTR)(id), MIN_START_FD); \
52 if (procFd == -1) { \
53 mq_close(id); \
54 set_errno(EMFILE); \
55 (id) = (mqd_t)(-EMFILE); \
56 } else { \
57 (id) = (mqd_t)procFd; \
58 } \
59 } while (0)
60
61/**
62 * @brief 打开一个消息队列,由posix接口封装
63 * @verbatim
64 IPC(Inter-Process Communication,进程间通信)
65 每个进程各自有不同的用户地址空间,进程之间地址保护,相互隔离,任何一个进程的信息在另一个进程中都看不到,
66 所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区,
67 进程B再从内核缓冲区把数据读走,
68
69 IPC实现方式之消息队列:
70 消息队列特点总结:
71 (1)消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识.
72 (2)消息队列允许一个或多个进程向它写入与读取消息.
73 (3)管道和消息队列的通信数据都是先进先出的原则。
74 (4)消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比FIFO更有优势。
75 (5)消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
76 (6)目前主要有两种类型的消息队列:POSIX消息队列以及System V消息队列,System V消息队列是随内核持续的,
77 只有在内核重起或者人工删除时,该消息队列才会被删除。
78
79 鸿蒙liteos 支持POSIX消息队列并加入了一种自研的消息队列 liteipc,此处重点讲 posix消息队列
80 * @endverbatim
81 * @param mqName
82 * @param openFlag
83 * @param mode
84 * @param attr
85 * @return mqd_t
86 */
87mqd_t SysMqOpen(const char *mqName, int openFlag, mode_t mode, struct mq_attr *attr)
88{
89 mqd_t ret;
90 int retValue;
91 char kMqName[PATH_MAX + 1] = { 0 };
92
93 retValue = LOS_StrncpyFromUser(kMqName, mqName, PATH_MAX);
94 if (retValue < 0) {
95 return retValue;
96 }
97 ret = mq_open(kMqName, openFlag, mode, attr);//posix ,一个消息队列可以有多个进程向它读写消息
98 if (ret == -1) {
99 return (mqd_t)-get_errno();
100 }
101 /* SysFd to procFd */
102 MQUEUE_FD_K2U(ret);
103 return ret;
104}
105///关闭一个消息队列
106int SysMqClose(mqd_t personal)
107{
108 int ret;
109 int ufd = (INTPTR)personal;
110
111 MQUEUE_FD_U2K(personal);
112 ret = mq_close(personal);
113 if (ret < 0) {
114 return -get_errno();
115 }
116 FreeProcessFd(ufd);
117 return ret;
118}
119int SysMqNotify(mqd_t personal, const struct sigevent *sigev)
120{
121 int ret;
122
123 MQUEUE_FD_U2K(personal);
124 ret = OsMqNotify(personal, sigev);
125 if (ret < 0) {
126 return -get_errno();
127 }
128 return ret;
129}
130
131/**
132 * @brief 封装posix的标准接口,获取和设置消息队列的属性
133 * @param mqd
134 * @param new 判断是否是获取还是设置功能,new==null 获取 否则为设置
135 * @param old
136 * @return int
137 */
138int SysMqGetSetAttr(mqd_t mqd, const struct mq_attr *new, struct mq_attr *old)
139{
140 int ret;
141 struct mq_attr knew, kold;
142
143 if (new != NULL) {
144 ret = LOS_ArchCopyFromUser(&knew, new, sizeof(struct mq_attr));
145 if (ret != 0) {
146 return -EFAULT;
147 }
148 }
149 MQUEUE_FD_U2K(mqd);
150 ret = mq_getsetattr(mqd, new ? &knew : NULL, old ? &kold : NULL);
151 if (ret < 0) {
152 return -get_errno();
153 }
154 if (old != NULL) {
155 ret = LOS_ArchCopyToUser(old, &kold, sizeof(struct mq_attr));
156 if (ret != 0) {
157 return -EFAULT;
158 }
159 }
160 return ret;
161}
162
163/**
164 * @brief
165 * @verbatim
166 从内核中删除名为mqName的消息队列
167 如果该函数被调用了,但是仍然有进程已经打开了这个消息队列,那么这个消息队列
168 的销毁会被推迟到所有的引用都被关闭时执行.并且函数 mq_unlink() 不需要阻塞
169 到所有的引用都被关闭为止,它会立即返回.函数 mq_unlink()调用成功后, 如果在
170 随后调用 mq_open() 时重用这个消息队列名字,效果就像这个名字的消息队列不存在,
171 如果没有设置O_CREAT标志,函数mq_open() 会返回失败,否则会创建一个新的消息队列.
172 * @endverbatim
173 * @param mqName
174 * @return int
175 */
176int SysMqUnlink(const char *mqName)
177{
178 int ret;
179 int retValue;
180 char kMqName[PATH_MAX + 1] = { 0 };
181
182 retValue = LOS_StrncpyFromUser(kMqName, mqName, PATH_MAX);
183 if (retValue < 0) {
184 return retValue;
185 }
186
187 ret = mq_unlink(kMqName);
188 if (ret < 0) {
189 return -get_errno();
190 }
191 return ret;
192}
193
194/// 定时时间发送消息,任务将被阻塞,等待被唤醒写入消息
195int SysMqTimedSend(mqd_t personal, const char *msg, size_t msgLen, unsigned int msgPrio,
196 const struct timespec *absTimeout)
197{
198 int ret;
199 struct timespec timeout;
200 char *msgIntr = NULL;
201
202 if (absTimeout != NULL) {
203 ret = LOS_ArchCopyFromUser(&timeout, absTimeout, sizeof(struct timespec));
204 if (ret != 0) {
205 return -EFAULT;
206 }
207 }
208 if (msgLen == 0) {
209 return -EINVAL;
210 }
211 msgIntr = (char *)malloc(msgLen);
212 if (msgIntr == NULL) {
213 return -ENOMEM;
214 }
215 ret = LOS_ArchCopyFromUser(msgIntr, msg, msgLen);
216 if (ret != 0) {
217 free(msgIntr);
218 return -EFAULT;
219 }
220 MQUEUE_FD_U2K(personal);
221 ret = mq_timedsend(personal, msgIntr, msgLen, msgPrio, absTimeout ? &timeout : NULL);//posix 接口的实现
222 free(msgIntr);
223 if (ret < 0) {
224 return -get_errno();
225 }
226 return ret;
227}
228
229///定时接收消息,任务将被阻塞,等待被唤醒读取
230ssize_t SysMqTimedReceive(mqd_t personal, char *msg, size_t msgLen, unsigned int *msgPrio,
231 const struct timespec *absTimeout)
232{
233 int ret, receiveLen;
234 struct timespec timeout;
235 char *msgIntr = NULL;
236 unsigned int kMsgPrio;
237
238 if (absTimeout != NULL) {
239 ret = LOS_ArchCopyFromUser(&timeout, absTimeout, sizeof(struct timespec));
240 if (ret != 0) {
241 return -EFAULT;
242 }
243 }
244 if (msgLen == 0) {
245 return -EINVAL;
246 }
247 msgIntr = (char *)malloc(msgLen);
248 if (msgIntr == NULL) {
249 return -ENOMEM;
250 }
251 MQUEUE_FD_U2K(personal);
252 receiveLen = mq_timedreceive(personal, msgIntr, msgLen, &kMsgPrio, absTimeout ? &timeout : NULL);//posix 接口的实现
253 if (receiveLen < 0) {
254 free(msgIntr);
255 return -get_errno();
256 }
257
258 if (msgPrio != NULL) {
259 ret = LOS_ArchCopyToUser(msgPrio, &kMsgPrio, sizeof(unsigned int));
260 if (ret != 0) {
261 free(msgIntr);
262 return -EFAULT;
263 }
264 }
265
266 ret = LOS_ArchCopyToUser(msg, msgIntr, receiveLen);
267 free(msgIntr);
268 if (ret != 0) {
269 return -EFAULT;
270 }
271 return receiveLen;
272}
273///注册信号,鸿蒙内核只捕捉了SIGSYS 信号
274int SysSigAction(int sig, const sigaction_t *restrict sa, sigaction_t *restrict old, size_t sigsetsize)
275{
276 return OsSigAction(sig, sa, old);
277}
278
279/**
280 * @brief 系统调用之进程信号屏蔽,
281 什么意思?简单说就是 一个信号来了进程要不要处理,屏蔽就是不处理,注意不能屏蔽SIGKILL和SIGSTOP信号,必须要处理.
282 * @param how SIG_BLOCK 加入信号到进程屏蔽。set包含了希望阻塞的附加信号
283 \n SIG_UNBLOCK 从进程屏蔽里将信号删除。set包含了希望解除阻塞的信号
284 \n SIG_SETMASK 将set的值设定为新的进程屏蔽
285 * @param setl
286 * @param oldl
287 * @param sigsetsize
288 * @return int
289 */
290int SysSigprocMask(int how, const sigset_t_l *restrict setl, sigset_t_l *restrict oldl, size_t sigsetsize)
291{
292 CHECK_ASPACE(setl, sizeof(sigset_t_l));
293 CHECK_ASPACE(oldl, sizeof(sigset_t_l));
294 CPY_FROM_USER(setl);
295 CPY_FROM_USER(oldl);
296 /* Let OsSigprocMask do all of the work */
297 int ret = OsSigprocMask(how, setl, oldl);
298 CPY_TO_USER(oldl);
299 return ret;
300}
301///系统调用之向进程发送信号
302int SysKill(pid_t pid, int sig)
303{
304 return OsKillLock(pid, sig);
305}
306///系统调用之之向进程发送信号
307int SysPthreadKill(pid_t pid, int sig)
308{
309 return OsPthreadKill(pid, sig);
310}
311
312int SysSigTimedWait(const sigset_t_l *setl, siginfo_t *info, const struct timespec *timeout, size_t sigsetsize)
313{
314 sigset_t set;
315 unsigned int tick;
316 int retVal, ret;
317 siginfo_t infoIntr;
318 struct timespec timeoutIntr;
319
320 retVal = LOS_ArchCopyFromUser(&set, &(setl->sig[0]), sizeof(sigset_t));
321 if (retVal != 0) {
322 return -EFAULT;
323 }
324
325 if (timeout == NULL) {
326 tick = LOS_WAIT_FOREVER;
327 } else {
328 retVal = LOS_ArchCopyFromUser(&timeoutIntr, timeout, sizeof(struct timespec));
329 if (retVal != 0) {
330 return -EFAULT;
331 }
332 if (!ValidTimeSpec(&timeoutIntr)) {
333 return -EINVAL;
334 }
335 tick = OsTimeSpec2Tick(&timeoutIntr);
336 }
337 ret = OsSigTimedWait(&set, &infoIntr, tick);
338 if (ret < 0) {
339 return ret;
340 }
341 if (info != NULL) {
342 retVal = LOS_ArchCopyToUser(info, &infoIntr, sizeof(siginfo_t));
343 if (retVal != 0) {
344 return -EFAULT;
345 }
346 }
347 return (ret == 0 ? infoIntr.si_signo : ret);
348}
349///系统调用之暂停任务
350int SysPause(void)
351{
352 return OsPause();
353}
354///获取阻塞当前任务的信号集
356{
357 sigset_t set;
358 int ret;
359
360 ret = LOS_ArchCopyFromUser(&set, &(setl->sig[0]), sizeof(sigset_t));
361 if (ret != 0) {
362 return -EFAULT;
363 }
364 ret = OsSigPending(&set);
365 if (ret != LOS_OK) {
366 return ret;
367 }
368 ret = LOS_ArchCopyToUser(&(setl->sig[0]), &set, sizeof(sigset_t));
369 if (ret != LOS_OK) {
370 return -EFAULT;
371 }
372 return ret;
373}
374
376{
377 sigset_t set;
378 int retVal;
379
380 retVal = LOS_ArchCopyFromUser(&set, &(setl->sig[0]), sizeof(sigset_t));
381 if (retVal != 0) {
382 return -EFAULT;
383 }
384
385 return OsSigSuspend(&set);
386}
387
388#ifdef LOSCFG_KERNEL_PIPE
389int SysMkFifo(const char *pathName, mode_t mode)
390{
391 int retValue;
392 char kPathName[PATH_MAX + 1] = { 0 };
393
394 retValue = LOS_StrncpyFromUser(kPathName, pathName, PATH_MAX);
395 if (retValue < 0) {
396 return retValue;
397 }
398 return mkfifo(kPathName, mode);
399}
400#endif
int mq_getsetattr(mqd_t personal, const struct mq_attr *mqSetAttr, struct mq_attr *MqOldAttr)
Definition: mqueue.c:648
mqd_t mq_open(const char *mqName, int openFlag,...)
Definition: mqueue.c:486
int mq_close(mqd_t personal)
Definition: mqueue.c:550
int mq_timedsend(mqd_t personal, const char *msg, size_t msgLen, unsigned int msgPrio, const struct timespec *absTimeout)
Definition: mqueue.c:759
int mq_unlink(const char *mqName)
Definition: mqueue.c:656
UINTPTR mqd_t
Definition: mqueue.h:127
ssize_t mq_timedreceive(mqd_t personal, char *msg, size_t msgLen, unsigned int *msgPrio, const struct timespec *absTimeout)
Definition: mqueue.c:801
int SysSigTimedWait(const sigset_t_l *setl, siginfo_t *info, const struct timespec *timeout, size_t sigsetsize)
Definition: ipc_syscall.c:312
int SysPthreadKill(pid_t pid, int sig)
系统调用之之向进程发送信号
Definition: ipc_syscall.c:307
int SysPause(void)
系统调用之暂停任务
Definition: ipc_syscall.c:350
int SysMkFifo(const char *pathName, mode_t mode)
Definition: ipc_syscall.c:389
mqd_t SysMqOpen(const char *mqName, int openFlag, mode_t mode, struct mq_attr *attr)
打开一个消息队列,由posix接口封装
Definition: ipc_syscall.c:87
int SysSigSuspend(sigset_t_l *setl)
Definition: ipc_syscall.c:375
int SysKill(pid_t pid, int sig)
系统调用之向进程发送信号
Definition: ipc_syscall.c:302
int SysMqUnlink(const char *mqName)
Definition: ipc_syscall.c:176
int SysSigAction(int sig, const sigaction_t *restrict sa, sigaction_t *restrict old, size_t sigsetsize)
注册信号,鸿蒙内核只捕捉了SIGSYS 信号
Definition: ipc_syscall.c:274
int SysSigPending(sigset_t_l *setl)
获取阻塞当前任务的信号集
Definition: ipc_syscall.c:355
int SysMqNotify(mqd_t personal, const struct sigevent *sigev)
Definition: ipc_syscall.c:119
int SysMqTimedSend(mqd_t personal, const char *msg, size_t msgLen, unsigned int msgPrio, const struct timespec *absTimeout)
定时时间发送消息,任务将被阻塞,等待被唤醒写入消息
Definition: ipc_syscall.c:195
int SysMqGetSetAttr(mqd_t mqd, const struct mq_attr *new, struct mq_attr *old)
封装posix的标准接口,获取和设置消息队列的属性
Definition: ipc_syscall.c:138
int SysMqClose(mqd_t personal)
关闭一个消息队列
Definition: ipc_syscall.c:106
int SysSigprocMask(int how, const sigset_t_l *restrict setl, sigset_t_l *restrict oldl, size_t sigsetsize)
系统调用之进程信号屏蔽, 什么意思?简单说就是 一个信号来了进程要不要处理,屏蔽就是不处理,注意不能屏蔽SIGKILL和SIGSTOP信号,必须要处理.
Definition: ipc_syscall.c:290
ssize_t SysMqTimedReceive(mqd_t personal, char *msg, size_t msgLen, unsigned int *msgPrio, const struct timespec *absTimeout)
定时接收消息,任务将被阻塞,等待被唤醒读取
Definition: ipc_syscall.c:230
int OsPause(void)
通过信号挂起当前任务
Definition: los_signal.c:617
int OsSigAction(int sig, const sigaction_t *act, sigaction_t *oact)
Definition: los_signal.c:677
int OsSigprocMask(int how, const sigset_t_l *set, sigset_t_l *oldset)
Definition: los_signal.c:233
int OsPthreadKill(UINT32 tid, int signo)
发送信号
Definition: los_signal.c:509
int OsKillLock(pid_t pid, int sig)
给发送信号过程加锁
Definition: los_signal.c:480
int OsSigPending(sigset_t *set)
获取阻塞当前任务的信号集
Definition: los_signal.c:541
struct sigaction sigaction_t
Definition: los_signal.h:186
int OsSigSuspend(const sigset_t *set)
用参数set代替进程的原有掩码,并暂停进程执行,直到收到信号再恢复原有掩码并继续执行进程。
Definition: los_signal.c:627
int OsSigTimedWait(sigset_t *set, siginfo_t *info, unsigned int timeout)
让当前任务等待的信号
Definition: los_signal.c:604
INT64 ssize_t
Definition: los_typedef.h:79
signed long INTPTR
Definition: los_typedef.h:69
void * malloc(size_t size)
动态分配内存块大小
Definition: malloc.c:81
void free(void *ptr)
释放ptr所指向的内存空间
Definition: malloc.c:66
int OsMqNotify(mqd_t personal, const struct sigevent *sigev)
Definition: mqueue.c:891
INT32 LOS_StrncpyFromUser(CHAR *dst, const CHAR *src, INT32 count)
unsigned long sig[MAX_SIG_ARRAY_IN_MUSL/sizeof(unsigned long)]
Definition: los_signal.h:166
ARG_NUM_3 ARG_NUM_1 ARG_NUM_2 ARG_NUM_2 ARG_NUM_3 ARG_NUM_1 ARG_NUM_4 ARG_NUM_2 ARG_NUM_2 ARG_NUM_5 ARG_NUM_2 ARG_NUM_0 ARG_NUM_2 ARG_NUM_1 ARG_NUM_2 ARG_NUM_3 ARG_NUM_7 ARG_NUM_2 ARG_NUM_3 ARG_NUM_2 ARG_NUM_4 ARG_NUM_5 ARG_NUM_6 ARG_NUM_3 ARG_NUM_5 ARG_NUM_7 ARG_NUM_1 ARG_NUM_4 ARG_NUM_5 ARG_NUM_4 ARG_NUM_7 ARG_NUM_2 ARG_NUM_3 ARG_NUM_7 ARG_NUM_7 ARG_NUM_3 ARG_NUM_3 ARG_NUM_3 ARG_NUM_7 ARG_NUM_3 ARG_NUM_2 char ARG_NUM_2 ARG_NUM_1 ARG_NUM_0 ARG_NUM_0 ARG_NUM_3 void ARG_NUM_1 ARG_NUM_0 unsigned ARG_NUM_0 ARG_NUM_2 ARG_NUM_3 ARG_NUM_2 ARG_NUM_5 ARG_NUM_3 ARG_NUM_3 ARG_NUM_4 ARG_NUM_1 ARG_NUM_1 ARG_NUM_3 ARG_NUM_2 mode_t
STATIC INLINE BOOL ValidTimeSpec(const struct timespec *tp)
Definition: time_posix.h:53
STATIC INLINE UINT32 OsTimeSpec2Tick(const struct timespec *tp)
Definition: time_posix.h:68
size_t LOS_ArchCopyToUser(void *dst, const void *src, size_t len)
从内核空间拷贝到用户空间
Definition: user_copy.c:79
size_t LOS_ArchCopyFromUser(void *dst, const void *src, size_t len)
Definition: user_copy.c:58
void FreeProcessFd(int procFd)
释放进程文件描述符
Definition: vfs_procfd.c:191