歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux內核

Linux內核中的文件描述符(四)--fd的分配--get_unused_fd

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個文件。

Copyright © Linux教程網 All Rights Reserved