更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
vfs_procfd.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 "fs/file.h"
33#include "los_process_pri.h"
34#include "fs/fd_table.h"
35#include "mqueue.h"
36#ifdef LOSCFG_NET_LWIP_SACK
37#include "lwip/sockets.h"
38#endif
39///对进程文件表操作上锁
40void FileTableLock(struct fd_table_s *fdt)
41{
42 /* Take the semaphore (perhaps waiting) */
43 while (sem_wait(&fdt->ft_sem) != 0) {
44 /*
45 * The only case that an error should occur here is if the wait was
46 * awakened by a signal.
47 */
48 LOS_ASSERT(errno == EINTR);
49 }
50}
51///对进程文件表操作解锁
52void FileTableUnLock(struct fd_table_s *fdt)
53{
54 int ret = sem_post(&fdt->ft_sem);
55 if (ret == -1) {
56 PRINTK("sem_post error, errno %d \n", get_errno());
57 }
58}
59///分配进程描述符
60static int AssignProcessFd(const struct fd_table_s *fdt, int minFd)
61{
62 if (minFd >= fdt->max_fds) {
63 set_errno(EINVAL);
64 return VFS_ERROR;
65 }
66 //从表中搜索未使用的 fd
67 /* search unused fd from table */
68 for (int i = minFd; i < fdt->max_fds; i++) {
69 if (!FD_ISSET(i, fdt->proc_fds)) {
70 return i;
71 }
72 }
73 set_errno(EMFILE);
74 return VFS_ERROR;
75}
76///获取进程文件描述符表
78{
79 struct fd_table_s *fdt = NULL;
80 struct files_struct *procFiles = OsCurrProcessGet()->files;//当前进程文件管理器
81
82 if (procFiles == NULL) {
83 return NULL;
84 }
85
86 fdt = procFiles->fdt;//进程文件表
87 if ((fdt == NULL) || (fdt->ft_fds == NULL)) {
88 return NULL;
89 }
90
91 return fdt;
92}
93
94static bool IsValidProcessFd(struct fd_table_s *fdt, int procFd)
95{
96 if (fdt == NULL) {
97 return false;
98 }
99 if ((procFd < 0) || (procFd >= fdt->max_fds)) {
100 return false;
101 }
102 return true;
103}
104///参数进程FD和参数系统FD进行绑定(关联)
105void AssociateSystemFd(int procFd, int sysFd)
106{
107 struct fd_table_s *fdt = GetFdTable();//获取当前进程FD表
108
109 if (!IsValidProcessFd(fdt, procFd)) {
110 return;
111 }
112
113 if (sysFd < 0) {
114 return;
115 }
116
117 FileTableLock(fdt);
118 fdt->ft_fds[procFd].sysFd = sysFd;//绑定
119 FileTableUnLock(fdt);
120}
121
122int CheckProcessFd(int procFd)
123{
124 struct fd_table_s *fdt = GetFdTable();
125
126 if (!IsValidProcessFd(fdt, procFd)) {
127 return VFS_ERROR;
128 }
129
130 return OK;
131}
132///获取绑定的系统描述符
134{
135 struct fd_table_s *fdt = GetFdTable();//获取当前进程FD表
136
137 if (!IsValidProcessFd(fdt, procFd)) {
138 return VFS_ERROR;
139 }
140
141 FileTableLock(fdt);//锁表
142 if (fdt->ft_fds[procFd].sysFd < 0) {
143 FileTableUnLock(fdt);
144 return VFS_ERROR;
145 }
146 int sysFd = fdt->ft_fds[procFd].sysFd;//进程FD捆绑系统FD
147 FileTableUnLock(fdt);//解锁表
148
149 return sysFd;
150}
151
152/* Occupy the procFd, there are three circumstances:
153 * 1.procFd is already associated, we need disassociate procFd with relevant sysfd.
154 * 2.procFd is not allocated, we occupy it immediately.
155 * 3.procFd is in open(), close(), dup() process, we return EBUSY immediately.
156 */
157/* 占用procFd,有三种情况:
158* 1.procFd 已经关联,我们需要将 procFd 与相关的 sysfd 解除关联。
159* 2.procFd 未分配,我们立即占用。
160* 3.procFd在open()、close()、dup()过程中,我们立即返回EBUSY。
161*/
162int AllocSpecifiedProcessFd(int procFd)//分配指定的进程Fd
163{
164 struct fd_table_s *fdt = GetFdTable();//获取进程FD表
165
166 if (!IsValidProcessFd(fdt, procFd)) {
167 return -EBADF;
168 }
169
170 FileTableLock(fdt);
171 if (fdt->ft_fds[procFd].sysFd >= 0) {//第一种情况
172 /* Disassociate procFd */
173 fdt->ft_fds[procFd].sysFd = -1;//解除关联
174 FileTableUnLock(fdt);
175 return OK;
176 }
177
178 if (FD_ISSET(procFd, fdt->proc_fds)) {//还在使用中
179 /* procFd in race condition */
180 FileTableUnLock(fdt);
181 return -EBUSY;
182 } else {//未分配情况
183 /* Unused procFd */
184 FD_SET(procFd, fdt->proc_fds);//立即占用
185 }
186
187 FileTableUnLock(fdt);
188 return OK;
189}
190///释放进程文件描述符
191void FreeProcessFd(int procFd)
192{
193 struct fd_table_s *fdt = GetFdTable();
194
195 if (!IsValidProcessFd(fdt, procFd)) {
196 return;
197 }
198
199 FileTableLock(fdt);
200 FD_CLR(procFd, fdt->proc_fds); //相应位清0
201 FD_CLR(procFd, fdt->cloexec_fds);
202 fdt->ft_fds[procFd].sysFd = -1; //解绑系统文件描述符
203 FileTableUnLock(fdt);
204}
205///解绑系统文件描述符,返回系统文件描述符
207{
208 struct fd_table_s *fdt = GetFdTable();
209
210 if (!IsValidProcessFd(fdt, procFd)) {
211 return VFS_ERROR;
212 }
213
214 FileTableLock(fdt);
215 if (fdt->ft_fds[procFd].sysFd < 0) {//无系统文件描述符
216 FileTableUnLock(fdt);
217 return VFS_ERROR;//解绑失败
218 }
219 int sysFd = fdt->ft_fds[procFd].sysFd;//存在绑定关系
220 if (procFd >= MIN_START_FD) {//必须大于2
221 fdt->ft_fds[procFd].sysFd = -1;//解绑
222 }
223 FileTableUnLock(fdt);
224
225 return sysFd;
226}
227///分配文件描述符
229{
230 return AllocLowestProcessFd(MIN_START_FD);
231}
232///分配文件描述符,从3号开始
234{
235 struct fd_table_s *fdt = GetFdTable();
236
237 if (fdt == NULL) {
238 return VFS_ERROR;
239 }
240 //minFd 应该是一个正数,并且 0,1,2 已经分配给 stdin,stdout,stderr
241 /* minFd should be a positive number,and 0,1,2 had be distributed to stdin,stdout,stderr */
242 if (minFd < MIN_START_FD) {
243 minFd = MIN_START_FD;
244 }
245
246 FileTableLock(fdt);
247
248 int procFd = AssignProcessFd(fdt, minFd);
249 if (procFd == VFS_ERROR) {
250 FileTableUnLock(fdt);
251 return VFS_ERROR;
252 }
253
254 /* occupy the fd set */
255 FD_SET(procFd, fdt->proc_fds);//占用该进程文件描述符
256 FileTableUnLock(fdt);
257
258 return procFd;
259}
260///分配和绑定进程描述符
261int AllocAndAssocProcessFd(int sysFd, int minFd)
262{
263 struct fd_table_s *fdt = GetFdTable();
264
265 if (fdt == NULL) {
266 return VFS_ERROR;
267 }
268
269 /* minFd should be a positive number,and 0,1,2 had be distributed to stdin,stdout,stderr */
270 if (minFd < MIN_START_FD) {
271 minFd = MIN_START_FD;
272 }
273
274 FileTableLock(fdt);
275
276 int procFd = AssignProcessFd(fdt, minFd);
277 if (procFd == VFS_ERROR) {
278 FileTableUnLock(fdt);
279 return VFS_ERROR;
280 }
281
282 /* occupy the fd set */
283 FD_SET(procFd, fdt->proc_fds);
284 fdt->ft_fds[procFd].sysFd = sysFd;
285 FileTableUnLock(fdt);
286
287 return procFd;
288}
289///分配和绑定系统描述符
290int AllocAndAssocSystemFd(int procFd, int minFd)
291{
292 struct fd_table_s *fdt = GetFdTable();//获取当前进程文件表
293
294 if (!IsValidProcessFd(fdt, procFd)) {
295 return VFS_ERROR;
296 }
297
298 int sysFd = alloc_fd(minFd);//1.分配一个系统描述符,从全局文件描述符 tg_filelist 表中分配
299 if (sysFd < 0) {
300 return VFS_ERROR;
301 }
302
303 FileTableLock(fdt);
304 fdt->ft_fds[procFd].sysFd = sysFd;//2.将进程描述符和系统描述符绑定
305 FileTableUnLock(fdt);
306
307 return sysFd;
308}
309///进程FD引用数改变
310static void FdRefer(int sysFd)
311{
312 if ((sysFd > STDERR_FILENO) && (sysFd < CONFIG_NFILE_DESCRIPTORS)) {
313 files_refer(sysFd);//增加系统FD引用次数
314 }
315#if defined(LOSCFG_NET_LWIP_SACK)
316 if ((sysFd >= CONFIG_NFILE_DESCRIPTORS) && (sysFd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS))) {
317 socks_refer(sysFd);//增加socket引用次数
318 }
319#endif
320#if defined(LOSCFG_COMPAT_POSIX)
321 if ((sysFd >= MQUEUE_FD_OFFSET) && (sysFd < (MQUEUE_FD_OFFSET + CONFIG_NQUEUE_DESCRIPTORS))) {
322 MqueueRefer(sysFd);
323 }
324#endif
325}
326///关闭FD
327static void FdClose(int sysFd, unsigned int targetPid)
328{
329 UINT32 intSave;
330
331 if ((sysFd > STDERR_FILENO) && (sysFd < CONFIG_NFILE_DESCRIPTORS)) {
332 LosProcessCB *processCB = OS_PCB_FROM_PID(targetPid);//获取目标进程
333 SCHEDULER_LOCK(intSave);
334 if (OsProcessIsInactive(processCB)) {
335 SCHEDULER_UNLOCK(intSave);
336 return;
337 }
338 SCHEDULER_UNLOCK(intSave);
339
340 files_close_internal(sysFd, processCB);//减少文件引用数(进程和系统的两个引用数)
341 }
342#if defined(LOSCFG_NET_LWIP_SACK)
343 if ((sysFd >= CONFIG_NFILE_DESCRIPTORS) && (sysFd < (CONFIG_NFILE_DESCRIPTORS + CONFIG_NSOCKET_DESCRIPTORS))) {
344 socks_close(sysFd);//减少sockert引用数
345 }
346#endif
347#if defined(LOSCFG_COMPAT_POSIX)
348 if ((sysFd >= MQUEUE_FD_OFFSET) && (sysFd < (MQUEUE_FD_OFFSET + CONFIG_NQUEUE_DESCRIPTORS))) {
349 mq_close((mqd_t)sysFd);//减少mqpersonal引用数
350 }
351#endif
352}
353///获取参数进程FD表
354static struct fd_table_s *GetProcessFTable(unsigned int pid, sem_t *semId)
355{
356 UINT32 intSave;
357 struct files_struct *procFiles = NULL;
358 LosProcessCB *processCB = OS_PCB_FROM_PID(pid);
359
360 SCHEDULER_LOCK(intSave);
361 if (OsProcessIsInactive(processCB)) {//参数进程必须处于激活状态
362 SCHEDULER_UNLOCK(intSave);
363 return NULL;
364 }
365
366 procFiles = processCB->files;
367 if (procFiles == NULL || procFiles->fdt == NULL) {
368 SCHEDULER_UNLOCK(intSave);
369 return NULL;
370 }
371
372 *semId = procFiles->fdt->ft_sem;
373 SCHEDULER_UNLOCK(intSave);
374
375 return procFiles->fdt;
376}
377///拷贝一个进程FD给指定的进程,使两个进程的FD都指向同一个系统FD
378int CopyFdToProc(int fd, unsigned int targetPid)
379{
380#if !defined(LOSCFG_NET_LWIP_SACK) && !defined(LOSCFG_COMPAT_POSIX) && !defined(LOSCFG_FS_VFS)
381 return -ENOSYS;
382#else
383 int sysFd;
384 struct fd_table_s *fdt = NULL;
385 int procFd;
386 sem_t semId;
387
388 if (OS_PID_CHECK_INVALID(targetPid)) {
389 return -EINVAL;
390 }
391
392 sysFd = GetAssociatedSystemFd(fd);//找到当前进程FD绑定的系统FD
393 if (sysFd < 0) {
394 return -EBADF;
395 }
396
397 FdRefer(sysFd);//引用数要增加了.
398 fdt = GetProcessFTable(targetPid, &semId);//获取目标进程的FD表
399 if (fdt == NULL || fdt->ft_fds == NULL) {
400 FdClose(sysFd, targetPid);
401 return -EPERM;
402 }
403
404 /* Take the semaphore (perhaps waiting) */
405 if (sem_wait(&semId) != 0) {
406 /* Target process changed */
407 FdClose(sysFd, targetPid);
408 return -ESRCH;
409 }
410
411 procFd = AssignProcessFd(fdt, 3);//从目标进程FD表中分配一个FD出来,注意这个FD编号不一定和当前进程的编号相同,但他们都将绑定在同一个系统FD上
412 if (procFd < 0) {
413 if (sem_post(&semId) == -1) {
414 PRINT_ERR("sem_post error, errno %d \n", get_errno());
415 }
416 FdClose(sysFd, targetPid);
417 return -EPERM;
418 }
419
420 /* occupy the fd set */
421 FD_SET(procFd, fdt->proc_fds);//申请到了等啥呀,赶紧占用这个FD
422 fdt->ft_fds[procFd].sysFd = sysFd;//绑定,这句话代表的意思是有两个进程的FD都帮到同一个系统FD上
423 if (sem_post(&semId) == -1) {
424 PRINTK("sem_post error, errno %d \n", get_errno());
425 }
426
427 return procFd;
428#endif
429}
430///关闭进程FD
431int CloseProcFd(int procFd, unsigned int targetPid)
432{
433#if !defined(LOSCFG_NET_LWIP_SACK) && !defined(LOSCFG_COMPAT_POSIX) && !defined(LOSCFG_FS_VFS)
434 return -ENOSYS;
435#else
436 int sysFd;
437 struct fd_table_s *fdt = NULL;
438 sem_t semId;
439
440 if (OS_PID_CHECK_INVALID(targetPid)) {
441 return -EINVAL;
442 }
443
444 fdt = GetProcessFTable(targetPid, &semId);//获取进程文件描述表
445 if (fdt == NULL || fdt->ft_fds == NULL) {
446 return -EPERM;
447 }
448
449 /* Take the semaphore (perhaps waiting) */
450 if (sem_wait(&semId) != 0) {
451 /* Target process changed */
452 return -ESRCH;
453 }
454
455 if (!IsValidProcessFd(fdt, procFd)) {
456 if (sem_post(&semId) == -1) {
457 PRINTK("sem_post error, errno %d \n", get_errno());
458 }
459 return -EPERM;
460 }
461
462 sysFd = fdt->ft_fds[procFd].sysFd;//获取参数进程描述符绑定的系统文件描述符
463 if (sysFd < 0) {
464 if (sem_post(&semId) == -1) {
465 PRINTK("sem_post error, errno %d \n", get_errno());
466 }
467 return -EPERM;
468 }
469
470 /* clean the fd set */
471 FD_CLR(procFd, fdt->proc_fds);//进程FD重置
472 FD_CLR(procFd, fdt->cloexec_fds);
473 fdt->ft_fds[procFd].sysFd = -1;//解绑
474 if (sem_post(&semId) == -1) {
475 PRINTK("sem_post error, errno %d \n", get_errno());
476 }
477 FdClose(sysFd, targetPid);//注意这个操作只是让对应的引用数量减少
478
479 return 0;
480#endif
481}
int alloc_fd(int minfd)
分配一个系统fd,从全局tg_filelist中拿sysFd
int files_close_internal(int fd, LosProcessCB *processCB)
void files_refer(int fd)
int mq_close(mqd_t personal)
Definition: mqueue.c:550
UINTPTR mqd_t
Definition: mqueue.h:127
STATIC INLINE BOOL OsProcessIsInactive(const LosProcessCB *processCB)
进程不活跃函数定义:身上贴有不使用且不活跃标签的进程
STATIC INLINE LosProcessCB * OsCurrProcessGet(VOID)
unsigned int UINT32
Definition: los_typedef.h:57
void MqueueRefer(int sysFd)
Definition: mqueue.c:339
int sem_post(sem_t *sem)
增加信号量计数
Definition: semaphore.c:139
int sem_wait(sem_t *sem)
获取信号量
Definition: semaphore.c:77
int socks_close(int sockfd)
Definition: sockets.c:1631
void socks_refer(int sockfd)
Definition: sockets.c:1612
struct files_struct * files
进程fd表结构体
Definition: fd_table.h:84
struct file_table_s * ft_fds
Definition: fd_table.h:86
unsigned int max_fds
进程的文件描述符最多有256个
Definition: fd_table.h:85
fd_set * proc_fds
进程fd管理位,用bitmap管理FD使用情况,默认打开了 0,1,2 (stdin,stdout,stderr)
Definition: fd_table.h:87
fd_set * cloexec_fds
Definition: fd_table.h:88
sem_t ft_sem
Definition: fd_table.h:89
intptr_t sysFd
Definition: fd_table.h:81
struct fd_table_s * fdt
持有的文件表
Definition: fd_table.h:95
static void FdRefer(int sysFd)
进程FD引用数改变
Definition: vfs_procfd.c:310
int AllocAndAssocProcessFd(int sysFd, int minFd)
分配和绑定进程描述符
Definition: vfs_procfd.c:261
int CheckProcessFd(int procFd)
Definition: vfs_procfd.c:122
struct fd_table_s * GetFdTable(void)
获取进程文件描述符表
Definition: vfs_procfd.c:77
int AllocLowestProcessFd(int minFd)
分配文件描述符,从3号开始
Definition: vfs_procfd.c:233
void FileTableLock(struct fd_table_s *fdt)
对进程文件表操作上锁
Definition: vfs_procfd.c:40
void AssociateSystemFd(int procFd, int sysFd)
参数进程FD和参数系统FD进行绑定(关联)
Definition: vfs_procfd.c:105
void FreeProcessFd(int procFd)
释放进程文件描述符
Definition: vfs_procfd.c:191
int DisassociateProcessFd(int procFd)
解绑系统文件描述符,返回系统文件描述符
Definition: vfs_procfd.c:206
static struct fd_table_s * GetProcessFTable(unsigned int pid, sem_t *semId)
获取参数进程FD表
Definition: vfs_procfd.c:354
static void FdClose(int sysFd, unsigned int targetPid)
关闭FD
Definition: vfs_procfd.c:327
int AllocAndAssocSystemFd(int procFd, int minFd)
分配和绑定系统描述符
Definition: vfs_procfd.c:290
static int AssignProcessFd(const struct fd_table_s *fdt, int minFd)
分配进程描述符
Definition: vfs_procfd.c:60
int CopyFdToProc(int fd, unsigned int targetPid)
拷贝一个进程FD给指定的进程,使两个进程的FD都指向同一个系统FD
Definition: vfs_procfd.c:378
int AllocProcessFd(void)
分配文件描述符
Definition: vfs_procfd.c:228
int AllocSpecifiedProcessFd(int procFd)
Definition: vfs_procfd.c:162
int GetAssociatedSystemFd(int procFd)
获取绑定的系统描述符
Definition: vfs_procfd.c:133
int CloseProcFd(int procFd, unsigned int targetPid)
关闭进程FD
Definition: vfs_procfd.c:431
void FileTableUnLock(struct fd_table_s *fdt)
对进程文件表操作解锁
Definition: vfs_procfd.c:52
static bool IsValidProcessFd(struct fd_table_s *fdt, int procFd)
Definition: vfs_procfd.c:94