更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
shm.c
浏览该文件的文档.
1/*!
2 * @file shm.c
3 * @brief
4 * @link
5 @verbatim
6 什么是共享内存
7 顾名思义,共享内存就是允许两个不相关的进程访问同一个物理内存。共享内存是在两个正在运行的进程之间
8 共享和传递数据的一种非常有效的方式。不同进程之间共享的内存通常安排为同一段物理内存。进程可以将同
9 一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言
10 函数malloc()分配的内存一样。而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段
11 共享内存的任何其他进程。
12
13 特别提醒:共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制
14 可以阻止第二个进程开始对它进行读取。所以我们通常需要用其他的机制来同步对共享内存的访问
15
16 共享线性区可以由任意的进程创建,每个使用共享线性区都必须经过映射.
17 @endverbatim
18 * @version
19 * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
20 * @date 2021-12-24
21 */
22/*
23 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
24 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without modification,
27 * are permitted provided that the following conditions are met:
28 *
29 * 1. Redistributions of source code must retain the above copyright notice, this list of
30 * conditions and the following disclaimer.
31 *
32 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
33 * of conditions and the following disclaimer in the documentation and/or other materials
34 * provided with the distribution.
35 *
36 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
37 * to endorse or promote products derived from this software without specific prior written
38 * permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
42 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
44 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
46 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
47 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
48 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
49 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
50 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 */
52
53#include "stdio.h"
54#include "string.h"
55#include "time.h"
56#include "sys/types.h"
57#include "sys/shm.h"
58#include "sys/stat.h"
59#include "los_config.h"
60#include "los_init.h"
61#include "los_vm_map.h"
62#include "los_vm_filemap.h"
63#include "los_vm_phys.h"
64#include "los_arch_mmu.h"
65#include "los_vm_page.h"
66#include "los_vm_lock.h"
67#include "los_process.h"
68#include "los_process_pri.h"
69#include "user_copy.h"
70#ifdef LOSCFG_SHELL
71#include "shcmd.h"
72#include "shell.h"
73#endif /* __cplusplus */
74
75#ifdef LOSCFG_KERNEL_SHM
76STATIC LosMux g_sysvShmMux; //互斥锁,共享内存本身并不保证操作的同步性,所以需用互斥锁
77
78/* private macro */
79#define SYSV_SHM_LOCK() (VOID)LOS_MuxLock(&g_sysvShmMux, LOS_WAIT_FOREVER) //申请永久等待锁
80#define SYSV_SHM_UNLOCK() (VOID)LOS_MuxUnlock(&g_sysvShmMux) //释放锁
81
82#define SHM_MAX_PAGES 4096
83#define SHM_MAX (SHM_MAX_PAGES * PAGE_SIZE) // 最大共享空间,4096*4K = 16M
84#define SHM_MIN 1 //
85#define SHM_MNI 192
86#define SHM_SEG 128
87#define SHM_ALL (SHM_MAX_PAGES)
88
89#define SHM_SEG_FREE 0x2000 //空闲未使用
90#define SHM_SEG_USED 0x4000 //已使用
91#define SHM_SEG_REMOVE 0x8000 //删除
92
93#ifndef SHM_M
94#define SHM_M 010000
95#endif
96
97#ifndef SHM_X
98#define SHM_X 0100
99#endif
100#ifndef ACCESSPERMS
101#define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO)//文件权限值意思就是 用户,用户组,其他可读可写.
102#endif //代表含义U:user G:group O:other
103
104#define SHM_S_IRUGO (S_IRUSR | S_IRGRP | S_IROTH)
105#define SHM_S_IWUGO (S_IWUSR | S_IWGRP | S_IWOTH)
106#define SHM_S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
107#define SHM_GROUPE_TO_USER 3
108#define SHM_OTHER_TO_USER 6
109
110#if 0 // @note_#if0
111
112//内核为每一个IPC对象保存一个ipc_perm结构体,该结构说明了IPC对象的权限和所有者
113struct ipc_perm {
114 key_t __ipc_perm_key; //调用shmget()时给出的关键字
115 uid_t uid; //共享内存所有者的有效用户ID
116 gid_t gid; //共享内存所有者所属组的有效组ID
117 uid_t cuid; //共享内存创建 者的有效用户ID
118 gid_t cgid; //共享内存创建者所属组的有效组ID
119 mode_t mode; //权限 + SHM_DEST / SHM_LOCKED /SHM_HUGETLB 标志位
120 int __ipc_perm_seq; //序列号
121 long __pad1; //保留扩展用
122 long __pad2;
123};
124//每个共享内存段在内核中维护着一个内部结构shmid_ds
125struct shmid_ds {
126 struct ipc_perm shm_perm;///< 操作许可,里面包含共享内存的用户ID、组ID等信息
127 size_t shm_segsz; ///< 共享内存段的大小,单位为字节
128 time_t shm_atime; ///< 最后一个进程访问共享内存的时间
129 time_t shm_dtime; ///< 最后一个进程离开共享内存的时间
130 time_t shm_ctime; ///< 创建时间
131 pid_t shm_cpid; ///< 创建共享内存的进程ID
132 pid_t shm_lpid; ///< 最后操作共享内存的进程ID
133 unsigned long shm_nattch; ///< 当前使用该共享内存段的进程数量
134 unsigned long __pad1; //保留扩展用
135 unsigned long __pad2;
136};
137// 共享内存模块设置信息
138struct shminfo {
139 unsigned long shmmax, shmmin, shmmni, shmseg, shmall, __unused[4];
140};
141
142#endif
143
144
145struct shmIDSource {//共享内存描述符
146 struct shmid_ds ds; //是内核为每一个共享内存段维护的数据结构
147 UINT32 status; //状态 SHM_SEG_FREE ...
148 LOS_DL_LIST node; //节点,挂VmPage
149#ifdef LOSCFG_SHELL
150 CHAR ownerName[OS_PCB_NAME_LEN];
151#endif
152};
153
154/* private data */
155STATIC struct shminfo g_shmInfo = { //描述共享内存范围的全局变量
156 .shmmax = SHM_MAX,//共享内存单个上限 4096页 即 16M
157 .shmmin = SHM_MIN,//共享内存单个下限 1页 即:4K
158 .shmmni = SHM_MNI,//共享内存总数 默认192
159 .shmseg = SHM_SEG,//每个用户进程可以使用的最多的共享内存段的数目 128
160 .shmall = SHM_ALL,//系统范围内共享内存的总页数, 4096页
161};
162
163STATIC struct shmIDSource *g_shmSegs = NULL;
165//共享内存初始化
167{
168 UINT32 ret;
169 UINT32 i;
170
171 ret = LOS_MuxInit(&g_sysvShmMux, NULL);//初始化互斥锁
172 if (ret != LOS_OK) {
173 goto ERROR;
174 }
175
176 g_shmSegs = LOS_MemAlloc((VOID *)OS_SYS_MEM_ADDR, sizeof(struct shmIDSource) * g_shmInfo.shmmni);//分配shm段数组
177 if (g_shmSegs == NULL) {
179 goto ERROR;
180 }
181 (VOID)memset_s(g_shmSegs, (sizeof(struct shmIDSource) * g_shmInfo.shmmni),
182 0, (sizeof(struct shmIDSource) * g_shmInfo.shmmni));//数组清零
183
184 for (i = 0; i < g_shmInfo.shmmni; i++) {
185 g_shmSegs[i].status = SHM_SEG_FREE;//节点初始状态为空闲
186 g_shmSegs[i].ds.shm_perm.seq = i + 1;//struct ipc_perm shm_perm;系统为每一个IPC对象保存一个ipc_perm结构体,结构说明了IPC对象的权限和所有者
187 LOS_ListInit(&g_shmSegs[i].node);//初始化节点
188 }
190
191 return LOS_OK;
192
193ERROR:
194 VM_ERR("ShmInit fail\n");
195 return LOS_NOK;
196}
197
198LOS_MODULE_INIT(ShmInit, LOS_INIT_LEVEL_VM_COMPLETE);//共享内存模块初始化
199//共享内存反初始化
201{
202 UINT32 ret;
203
204 (VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, g_shmSegs);//归还内存池
205 g_shmSegs = NULL;
206
207 ret = LOS_MuxDestroy(&g_sysvShmMux);//销毁互斥量
208 if (ret != LOS_OK) {
209 return -1;
210 }
211
212 return 0;
213}
214///给共享段中所有物理页框贴上共享标签
215STATIC inline VOID ShmSetSharedFlag(struct shmIDSource *seg)
216{
217 LosVmPage *page = NULL;
218
219 LOS_DL_LIST_FOR_EACH_ENTRY(page, &seg->node, LosVmPage, node) {
220 OsSetPageShared(page);
221 }
222}
223///给共享段中所有物理页框撕掉共享标签
224STATIC inline VOID ShmClearSharedFlag(struct shmIDSource *seg)
225{
226 LosVmPage *page = NULL;
227
228 LOS_DL_LIST_FOR_EACH_ENTRY(page, &seg->node, LosVmPage, node) {
229 OsCleanPageShared(page);
230 }
231}
232///seg下所有共享页引用减少
233STATIC VOID ShmPagesRefDec(struct shmIDSource *seg)
234{
235 LosVmPage *page = NULL;
236
237 LOS_DL_LIST_FOR_EACH_ENTRY(page, &seg->node, LosVmPage, node) {
238 LOS_AtomicDec(&page->refCounts);
239 }
240}
241
242/**
243 * @brief 为共享段分配物理内存
244 例如:参数size = 4097, LOS_Align(size, PAGE_SIZE) = 8192
245 分配页数 size >> PAGE_SHIFT = 2页
246 * @param key
247 * @param size
248 * @param shmflg
249 * @return STATIC
250 */
251STATIC INT32 ShmAllocSeg(key_t key, size_t size, INT32 shmflg)
252{
253 INT32 i;
254 INT32 segNum = -1;
255 struct shmIDSource *seg = NULL;
256 size_t count;
257
258 if ((size == 0) || (size < g_shmInfo.shmmin) ||
259 (size > g_shmInfo.shmmax)) {
260 return -EINVAL;
261 }
262 size = LOS_Align(size, PAGE_SIZE);//必须对齐
263 if ((g_shmUsedPageCount + (size >> PAGE_SHIFT)) > g_shmInfo.shmall) {
264 return -ENOMEM;
265 }
266
267 for (i = 0; i < g_shmInfo.shmmni; i++) {//试图找到一个空闲段与参数key绑定
268 if (g_shmSegs[i].status & SHM_SEG_FREE) {//找到空闲段
269 g_shmSegs[i].status &= ~SHM_SEG_FREE;//变成非空闲状态
270 segNum = i;//标号
271 break;
272 }
273 }
274
275 if (segNum < 0) {
276 return -ENOSPC;
277 }
278
279 seg = &g_shmSegs[segNum];
280 count = LOS_PhysPagesAlloc(size >> PAGE_SHIFT, &seg->node);//分配共享页面,函数内部把node都挂好了.
281 if (count != (size >> PAGE_SHIFT)) {//当未分配到足够的内存时,处理方式是:不稀罕给那么点,舍弃!
282 (VOID)LOS_PhysPagesFree(&seg->node);//释放节点上的物理页框
283 seg->status = SHM_SEG_FREE;//共享段变回空闲状态
284 return -ENOMEM;
285 }
286 ShmSetSharedFlag(seg);//将node的每个页面设置为共享页
287 g_shmUsedPageCount += size >> PAGE_SHIFT;
288
289 seg->status |= SHM_SEG_USED; //共享段贴上已在使用的标签
290 seg->ds.shm_perm.mode = (UINT32)shmflg & ACCESSPERMS;
291 seg->ds.shm_perm.key = key;//保存参数key,如此 key 和 共享ID绑定在一块
292 seg->ds.shm_segsz = size; //共享段的大小
293 seg->ds.shm_perm.cuid = LOS_GetUserID(); //设置用户ID
294 seg->ds.shm_perm.uid = LOS_GetUserID(); //设置用户ID
295 seg->ds.shm_perm.cgid = LOS_GetGroupID(); //设置组ID
296 seg->ds.shm_perm.gid = LOS_GetGroupID(); //设置组ID
297 seg->ds.shm_lpid = 0; //最后一个操作的进程
298 seg->ds.shm_nattch = 0; //绑定进程的数量
299 seg->ds.shm_cpid = LOS_GetCurrProcessID(); //获取进程ID
300 seg->ds.shm_atime = 0; //访问时间
301 seg->ds.shm_dtime = 0; //detach 分离时间 共享内存使用完之后,需要将它从进程地址空间中分离出来;将共享内存分离并不是删除它,只是使该共享内存对当前的进程不再可用
302 seg->ds.shm_ctime = time(NULL);//创建时间
303#ifdef LOSCFG_SHELL
304 (VOID)memcpy_s(seg->ownerName, OS_PCB_NAME_LEN, OsCurrProcessGet()->processName, OS_PCB_NAME_LEN);
305#endif
306
307 return segNum;
308}
309///释放seg->node 所占物理页框,seg本身重置
310STATIC INLINE VOID ShmFreeSeg(struct shmIDSource *seg)
311{
312 UINT32 count;
313
314 ShmClearSharedFlag(seg);//先撕掉 seg->node 中vmpage的共享标签
315 count = LOS_PhysPagesFree(&seg->node);//再挨个删除物理页框
316 if (count != (seg->ds.shm_segsz >> PAGE_SHIFT)) {//异常,必须要一样
317 VM_ERR("free physical pages failed, count = %d, size = %d", count, seg->ds.shm_segsz >> PAGE_SHIFT);
318 return;
319 }
320 g_shmUsedPageCount -= seg->ds.shm_segsz >> PAGE_SHIFT;
321 seg->status = SHM_SEG_FREE;//seg恢复自由之身
322 LOS_ListInit(&seg->node);//重置node
323}
324///通过key查找 shmId
325STATIC INT32 ShmFindSegByKey(key_t key)
326{
327 INT32 i;
328 struct shmIDSource *seg = NULL;
329
330 for (i = 0; i < g_shmInfo.shmmni; i++) {//遍历共享段池,找到与key绑定的共享ID
331 seg = &g_shmSegs[i];
332 if ((seg->status & SHM_SEG_USED) &&
333 (seg->ds.shm_perm.key == key)) {//满足两个条件,找到后返回
334 return i;
335 }
336 }
337
338 return -1;
339}
340///共享内存段有效性检查
341STATIC INT32 ShmSegValidCheck(INT32 segNum, size_t size, INT32 shmFlg)
342{
343 struct shmIDSource *seg = &g_shmSegs[segNum];//拿到shmID
344
345 if (size > seg->ds.shm_segsz) {//段长
346 return -EINVAL;
347 }
348
349 if (((UINT32)shmFlg & (IPC_CREAT | IPC_EXCL)) ==
350 (IPC_CREAT | IPC_EXCL)) {
351 return -EEXIST;
352 }
353
354 return segNum;
355}
356///通过ID找到共享内存资源
357STATIC struct shmIDSource *ShmFindSeg(int shmid)
358{
359 struct shmIDSource *seg = NULL;
360
361 if ((shmid < 0) || (shmid >= g_shmInfo.shmmni)) {
362 set_errno(EINVAL);
363 return NULL;
364 }
365
366 seg = &g_shmSegs[shmid];
367 if ((seg->status & SHM_SEG_FREE) || ((seg->ds.shm_nattch == 0) && (seg->status & SHM_SEG_REMOVE))) {
368 set_errno(EIDRM);
369 return NULL;
370 }
371
372 return seg;
373}
374///共享内存映射
375STATIC VOID ShmVmmMapping(LosVmSpace *space, LOS_DL_LIST *pageList, VADDR_T vaddr, UINT32 regionFlags)
376{
377 LosVmPage *vmPage = NULL;
378 VADDR_T va = vaddr;
379 PADDR_T pa;
380 STATUS_T ret;
381
382 LOS_DL_LIST_FOR_EACH_ENTRY(vmPage, pageList, LosVmPage, node) {//遍历一页一页映射
383 pa = VM_PAGE_TO_PHYS(vmPage);//拿到物理地址
384 LOS_AtomicInc(&vmPage->refCounts);//自增
385 ret = LOS_ArchMmuMap(&space->archMmu, va, pa, 1, regionFlags);//虚实映射
386 if (ret != 1) {
387 VM_ERR("LOS_ArchMmuMap failed, ret = %d", ret);
388 }
389 va += PAGE_SIZE;
390 }
391}
392///fork 一个共享线性区
393VOID OsShmFork(LosVmSpace *space, LosVmMapRegion *oldRegion, LosVmMapRegion *newRegion)
394{
395 struct shmIDSource *seg = NULL;
396
397 SYSV_SHM_LOCK();
398 seg = ShmFindSeg(oldRegion->shmid);//通过老区ID获取对应的共享资源ID结构体
399 if (seg == NULL) {
400 SYSV_SHM_UNLOCK();
401 VM_ERR("shm fork failed!");
402 return;
403 }
404
405 newRegion->shmid = oldRegion->shmid;//一样的共享区ID
406 newRegion->forkFlags = oldRegion->forkFlags;//forkFlags也一样了
407 ShmVmmMapping(space, &seg->node, newRegion->range.base, newRegion->regionFlags);//新线性区与共享内存进行映射
408 seg->ds.shm_nattch++;//附在共享线性区上的进程数++
409 SYSV_SHM_UNLOCK();
410}
411///释放共享线性区
413{
414 struct shmIDSource *seg = NULL;
415
416 SYSV_SHM_LOCK();
417 seg = ShmFindSeg(region->shmid);//通过线性区ID获取对应的共享资源ID结构体
418 if (seg == NULL) {
419 SYSV_SHM_UNLOCK();
420 return;
421 }
422
423 LOS_ArchMmuUnmap(&space->archMmu, region->range.base, region->range.size >> PAGE_SHIFT);//解除线性区的映射
424 ShmPagesRefDec(seg);//ref --
425 seg->ds.shm_nattch--;//附在共享线性区上的进程数--
426 if (seg->ds.shm_nattch <= 0 && (seg->status & SHM_SEG_REMOVE)) {
427 ShmFreeSeg(seg);//就释放掉物理内存!注意是:物理内存
428 } else {
429 seg->ds.shm_dtime = time(NULL);
430 seg->ds.shm_lpid = LOS_GetCurrProcessID(); /* may not be the space's PID. */
431 }
432 SYSV_SHM_UNLOCK();
433}
434///是否为共享线性区,是否有标签?
436{
437 return (region->regionFlags & VM_MAP_REGION_FLAG_SHM) ? TRUE : FALSE;
438}
439///获取共享内存池中已被使用的段数量
441{
442 INT32 i;
443 INT32 count = 0;
444 struct shmIDSource *seg = NULL;
445
446 for (i = 0; i < g_shmInfo.shmmni; i++) {
447 seg = &g_shmSegs[i];
448 if (seg->status & SHM_SEG_USED) {//找到一个
449 count++;
450 }
451 }
452 return count;
453}
454///对共享内存段权限检查
455STATIC INT32 ShmPermCheck(struct shmIDSource *seg, mode_t mode)
456{
457 INT32 uid = LOS_GetUserID();//当前进程的用户ID
458 UINT32 tmpMode = 0;
459 mode_t privMode = seg->ds.shm_perm.mode;
460 mode_t accMode;
461
462 if ((uid == seg->ds.shm_perm.uid) || (uid == seg->ds.shm_perm.cuid)) {
463 tmpMode |= SHM_M;
464 accMode = mode & S_IRWXU;
465 } else if (LOS_CheckInGroups(seg->ds.shm_perm.gid) ||
467 privMode <<= SHM_GROUPE_TO_USER;
468 accMode = (mode & S_IRWXG) << SHM_GROUPE_TO_USER;
469 } else {
470 privMode <<= SHM_OTHER_TO_USER;
471 accMode = (mode & S_IRWXO) << SHM_OTHER_TO_USER;
472 }
473
474 if (privMode & SHM_R) {
475 tmpMode |= SHM_R;
476 }
477
478 if (privMode & SHM_W) {
479 tmpMode |= SHM_W;
480 }
481
482 if (privMode & SHM_X) {
483 tmpMode |= SHM_X;
484 }
485
486 if ((mode == SHM_M) && (tmpMode & SHM_M)) {
487 return 0;
488 } else if (mode == SHM_M) {
489 return EACCES;
490 }
491
492 if ((tmpMode & accMode) == accMode) {
493 return 0;
494 } else {
495 return EACCES;
496 }
497}
498
499/*!
500 * @brief ShmGet
501 * 得到一个共享内存标识符或创建一个共享内存对象
502 * @param key 建立新共享内存对象 标识符是IPC对象的内部名。为使多个合作进程能够在同一IPC对象上汇聚,需要提供一个外部命名方案。
503 为此,每个IPC对象都与一个键(key)相关联,这个键作为该对象的外部名,无论何时创建IPC结构(通过msgget、semget、shmget创建),
504 都应给IPC指定一个键, key_t由ftok创建,ftok当然在本工程里找不到,所以要写这么多.
505 * @param shmflg IPC_CREAT IPC_EXCL
506 IPC_CREAT: 在创建新的IPC时,如果key参数是IPC_PRIVATE或者和当前某种类型的IPC结构无关,则需要指明flag参数的IPC_CREAT标志位,
507 则用来创建一个新的IPC结构。(如果IPC结构已存在,并且指定了IPC_CREAT,则IPC_CREAT什么都不做,函数也不出错)
508 IPC_EXCL: 此参数一般与IPC_CREAT配合使用来创建一个新的IPC结构。如果创建的IPC结构已存在函数就出错返回,
509 返回EEXIST(这与open函数指定O_CREAT和O_EXCL标志原理相同)
510 * @param size 新建的共享内存大小,以字节为单位
511 * @return
512 *
513 * @see
514 */
515INT32 ShmGet(key_t key, size_t size, INT32 shmflg)
516{
517 INT32 ret;
518 INT32 shmid;
519
520 SYSV_SHM_LOCK();
521
522 if (key == IPC_PRIVATE) {
523 ret = ShmAllocSeg(key, size, shmflg);
524 } else {
525 ret = ShmFindSegByKey(key);//通过key查找资源ID
526 if (ret < 0) {
527 if (((UINT32)shmflg & IPC_CREAT) == 0) {//
528 ret = -ENOENT;
529 goto ERROR;
530 } else {
531 ret = ShmAllocSeg(key, size, shmflg);//分配一个共享内存
532 }
533 } else {
534 shmid = ret;
535 if (((UINT32)shmflg & IPC_CREAT) &&
536 ((UINT32)shmflg & IPC_EXCL)) {
537 ret = -EEXIST;
538 goto ERROR;
539 }
540 ret = ShmPermCheck(ShmFindSeg(shmid), (UINT32)shmflg & ACCESSPERMS);//对共享内存权限检查
541 if (ret != 0) {
542 ret = -ret;
543 goto ERROR;
544 }
545 ret = ShmSegValidCheck(shmid, size, shmflg);
546 }
547 }
548 if (ret < 0) {
549 goto ERROR;
550 }
551
552 SYSV_SHM_UNLOCK();
553
554 return ret;
555ERROR:
556 set_errno(-ret);
557 SYSV_SHM_UNLOCK();
558 PRINT_DEBUG("%s %d, ret = %d\n", __FUNCTION__, __LINE__, ret);
559 return -1;
560}
561
562INT32 ShmatParamCheck(const VOID *shmaddr, INT32 shmflg)
563{
564 if (((UINT32)shmflg & SHM_REMAP) && (shmaddr == NULL)) {
565 return EINVAL;
566 }
567
568 if ((shmaddr != NULL) && !IS_PAGE_ALIGNED(shmaddr) &&
569 (((UINT32)shmflg & SHM_RND) == 0)) {
570 return EINVAL;
571 }
572
573 return 0;
574}
575///分配一个共享线性区并映射好
576LosVmMapRegion *ShmatVmmAlloc(struct shmIDSource *seg, const VOID *shmaddr,
577 INT32 shmflg, UINT32 prot)
578{
580 LosVmMapRegion *region = NULL;
581 UINT32 flags = MAP_ANONYMOUS | MAP_SHARED;//本线性区为共享+匿名标签
582 UINT32 mapFlags = flags | MAP_FIXED;
583 VADDR_T vaddr;
584 UINT32 regionFlags;
585 INT32 ret;
586
587 if (shmaddr != NULL) {
588 flags |= MAP_FIXED_NOREPLACE;
589 }
590 regionFlags = OsCvtProtFlagsToRegionFlags(prot, flags);
591 (VOID)LOS_MuxAcquire(&space->regionMux);
592 if (shmaddr == NULL) {//未指定了共享内存连接到当前进程中的地址位置
593 region = LOS_RegionAlloc(space, 0, seg->ds.shm_segsz, regionFlags, 0);//分配线性区
594 } else {//指定时,就需要先找地址所在的线性区
595 if ((UINT32)shmflg & SHM_RND) {
596 vaddr = ROUNDDOWN((VADDR_T)(UINTPTR)shmaddr, SHMLBA);
597 } else {
598 vaddr = (VADDR_T)(UINTPTR)shmaddr;
599 }//找到线性区并重新映射,当指定地址时需贴上重新映射的标签
600 if (!((UINT32)shmflg & SHM_REMAP) && (LOS_RegionFind(space, vaddr) ||
601 LOS_RegionFind(space, vaddr + seg->ds.shm_segsz - 1) ||
602 LOS_RegionRangeFind(space, vaddr, seg->ds.shm_segsz - 1))) {
603 ret = EINVAL;
604 goto ERROR;
605 }
606 vaddr = (VADDR_T)LOS_MMap(vaddr, seg->ds.shm_segsz, prot, mapFlags, -1, 0);//做好映射
607 region = LOS_RegionFind(space, vaddr);//重新查找线性区,用于返回.
608 }
609
610 if (region == NULL) {
611 ret = ENOMEM;
612 goto ERROR;
613 }
614 ShmVmmMapping(space, &seg->node, region->range.base, regionFlags);//共享内存映射
615 (VOID)LOS_MuxRelease(&space->regionMux);
616 return region;
617ERROR:
618 set_errno(ret);
619 (VOID)LOS_MuxRelease(&space->regionMux);
620 return NULL;
621}
622
623/*!
624 * @brief ShmAt
625 * 用来启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间。
626 * @param shm_flg 是一组标志位,通常为0。
627 * @param shmaddr 指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。
628 * @param shmid 是shmget()函数返回的共享内存标识符
629 * @return
630 * 如果shmat成功执行,那么内核将使与该共享存储相关的shmid_ds结构中的shm_nattch计数器值加1
631 shmid 就是个索引,就跟进程和线程的ID一样 g_shmSegs[shmid] shmid > 192个
632 * @see
633 */
634VOID *ShmAt(INT32 shmid, const VOID *shmaddr, INT32 shmflg)
635{
636 INT32 ret;
637 UINT32 prot = PROT_READ;
638 mode_t acc_mode = SHM_S_IRUGO;
639 struct shmIDSource *seg = NULL;
640 LosVmMapRegion *r = NULL;
641
642 ret = ShmatParamCheck(shmaddr, shmflg);//参数检查
643 if (ret != 0) {
644 set_errno(ret);
645 return (VOID *)-1;
646 }
647
648 if ((UINT32)shmflg & SHM_EXEC) {//flag 转换
649 prot |= PROT_EXEC;
650 acc_mode |= SHM_S_IXUGO;
651 } else if (((UINT32)shmflg & SHM_RDONLY) == 0) {
652 prot |= PROT_WRITE;
653 acc_mode |= SHM_S_IWUGO;
654 }
655
656 SYSV_SHM_LOCK();
657 seg = ShmFindSeg(shmid);//找到段
658 if (seg == NULL) {
659 SYSV_SHM_UNLOCK();
660 return (VOID *)-1;
661 }
662
663 ret = ShmPermCheck(seg, acc_mode);
664 if (ret != 0) {
665 goto ERROR;
666 }
667
668 seg->ds.shm_nattch++;//ds上记录有一个进程绑定上来
669 r = ShmatVmmAlloc(seg, shmaddr, shmflg, prot);//在当前进程空间分配一个线性区并映射到共享内存
670 if (r == NULL) {
671 seg->ds.shm_nattch--;
672 SYSV_SHM_UNLOCK();
673 return (VOID *)-1;
674 }
675
676 r->shmid = shmid;//把ID给线性区的shmid
677 r->regionFlags |= VM_MAP_REGION_FLAG_SHM;//这是一个共享线性区
678 seg->ds.shm_atime = time(NULL);//访问时间
679 seg->ds.shm_lpid = LOS_GetCurrProcessID();//进程ID
680 SYSV_SHM_UNLOCK();
681
682 return (VOID *)(UINTPTR)r->range.base;
683ERROR:
684 set_errno(ret);
685 SYSV_SHM_UNLOCK();
686 PRINT_DEBUG("%s %d, ret = %d\n", __FUNCTION__, __LINE__, ret);
687 return (VOID *)-1;
688}
689
690/*!
691 * @brief ShmCtl
692 * 此函数可以对shmid指定的共享存储进行多种操作(删除、取信息、加锁、解锁等)
693 * @param buf 是一个结构指针,它指向共享内存模式和访问权限的结构。
694 * @param cmd command是要采取的操作,它可以取下面的三个值 :
695 IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖shmid_ds的值。
696 IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为shmid_ds结构中给出的值
697 IPC_RMID:删除共享内存段
698 * @param shmid 是shmget()函数返回的共享内存标识符
699 * @return
700 *
701 * @see
702 */
703INT32 ShmCtl(INT32 shmid, INT32 cmd, struct shmid_ds *buf)
704{
705 struct shmIDSource *seg = NULL;
706 INT32 ret = 0;
707 struct shm_info shmInfo;
708 struct ipc_perm shm_perm;
709
710 cmd = ((UINT32)cmd & ~IPC_64);
711
712 SYSV_SHM_LOCK();
713
714 if ((cmd != IPC_INFO) && (cmd != SHM_INFO)) {
715 seg = ShmFindSeg(shmid);//通过索引ID找到seg
716 if (seg == NULL) {
717 SYSV_SHM_UNLOCK();
718 return -1;
719 }
720 }
721
722 if ((buf == NULL) && (cmd != IPC_RMID)) {
723 ret = EINVAL;
724 goto ERROR;
725 }
726
727 switch (cmd) {
728 case IPC_STAT:
729 case SHM_STAT://取段结构
730 ret = ShmPermCheck(seg, SHM_S_IRUGO);
731 if (ret != 0) {
732 goto ERROR;
733 }
734
735 ret = LOS_ArchCopyToUser(buf, &seg->ds, sizeof(struct shmid_ds));//把内核空间的共享页数据拷贝到用户空间
736 if (ret != 0) {
737 ret = EFAULT;
738 goto ERROR;
739 }
740 if (cmd == SHM_STAT) {
741 ret = (unsigned int)((unsigned int)seg->ds.shm_perm.seq << 16) | (unsigned int)((unsigned int)shmid & 0xffff); /* 16: use the seq as the upper 16 bits */
742 }
743 break;
744 case IPC_SET://重置共享段
745 ret = ShmPermCheck(seg, SHM_M);
746 if (ret != 0) {
747 ret = EPERM;
748 goto ERROR;
749 }
750 //从用户空间拷贝数据到内核空间
751 ret = LOS_ArchCopyFromUser(&shm_perm, &buf->shm_perm, sizeof(struct ipc_perm));
752 if (ret != 0) {
753 ret = EFAULT;
754 goto ERROR;
755 }
756 seg->ds.shm_perm.uid = shm_perm.uid;
757 seg->ds.shm_perm.gid = shm_perm.gid;
758 seg->ds.shm_perm.mode = (seg->ds.shm_perm.mode & ~ACCESSPERMS) |
759 (shm_perm.mode & ACCESSPERMS);//可访问
760 seg->ds.shm_ctime = time(NULL);
761#ifdef LOSCFG_SHELL
762 (VOID)memcpy_s(seg->ownerName, OS_PCB_NAME_LEN, OS_PCB_FROM_PID(shm_perm.uid)->processName,
763 OS_PCB_NAME_LEN);
764#endif
765 break;
766 case IPC_RMID://删除共享段
767 ret = ShmPermCheck(seg, SHM_M);
768 if (ret != 0) {
769 ret = EPERM;
770 goto ERROR;
771 }
772
773 seg->status |= SHM_SEG_REMOVE;
774 if (seg->ds.shm_nattch <= 0) {//没有任何进程在使用了
775 ShmFreeSeg(seg);//释放 归还内存
776 }
777 break;
778 case IPC_INFO://把内核空间的共享页数据拷贝到用户空间
779 ret = LOS_ArchCopyToUser(buf, &g_shmInfo, sizeof(struct shminfo));
780 if (ret != 0) {
781 ret = EFAULT;
782 goto ERROR;
783 }
784 ret = g_shmInfo.shmmni;
785 break;
786 case SHM_INFO:
787 shmInfo.shm_rss = 0;
788 shmInfo.shm_swp = 0;
789 shmInfo.shm_tot = 0;
790 shmInfo.swap_attempts = 0;
791 shmInfo.swap_successes = 0;
792 shmInfo.used_ids = ShmSegUsedCount();//在使用的seg数
793 ret = LOS_ArchCopyToUser(buf, &shmInfo, sizeof(struct shm_info));//把内核空间的共享页数据拷贝到用户空间
794 if (ret != 0) {
795 ret = EFAULT;
796 goto ERROR;
797 }
798 ret = g_shmInfo.shmmni;
799 break;
800 default:
801 VM_ERR("the cmd(%d) is not supported!", cmd);
802 ret = EINVAL;
803 goto ERROR;
804 }
805
806 SYSV_SHM_UNLOCK();
807 return ret;
808
809ERROR:
810 set_errno(ret);
811 SYSV_SHM_UNLOCK();
812 PRINT_DEBUG("%s %d, ret = %d\n", __FUNCTION__, __LINE__, ret);
813 return -1;
814}
815
816/**
817 * @brief 当对共享存储的操作已经结束时,则调用shmdt与该存储段分离
818 如果shmat成功执行,那么内核将使与该共享存储相关的shmid_ds结构中的shm_nattch计数器值减1
819 * @attention 注意:这并不从系统中删除共享存储的标识符以及其相关的数据结构。共享存储的仍然存在,
820 直至某个进程带IPC_RMID命令的调用shmctl特地删除共享存储为止
821 * @param shmaddr
822 * @return INT32
823 */
824INT32 ShmDt(const VOID *shmaddr)
825{
826 LosVmSpace *space = OsCurrProcessGet()->vmSpace;//获取进程空间
827 struct shmIDSource *seg = NULL;
828 LosVmMapRegion *region = NULL;
829 INT32 shmid;
830 INT32 ret;
831
832 if (IS_PAGE_ALIGNED(shmaddr) == 0) {//地址是否对齐
833 ret = EINVAL;
834 goto ERROR;
835 }
836
837 (VOID)LOS_MuxAcquire(&space->regionMux);
838 region = LOS_RegionFind(space, (VADDR_T)(UINTPTR)shmaddr);//找到线性区
839 if (region == NULL) {
840 ret = EINVAL;
841 goto ERROR_WITH_LOCK;
842 }
843 shmid = region->shmid;//线性区共享ID
844
845 if (region->range.base != (VADDR_T)(UINTPTR)shmaddr) {//这是用户空间和内核空间的一次解绑
846 ret = EINVAL; //shmaddr 必须要等于region->range.base
847 goto ERROR_WITH_LOCK;
848 }
849
850 /* remove it from aspace */
851 LOS_RbDelNode(&space->regionRbTree, &region->rbNode);//从红黑树和链表中摘除节点
852 LOS_ArchMmuUnmap(&space->archMmu, region->range.base, region->range.size >> PAGE_SHIFT);//解除线性区的映射
853 (VOID)LOS_MuxRelease(&space->regionMux);
854 /* free it */
855 free(region);//释放线性区所占内存池中的内存
856
857 SYSV_SHM_LOCK();
858 seg = ShmFindSeg(shmid);//找到seg,线性区和共享段的关系是 1:N 的关系,其他空间的线性区也会绑在共享段上
859 if (seg == NULL) {
860 ret = EINVAL;
861 SYSV_SHM_UNLOCK();
862 goto ERROR;
863 }
864
865 ShmPagesRefDec(seg);//页面引用数 --
866 seg->ds.shm_nattch--;//使用共享内存的进程数少了一个
867 if ((seg->ds.shm_nattch <= 0) && //无任何进程使用共享内存
868 (seg->status & SHM_SEG_REMOVE)) {//状态为删除时需要释放物理页内存了,否则其他进程还要继续使用共享内存
869 ShmFreeSeg(seg);//释放seg 页框链表中的页框内存,再重置seg状态
870 } else {
871
872 seg->ds.shm_dtime = time(NULL);//记录分离的时间
873 seg->ds.shm_lpid = LOS_GetCurrProcessID();//记录操作进程ID
874 }
875 SYSV_SHM_UNLOCK();
876
877 return 0;
878
879ERROR_WITH_LOCK:
880 (VOID)LOS_MuxRelease(&space->regionMux);
881ERROR:
882 set_errno(ret);
883 PRINT_DEBUG("%s %d, ret = %d\n", __FUNCTION__, __LINE__, ret);
884 return -1;
885}
886
887#ifdef LOSCFG_SHELL
888STATIC VOID OsShmInfoCmd(VOID)
889{
890 INT32 i;
891 struct shmIDSource *seg = NULL;
892
893 PRINTK("\r\n------- Shared Memory Segments -------\n");
894 PRINTK("key shmid perms bytes nattch status owner\n");
895 SYSV_SHM_LOCK();
896 for (i = 0; i < g_shmInfo.shmmni; i++) {
897 seg = &g_shmSegs[i];
898 if (!(seg->status & SHM_SEG_USED)) {
899 continue;
900 }
901 PRINTK("%08x %-8d %-10o %-10u %-10u %-10x %s\n", seg->ds.shm_perm.key,
902 i, seg->ds.shm_perm.mode, seg->ds.shm_segsz, seg->ds.shm_nattch,
903 seg->status, seg->ownerName);
904
905 }
906 SYSV_SHM_UNLOCK();
907}
908STATIC VOID OsShmDeleteCmd(INT32 shmid)
909{
910 struct shmIDSource *seg = NULL;
911
912 if ((shmid < 0) || (shmid >= g_shmInfo.shmmni)) {
913 PRINT_ERR("shmid is invalid: %d\n", shmid);
914 return;
915 }
916
917 SYSV_SHM_LOCK();
918 seg = ShmFindSeg(shmid);
919 if (seg == NULL) {
920 SYSV_SHM_UNLOCK();
921 return;
922 }
923
924 if (seg->ds.shm_nattch <= 0) {
925 ShmFreeSeg(seg);
926 }
927 SYSV_SHM_UNLOCK();
928}
929
930STATIC VOID OsShmCmdUsage(VOID)
931{
932 PRINTK("\tnone option, print shm usage info\n"
933 "\t-r [shmid], Recycle the specified shared memory about shmid\n"
934 "\t-h | --help, print shm command usage\n");
935}
936///共享内存
937UINT32 OsShellCmdShm(INT32 argc, const CHAR *argv[])
938{
939 INT32 shmid;
940 CHAR *endPtr = NULL;
941
942 if (argc == 0) {
943 OsShmInfoCmd();
944 } else if (argc == 1) {
945 if ((strcmp(argv[0], "-h") != 0) && (strcmp(argv[0], "--help") != 0)) {
946 PRINTK("Invalid option: %s\n", argv[0]);
947 }
949 } else if (argc == 2) { /* 2: two parameter */
950 if (strcmp(argv[0], "-r") != 0) {
951 PRINTK("Invalid option: %s\n", argv[0]);
952 goto DONE;
953 }
954 shmid = strtoul((CHAR *)argv[1], &endPtr, 0);
955 if ((endPtr == NULL) || (*endPtr != 0)) {
956 PRINTK("check shmid %s(us) invalid\n", argv[1]);
957 goto DONE;
958 }
959 /* try to delete shm about shmid */
960 OsShmDeleteCmd(shmid);
961 }
962 return 0;
963DONE:
965 return -1;
966}
967
969#endif
970#endif
971
@ CMD_TYPE_SHOW
用户怎么输入就怎么显示出现,包括 \0 这些字符也都会存在
Definition: shell.h:89
STATIC INLINE VOID LOS_AtomicInc(Atomic *v)
Atomic addSelf.
Definition: los_atomic.h:253
STATIC INLINE VOID LOS_AtomicDec(Atomic *v)
Atomic auto-decrement. | 对32bit原子数据做减1
Definition: los_atomic.h:323
LITE_OS_SEC_TEXT UINTPTR LOS_Align(UINTPTR addr, UINT32 boundary)
Align the value (addr) by some bytes (boundary) you specify.
Definition: los_misc.c:35
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_ListInit(LOS_DL_LIST *list)
Definition: los_list.h:104
VOID * LOS_MemAlloc(VOID *pool, UINT32 size)
从指定内存池中申请size长度的内存,注意这可不是从内核堆空间中申请内存
Definition: los_memory.c:1123
UINT32 LOS_MemFree(VOID *pool, VOID *ptr)
释放从指定动态内存中申请的内存
Definition: los_memory.c:1369
LITE_OS_SEC_TEXT UINT32 LOS_MuxInit(LosMux *mutex, const LosMuxAttr *attr)
初始化互斥锁
Definition: los_mux.c:262
LITE_OS_SEC_TEXT UINT32 LOS_MuxDestroy(LosMux *mutex)
销毁互斥锁
Definition: los_mux.c:289
https://blog.csdn.net/qq_38410730/article/details/81036768
STATUS_T LOS_ArchMmuMap(LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T paddr, size_t count, UINT32 flags)
LOS_ArchMmuMap 映射进程空间虚拟地址区间与物理地址区间 所谓的map就是生成L1,L2页表项的过程
Definition: los_arch_mmu.c:891
STATUS_T LOS_ArchMmuUnmap(LosArchMmu *archMmu, VADDR_T vaddr, size_t count)
LOS_ArchMmuUnmap 解除进程空间虚拟地址区间与物理地址区间的映射关系
Definition: los_arch_mmu.c:619
LITE_OS_SEC_TEXT INT32 LOS_GetUserID(VOID)
Definition: los_process.c:826
LITE_OS_SEC_TEXT INT32 LOS_GetGroupID(VOID)
Definition: los_process.c:842
LITE_OS_SEC_TEXT UINT32 LOS_GetCurrProcessID(VOID)
获取当前进程的进程ID
Definition: los_process.c:2161
LITE_OS_SEC_TEXT BOOL LOS_CheckInGroups(UINT32 gid)
Definition: los_process.c:805
STATIC INLINE LosProcessCB * OsCurrProcessGet(VOID)
VOID LOS_RbDelNode(LosRbTree *pstTree, LosRbNode *pstNode)
Definition: los_rbtree.c:700
unsigned long PADDR_T
Definition: los_typedef.h:207
signed int INT32
Definition: los_typedef.h:60
unsigned long VADDR_T
Definition: los_typedef.h:208
int STATUS_T
Definition: los_typedef.h:215
unsigned long UINTPTR
Definition: los_typedef.h:68
unsigned int UINT32
Definition: los_typedef.h:57
char CHAR
Definition: los_typedef.h:63
size_t BOOL
Definition: los_typedef.h:88
STATIC INLINE VOID OsCleanPageShared(LosVmPage *page)
给页面撕掉共享页标签
STATIC INLINE VOID OsSetPageShared(LosVmPage *page)
STATIC INLINE STATUS_T LOS_MuxAcquire(LosMux *m)
Definition: los_vm_lock.h:48
STATIC INLINE STATUS_T LOS_MuxRelease(LosMux *m)
Definition: los_vm_lock.h:53
STATIC INLINE UINT32 OsCvtProtFlagsToRegionFlags(unsigned long prot, unsigned long flags)
从外部权限标签转化为线性区权限标签
Definition: los_vm_map.h:197
LosVmMapRegion * LOS_RegionFind(LosVmSpace *vmSpace, VADDR_T addr)
查找线性区 根据起始地址在进程空间内查找是否存在
Definition: los_vm_map.c:414
LosVmMapRegion * LOS_RegionAlloc(LosVmSpace *vmSpace, VADDR_T vaddr, size_t len, UINT32 regionFlags, VM_OFFSET_T pgoff)
Definition: los_vm_map.c:581
LosVmMapRegion * LOS_RegionRangeFind(LosVmSpace *vmSpace, VADDR_T addr, size_t len)
查找线性区 根据地址区间在进程空间内查找是否存在
Definition: los_vm_map.c:425
size_t LOS_PhysPagesAlloc(size_t nPages, LOS_DL_LIST *list)
LOS_PhysPagesAlloc 分配nPages页个物理页框,并将页框挂入list 返回已分配的页面大小,不负责一定能分配到nPages的页框
Definition: los_vm_phys.c:581
size_t LOS_PhysPagesFree(LOS_DL_LIST *list)
释放双链表中的所有节点内存,本质是回归到伙伴orderlist中
Definition: los_vm_phys.c:661
VADDR_T LOS_MMap(VADDR_T vaddr, size_t len, unsigned prot, unsigned long flags, int fd, unsigned long pgoff)
void free(void *ptr)
释放ptr所指向的内存空间
Definition: malloc.c:66
STATIC struct shmIDSource * g_shmSegs
Definition: shm.c:163
VOID OsShmFork(LosVmSpace *space, LosVmMapRegion *oldRegion, LosVmMapRegion *newRegion)
fork 一个共享线性区
Definition: shm.c:393
LosVmMapRegion * ShmatVmmAlloc(struct shmIDSource *seg, const VOID *shmaddr, INT32 shmflg, UINT32 prot)
分配一个共享线性区并映射好
Definition: shm.c:576
BOOL OsIsShmRegion(LosVmMapRegion *region)
是否为共享线性区,是否有标签?
Definition: shm.c:435
STATIC VOID OsShmDeleteCmd(INT32 shmid)
Definition: shm.c:908
STATIC VOID OsShmInfoCmd(VOID)
Definition: shm.c:888
STATIC INT32 ShmFindSegByKey(key_t key)
通过key查找 shmId
Definition: shm.c:325
STATIC INLINE VOID ShmFreeSeg(struct shmIDSource *seg)
释放seg->node 所占物理页框,seg本身重置
Definition: shm.c:310
LOS_MODULE_INIT(ShmInit, LOS_INIT_LEVEL_VM_COMPLETE)
UINT32 ShmDeinit(VOID)
Definition: shm.c:200
STATIC LosMux g_sysvShmMux
Definition: shm.c:76
INT32 ShmDt(const VOID *shmaddr)
当对共享存储的操作已经结束时,则调用shmdt与该存储段分离 如果shmat成功执行,那么内核将使与该共享存储相关的shmid_ds结构中的shm_nattch计数器值减1
Definition: shm.c:824
STATIC UINT32 g_shmUsedPageCount
Definition: shm.c:164
STATIC VOID ShmSetSharedFlag(struct shmIDSource *seg)
给共享段中所有物理页框贴上共享标签
Definition: shm.c:215
INT32 ShmatParamCheck(const VOID *shmaddr, INT32 shmflg)
Definition: shm.c:562
STATIC INT32 ShmAllocSeg(key_t key, size_t size, INT32 shmflg)
为共享段分配物理内存 例如:参数size = 4097, LOS_Align(size, PAGE_SIZE) = 8192 分配页数 size >> PAGE_SHIFT = 2页
Definition: shm.c:251
INT32 ShmCtl(INT32 shmid, INT32 cmd, struct shmid_ds *buf)
ShmCtl 此函数可以对shmid指定的共享存储进行多种操作(删除、取信息、加锁、解锁等)
Definition: shm.c:703
VOID OsShmRegionFree(LosVmSpace *space, LosVmMapRegion *region)
释放共享线性区
Definition: shm.c:412
UINT32 ShmInit(VOID)
Definition: shm.c:166
STATIC VOID OsShmCmdUsage(VOID)
Definition: shm.c:930
UINT32 OsShellCmdShm(INT32 argc, const CHAR *argv[])
共享内存
Definition: shm.c:937
STATIC VOID ShmClearSharedFlag(struct shmIDSource *seg)
给共享段中所有物理页框撕掉共享标签
Definition: shm.c:224
STATIC struct shminfo g_shmInfo
Definition: shm.c:155
STATIC struct shmIDSource * ShmFindSeg(int shmid)
通过ID找到共享内存资源
Definition: shm.c:357
STATIC INT32 ShmSegValidCheck(INT32 segNum, size_t size, INT32 shmFlg)
共享内存段有效性检查
Definition: shm.c:341
SHELLCMD_ENTRY(shm_shellcmd, CMD_TYPE_SHOW, "shm", 2,(CmdCallBackFunc) OsShellCmdShm)
STATIC VOID ShmPagesRefDec(struct shmIDSource *seg)
seg下所有共享页引用减少
Definition: shm.c:233
VOID * ShmAt(INT32 shmid, const VOID *shmaddr, INT32 shmflg)
ShmAt 用来启动对该共享内存的访问,并把共享内存连接到当前进程的地址空间。
Definition: shm.c:634
STATIC VOID ShmVmmMapping(LosVmSpace *space, LOS_DL_LIST *pageList, VADDR_T vaddr, UINT32 regionFlags)
共享内存映射
Definition: shm.c:375
STATIC INT32 ShmSegUsedCount(VOID)
获取共享内存池中已被使用的段数量
Definition: shm.c:440
INT32 ShmGet(key_t key, size_t size, INT32 shmflg)
ShmGet 得到一个共享内存标识符或创建一个共享内存对象
Definition: shm.c:515
STATIC INT32 ShmPermCheck(struct shmIDSource *seg, mode_t mode)
对共享内存段权限检查
Definition: shm.c:455
Definition: los_mux.h:73
CHAR processName[OS_PCB_NAME_LEN]
LosVmSpace * vmSpace
UINT32 size
Definition: los_vm_map.h:85
VADDR_T base
Definition: los_vm_map.h:84
UINT32 regionFlags
Definition: los_vm_map.h:125
LosRbNode rbNode
Definition: los_vm_map.h:120
UINT32 shmid
Definition: los_vm_map.h:126
UINT8 forkFlags
Definition: los_vm_map.h:127
LosVmMapRange range
Definition: los_vm_map.h:123
物理页框描述符 虚拟内存体现的是程序对内存资源的需求,而物理内存是对该请求的供应。 伙伴算法的思想是:把内存中连续的空闲页框空间看成是空闲页框块,并按照它们的大小(连续页框的数目)分组
Definition: los_vm_page.h:53
Atomic refCounts
Definition: los_vm_page.h:57
虚拟空间,每个进程都有一个属于自己的虚拟内存地址空间
Definition: los_vm_map.h:146
LosRbTree regionRbTree
Definition: los_vm_map.h:148
LosMux regionMux
Definition: los_vm_map.h:149
LosArchMmu archMmu
Definition: los_vm_map.h:157
Definition: shm.c:113
gid_t cgid
Definition: shm.c:118
int __ipc_perm_seq
Definition: shm.c:120
key_t __ipc_perm_key
Definition: shm.c:114
long __pad2
Definition: shm.c:122
long __pad1
Definition: shm.c:121
mode_t mode
Definition: shm.c:119
uid_t cuid
Definition: shm.c:117
gid_t gid
Definition: shm.c:116
uid_t uid
Definition: shm.c:115
CHAR ownerName[OS_PCB_NAME_LEN]
Definition: shm.c:150
LOS_DL_LIST node
Definition: shm.c:148
struct shmid_ds ds
Definition: shm.c:146
UINT32 status
Definition: shm.c:147
Definition: shm.c:125
size_t shm_segsz
共享内存段的大小,单位为字节
Definition: shm.c:127
time_t shm_ctime
创建时间
Definition: shm.c:130
time_t shm_dtime
最后一个进程离开共享内存的时间
Definition: shm.c:129
unsigned long __pad1
Definition: shm.c:134
pid_t shm_lpid
最后操作共享内存的进程ID
Definition: shm.c:132
unsigned long shm_nattch
当前使用该共享内存段的进程数量
Definition: shm.c:133
struct ipc_perm shm_perm
操作许可,里面包含共享内存的用户ID、组ID等信息
Definition: shm.c:126
unsigned long __pad2
Definition: shm.c:135
time_t shm_atime
最后一个进程访问共享内存的时间
Definition: shm.c:128
pid_t shm_cpid
创建共享内存的进程ID
Definition: shm.c:131
Definition: shm.c:138
unsigned long shmmni
Definition: shm.c:139
unsigned long shmseg
Definition: shm.c:139
unsigned long shmmax
Definition: shm.c:139
unsigned long shmall
Definition: shm.c:139
unsigned long __unused[4]
Definition: shm.c:139
unsigned long shmmin
Definition: shm.c:139
ARG_NUM_3 int
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
time_t time(time_t *t)
Definition: time.c:1224
u32_t(* CmdCallBackFunc)(u32_t argc, const char **argv)
Definition: types_adapt.h:86
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