Kernel version:2.6.14
CPU architecture:ARM920T
在linux內核中主要有兩個函數涉及到文件描述符的分配:get_unused_fd和locate_fd。本文主要講解get_unused_fd,將會在下一篇文章中介紹locate_fd。首先給出get_unused_fd的定義(fs/open.c):
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 < 0)
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,該值定義如下:
# define RLIMIT_NOFILE 7 /* max number of open files */
在signal結構中,rlim是struct rlimit類型的數組,
struct signal_struct {
...
struct rlimit rlim[RLIM_NLIMITS];
...
};
struct rlimit定義如下
struct rlimit {
unsigned long rlim_cur;//當前值
unsigned long rlim_max;//最大值
};
這些值時是在哪設定的呢?我們應該知道,linux內核通過fork創建進程,第一個進程是靜態定義的。因此,如果進程創建後沒有修改這些值,那麼這些和第一個進程中的值應該是一樣的。下面是第一個進程的task_struct結構,僅列出部分數據。
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的定義如下:
#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個文件。