Kernel version:2.6.14
CPU architecture:ARM920T
Author:ce123(http://blog.csdn.net/ce123)
在linux内核中主要有两个函数涉及到文件描述符的分配:get_unused_fd和locate_fd。本文主要讲解get_unused_fd,将会在下一篇文章中介绍locate_fd。首先给出get_unused_fd的定义(fs/open.c):
[plain] view plain copy
print?
- int get_unused_fd(void)
- {
- struct files_struct * files = current->files;//获得当前进程的打开文件列表files
- int fd, error;
- struct fdtable *fdt;
-
- error = -EMFILE;
- spin_lock(&files->file_lock);
-
- repeat:
- fdt = files_fdtable(files);//获得文件描述符位图结构
- fd = find_next_zero_bit(fdt->open_fds->fds_bits,
- fdt->max_fdset,
- fdt->next_fd);
- //find_next_zero_bit函数在文件描述符位图fds_bits中从next_fd位开始搜索下一个(包括next_fd)为0的位,也就是分配一个文教描述符
- /*
- * N.B. For clone tasks sharing a files structure, this test
- * will limit the total number of files that can be opened.
- */
- if (fd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur)//检查是否超过当前进程限定的最大可打开文件数
- goto out;
-
- /* Do we need to expand the fd array or fd set? */
- error = expand_files(files, fd);//根据需要扩展fd,稍后我们会详细介绍该函数。返回值<0,错误;返回值>0,扩展后再次进行fd的分配
- if (error
- goto out;
-
- if (error) {
- /*
- * If we needed to expand the fs array we
- * might have blocked - try again.
- */
- error = -EMFILE;
- goto repeat;//之前进行了扩展操作,重新进行一次空闲fd的分配
- }
-
- FD_SET(fd, fdt->open_fds);//在open_fds的位图上置位
- FD_CLR(fd, fdt->close_on_exec);
- fdt->next_fd = fd + 1;//next_fd加1
- #if 1
- /* Sanity check */
- if (fdt->fd[fd] != NULL) {
- printk(KERN_WARNING "get_unused_fd: slot %d not NULL!\n", fd);
- fdt->fd[fd] = NULL;
- }
- #endif
- error = fd;
-
- out:
- spin_unlock(&files->file_lock);
- return error;
- }
current->signal->rlim[RLIMIT_NOFILE].rlim_cur是一个进程可以打开的最大文件数量。我们首先来看RLIMIT_NOFILE,该值定义如下:
[plain] view plain copy
print?
- # define RLIMIT_NOFILE 7 /* max number of open files */
在signal结构中,rlim是struct rlimit类型的数组,
[plain] view plain copy
print?
- struct signal_struct {
- ...
- struct rlimit rlim[RLIM_NLIMITS];
- ...
- };
struct rlimit定义如下
[plain] view plain copy
print?
- struct rlimit {
- unsigned long rlim_cur;//当前值
- unsigned long rlim_max;//最大值
- };
这些值时是在哪设定的呢?我们应该知道,linux内核通过fork创建进程,第一个进程是静态定义的。因此,如果进程创建后没有修改这些值,那么这些和第一个进程中的值应该是一样的。下面是第一个进程的task_struct结构,仅列出部分数据。
[plain] view plain copy
print?
- linux/arch/arm/kernel/init_task.c
-
- struct task_struct init_task = INIT_TASK(init_task);
-
- #define INIT_TASK(tsk) \
- { \
- ...
- .signal = &init_signals, \
- ...
- }
init_signals的定义如下:
[plain] view plain copy
print?
- #define INIT_SIGNALS(sig) { \
- .count = ATOMIC_INIT(1), \
- .wait_chldexit = __WAIT_QUEUE_HEAD_INITIALIZER(sig.wait_chldexit),\
- .shared_pending = { \
- .list = LIST_HEAD_INIT(sig.shared_pending.list), \
- .signal = {{0}}}, \
- .posix_timers = LIST_HEAD_INIT(sig.posix_timers), \
- .cpu_timers = INIT_CPU_TIMERS(sig.cpu_timers), \
- .rlim = INIT_RLIMITS, \
- }
-
- include\asm-generic\resource.h
- #define INIT_RLIMITS \
- { \
- [RLIMIT_CPU] = { RLIM_INFINITY, RLIM_INFINITY }, \
- [RLIMIT_FSIZE] = { RLIM_INFINITY, RLIM_INFINITY }, \
- [RLIMIT_DATA] = { RLIM_INFINITY, RLIM_INFINITY }, \
- [RLIMIT_STACK] = { _STK_LIM, _STK_LIM_MAX }, \
- [RLIMIT_CORE] = { 0, RLIM_INFINITY }, \
- [RLIMIT_RSS] = { RLIM_INFINITY, RLIM_INFINITY }, \
- [RLIMIT_NPROC] = { 0, 0 }, \
- [RLIMIT_NOFILE] = { INR_OPEN, INR_OPEN }, \
- [RLIMIT_MEMLOCK] = { MLOCK_LIMIT, MLOCK_LIMIT }, \
- [RLIMIT_AS] = { RLIM_INFINITY, RLIM_INFINITY }, \
- [RLIMIT_LOCKS] = { RLIM_INFINITY, RLIM_INFINITY }, \
- [RLIMIT_SIGPENDING] = { 0, 0 }, \
- [RLIMIT_MSGQUEUE] = { MQ_BYTES_MAX, MQ_BYTES_MAX }, \
- [RLIMIT_NICE] = { 0, 0 }, \
- [RLIMIT_RTPRIO] = { 0, 0 }, \
- }
-
- #define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */
- #define INR_OPEN 1024 /* Initial setting for nfile rlimits */
从上面的代码我们可以看到rlim_cur = 1024,也就是说进程最多可以打开1024个文件。
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』