部落格:blog.focus-linux.net linuxfocus.blog.chinaunix.net
本文的copyleft歸[email protected]所有,使用GPL釋出,可以自由拷貝,轉載。但轉載請保持文檔的完整性,注明原作者及原連結,嚴禁用于任何商業用途。
======================================================================================================
繼續昨天的學習。
昨天學習alloc_fd時,還有一個函數expand_files沒有進入跟蹤。
int expand_files(struct files_struct *files, int nr)
{
struct fdtable *fdt;
fdt = files_fdtable(files);
/*
* N.B. For clone tasks sharing a files structure, this test
* will limit the total number of files that can be opened.
*/
/* 檢查是否超過目前程序限定的最大可打開檔案數 */
if (nr >= rlimit(RLIMIT_NOFILE))
return -EMFILE;
/* Do we need to expand? */
/*
如果nr小于max_fds,即目前的檔案表的個數已經超過了nr, 是以無需擴充。
這也說明,檔案表隻會增大,不會減小。
*/
if (nr fdt->max_fds)
return 0;
/* Can we expand? */
檢查是否超過了系統限定的最大可打開檔案數
注意前面的檢查為目前程序的打開檔案數,此處的檢查為系統可打開的檔案數——所有程序
if (nr >= sysctl_nr_open)
/* All good, so we try */
/* 真正去做expand*/
return expand_fdtable(files, nr);
}
進入expand_fdtable
static int expand_fdtable(struct files_struct *files, int nr)
__releases(files->file_lock)
__acquires(files->file_lock)
struct fdtable *new_fdt, *cur_fdt;
spin_unlock(&files->file_lock);
/* 申請新的檔案表 */
new_fdt = alloc_fdtable(nr);
spin_lock(&files->file_lock);
if (!new_fdt)
return -ENOMEM;
* extremely unlikely race - sysctl_nr_open decreased between the check in
* caller and alloc_fdtable(). Cheaper to catch it here...
/* 如注釋所示,由于競争,有可能在申請nr個數的新檔案表時,修改了sysctl_nr_open,導緻新的檔案表個數 小于我們所需要的。是以,這裡需要對new_fdt->max_fds和nr進行判斷。如果小于nr,那麼expand失敗 */
if (unlikely(new_fdt->max_fds = nr)) {
__free_fdtable(new_fdt);
}
* Check again since another task may have expanded the fd table while
* we dropped the lock
cur_fdt = files_fdtable(files);
/* 如注釋所示,有可能另外一個程序已經擴充了檔案表,是以這裡再次判斷 */
if (nr >= cur_fdt->max_fds) {
/* 複制檔案表 */
/* Continue as planned */
copy_fdtable(new_fdt, cur_fdt);
rcu_assign_pointer(files->fdt, new_fdt);
/*
對于檔案表結構struct files_struct,其成員變量fd_array為一個大小為NR_OPEN_DEFAULT的數 組。這是一種常用的技巧。一般來說,程序的打開的檔案不會太多,是以可以直接使用一個比較小的數組,這 樣可以提高效率避免二次配置設定,同時由于數組較小,并不會太浪費空間。當檔案個數超過數組大小的時候,再 重新申請記憶體。*/
if (cur_fdt->max_fds > NR_OPEN_DEFAULT)
free_fdtable(cur_fdt);
} else {
/* Somebody else expanded, so undo our attempt */
return 1;
expand_files結束之後,alloc_fd也學習完了,即宏get_unused_fd_flags也就結束了,那麼我們就再次回到了函數sock_alloc_file,繼續學習其調用的其它函數。