文件描述符存储在进程内存中的位置?

时间:2022-03-28 02:50:03

When a function A is called from a point of execution, internally it is a JMP statement to the address pointing to function A. So the current point of execution is saved onto the stack, the PC loads the address of the called function A and continues.

当从执行点调用函数a时,在内部它是指向函数a的地址的JMP语句,因此当前的执行点被保存到堆栈中,PC装载被调用函数a的地址并继续。

To get back to the point of execution after the function call, the function block should have equal push and pops onto the stack. Normally in C on exiting the function, the stack variables defined are destroyed(which I presume means popped off the stack), but I decided to define a file descriptor variable inside my function. The code is below:

要在函数调用之后回到执行点,函数块应该具有相等的push和pop到堆栈上。通常在退出函数的C中,所定义的堆栈变量会被销毁(我假定这意味着从堆栈中弹出),但我决定在函数中定义一个文件描述符变量。下面的代码是:

void main() {
    printf("In the beginning there was main()\n");
    func_call();
    printf("func_call complete\n");
    while(1);
}

void func_call() {
    int fp;
    //Opening a file to get handle to it.
    fp = open("stack_flush.c", O_RDONLY);
    if (fp < 0 ) {
        perror("fp could not open stack_flush.c");
        return;
    }
}

On running this program and checking lsof, I can see that the fd is still open upon exiting the function func_call().

在运行这个程序并检查lsof时,我可以看到fd在退出函数func_call()时仍然是打开的。

stack_flu 3791 vvdnlt260    0u   CHR  136,1      0t0        4 /dev/pts/1
stack_flu 3791 vvdnlt260    1u   CHR  136,1      0t0        4 /dev/pts/1
stack_flu 3791 vvdnlt260    2u   CHR  136,1      0t0        4 /dev/pts/1
stack_flu 3791 vvdnlt260    3r   REG    8,3      526 24660187 /home/vvdnlt260/Nishanth/test_space/stack_flush.c

I checked the wikipedia entry for file descriptors and I found this:

我查看了*的文件描述符条目,发现:

To perform input or output, the process passes the file descriptor to the kernel through a system call, and the kernel will access the file on behalf of the process. The process does not have direct access to the file or inode tables.

为了执行输入或输出,进程通过系统调用将文件描述符传递给内核,内核将代表进程访问文件。进程没有直接访问文件或inode表的权限。

From the above statement it's obvious that the file descriptor integer value is stored in process memory, but although it was defined in a function, the file descriptor was not local to the function as it did not get removed on function exit.

从上面的语句中可以看出,文件描述符整数值存储在进程内存中,但是尽管它是在函数中定义的,但是文件描述符并不是函数的局部变量,因为它在函数退出时没有被删除。

So my question is 2 fold:

我的问题有两个方面:

1) If the file descriptor is part of the func_call() stack, then how does the code return to its pre function call execution point although it has not been popped off? Also in this case why does it persist after the function call exists?

1)如果文件描述符是function_call()堆栈的一部分,那么代码如何返回到它的pre函数调用执行点,尽管它还没有被弹出?同样,在这种情况下,为什么函数调用存在后它仍然存在?

2) If not part of the func_call() stack where does the file descriptor reside in the process memory?

2)如果函数调用()堆栈中没有文件描述符,那么文件描述符位于进程内存中的什么位置?

3 个解决方案

#1


2  

The variable int fd; is only visible from the function func_call() and after this function finishes executing it will be popped of the stack and the memory will be overwritten probably when a new function is entered. The fact that you destroy some int value pointing to the file does not mean that you close said file. What if you did something like:

变量int fd;仅从函数func_call()中可见,在该函数执行完毕后,它将被堆栈弹出,并且可能在输入新函数时重写内存。销毁指向文件的int值并不意味着关闭该文件。如果你做了这样的事情:

int global_fd;
void foo() {
    int local_fd = open("bar.txt", O_RDONLY);
    global_fd = local_fd;
}

And called foo()? Would You expect to not be able to use global_fd anymore afteer foo exits?

和调用foo()?您是否期望在foo出口之后不能再使用global_fd ?

It is helpful to think in this case of the file descriptor as a of a pointer, You ask the kernel to give You the file, and it gives you a value that You can use as a token for this specific file, this token is what you use to let the kernel know on which file should the function like read or lseek act. When the token is passed around or destroyed the file remains open just as destroying the pointer does not free the allocated memory.

认为在这种情况下是有帮助的文件描述符的指针,你问内核给你文件,和它给你一个值,您可以使用为这个特定的文件作为一个令牌,这令牌是你用来告诉内核文件应该像阅读或lseek的行动。当令牌被传递或销毁时,文件仍然打开,就像销毁指针不会释放分配的内存一样。

#2


1  

When you open a file there's a table in the kernel where descriptor of files are stored. So, when you opened your file, you created an entry in that table. If you don't close the file (with its descriptor) the entry is never deleted (it doesn't mean you cannot open the file again).

打开文件时,内核中有一个表,其中存储文件的描述符。因此,打开文件时,在该表中创建了一个条目。如果不关闭文件(及其描述符),则永远不会删除条目(这并不意味着不能再次打开该文件)。

If the file descriptor is part of the func_call() stack, then how does the code return to its pre function call execution point although it has not been popped off? Also in this case why does it persist after the function call exists?

如果文件描述符是function_call()堆栈的一部分,那么代码如何返回到它的pre函数调用执行点,尽管它还没有被弹出?同样,在这种情况下,为什么函数调用存在后它仍然存在?

As far as I know, there's only one stack per process, not per function. So the fp variable is stored at the stack of the process and it's deleted from there when the function ends.

就我所知,每个进程只有一个堆栈,而不是每个函数。所以fp变量被存储在进程的堆栈中,当函数结束时,它被从堆栈中删除。

#3


0  

File descriptors are special. As you know, they're just ints. But they "contain" a fair amount of information about the file being read (the location of the file on disk, the position within the fie of the read/write pointer, etc.), so where is that information stored? The answer is that it's stored somewhere in the OS kernel. It's stored in the OS kernel because its the kernel's job to manage file I/O for you. When we say that the int referring to the open file is a "file descriptor" we mean that the int is referring to information stored somewhere else, sort of like a pointer. That word "descriptor" is important. Another word that's sometimes used for this sort of situation is "handle".

文件描述符是特别的。如你所知,他们只是小酒馆。但是它们“包含”了大量关于正在读取的文件的信息(磁盘上文件的位置、读/写指针的5个位置等等),那么存储的信息在哪里呢?答案是它存储在OS内核的某个地方。它存储在OS内核中,因为为您管理文件I/O是内核的工作。当我们说int表示打开的文件是一个“文件描述符”时,我们的意思是int表示存储在其他地方的信息,有点像一个指针。描述符这个词很重要。另一个有时用于这种情况的词是“句柄”。

As you know, the memory for local variables is generally stored on the stack. When you return from a function, releasing the memory for the function's local variables is very simple -- they basically disappear along with the function's stack frame. And when they disappear, they do just disappear: there's no way (in C) to have some action associated with their disappearing. In particular, there's no way to have the effect of a call to close() for variables that happen to be file descriptors.

如您所知,本地变量的内存通常存储在堆栈中。当您从函数返回时,释放函数局部变量的内存是非常简单的——它们基本上随函数的堆栈帧一起消失。当它们消失时,它们就会消失:(在C语言中)不可能有与它们消失相关的动作。特别是,对于碰巧是文件描述符的变量,不可能调用close()。

(If you want to have a cleanup action take place when a variable disappears, one way is to use C++, and use a class variable, and define an explicit destructor.)

(如果希望在变量消失时执行清理操作,一种方法是使用c++,使用类变量,并定义显式析构函数。)

A similar situation arises when you call malloc. In this function:

当您调用malloc时,也会出现类似的情况。在这个函数:

void f()
{
    char *p = malloc(10);
}

we call malloc to allocate 10 bytes of memory and store the returned pointer in a local pointer variable p, which disappears when function f returns. So we lose the pointer to the allocated memory, but there's no call to free(), so the memory remains allocated. (This is an example of a memory leak.)

我们调用malloc来分配10字节的内存,并将返回的指针存储在本地指针变量p中,当函数f返回时,该变量将消失。因此我们丢失了指向已分配内存的指针,但是没有调用free(),因此内存仍然被分配。(这是一个内存泄漏的例子。)

#1


2  

The variable int fd; is only visible from the function func_call() and after this function finishes executing it will be popped of the stack and the memory will be overwritten probably when a new function is entered. The fact that you destroy some int value pointing to the file does not mean that you close said file. What if you did something like:

变量int fd;仅从函数func_call()中可见,在该函数执行完毕后,它将被堆栈弹出,并且可能在输入新函数时重写内存。销毁指向文件的int值并不意味着关闭该文件。如果你做了这样的事情:

int global_fd;
void foo() {
    int local_fd = open("bar.txt", O_RDONLY);
    global_fd = local_fd;
}

And called foo()? Would You expect to not be able to use global_fd anymore afteer foo exits?

和调用foo()?您是否期望在foo出口之后不能再使用global_fd ?

It is helpful to think in this case of the file descriptor as a of a pointer, You ask the kernel to give You the file, and it gives you a value that You can use as a token for this specific file, this token is what you use to let the kernel know on which file should the function like read or lseek act. When the token is passed around or destroyed the file remains open just as destroying the pointer does not free the allocated memory.

认为在这种情况下是有帮助的文件描述符的指针,你问内核给你文件,和它给你一个值,您可以使用为这个特定的文件作为一个令牌,这令牌是你用来告诉内核文件应该像阅读或lseek的行动。当令牌被传递或销毁时,文件仍然打开,就像销毁指针不会释放分配的内存一样。

#2


1  

When you open a file there's a table in the kernel where descriptor of files are stored. So, when you opened your file, you created an entry in that table. If you don't close the file (with its descriptor) the entry is never deleted (it doesn't mean you cannot open the file again).

打开文件时,内核中有一个表,其中存储文件的描述符。因此,打开文件时,在该表中创建了一个条目。如果不关闭文件(及其描述符),则永远不会删除条目(这并不意味着不能再次打开该文件)。

If the file descriptor is part of the func_call() stack, then how does the code return to its pre function call execution point although it has not been popped off? Also in this case why does it persist after the function call exists?

如果文件描述符是function_call()堆栈的一部分,那么代码如何返回到它的pre函数调用执行点,尽管它还没有被弹出?同样,在这种情况下,为什么函数调用存在后它仍然存在?

As far as I know, there's only one stack per process, not per function. So the fp variable is stored at the stack of the process and it's deleted from there when the function ends.

就我所知,每个进程只有一个堆栈,而不是每个函数。所以fp变量被存储在进程的堆栈中,当函数结束时,它被从堆栈中删除。

#3


0  

File descriptors are special. As you know, they're just ints. But they "contain" a fair amount of information about the file being read (the location of the file on disk, the position within the fie of the read/write pointer, etc.), so where is that information stored? The answer is that it's stored somewhere in the OS kernel. It's stored in the OS kernel because its the kernel's job to manage file I/O for you. When we say that the int referring to the open file is a "file descriptor" we mean that the int is referring to information stored somewhere else, sort of like a pointer. That word "descriptor" is important. Another word that's sometimes used for this sort of situation is "handle".

文件描述符是特别的。如你所知,他们只是小酒馆。但是它们“包含”了大量关于正在读取的文件的信息(磁盘上文件的位置、读/写指针的5个位置等等),那么存储的信息在哪里呢?答案是它存储在OS内核的某个地方。它存储在OS内核中,因为为您管理文件I/O是内核的工作。当我们说int表示打开的文件是一个“文件描述符”时,我们的意思是int表示存储在其他地方的信息,有点像一个指针。描述符这个词很重要。另一个有时用于这种情况的词是“句柄”。

As you know, the memory for local variables is generally stored on the stack. When you return from a function, releasing the memory for the function's local variables is very simple -- they basically disappear along with the function's stack frame. And when they disappear, they do just disappear: there's no way (in C) to have some action associated with their disappearing. In particular, there's no way to have the effect of a call to close() for variables that happen to be file descriptors.

如您所知,本地变量的内存通常存储在堆栈中。当您从函数返回时,释放函数局部变量的内存是非常简单的——它们基本上随函数的堆栈帧一起消失。当它们消失时,它们就会消失:(在C语言中)不可能有与它们消失相关的动作。特别是,对于碰巧是文件描述符的变量,不可能调用close()。

(If you want to have a cleanup action take place when a variable disappears, one way is to use C++, and use a class variable, and define an explicit destructor.)

(如果希望在变量消失时执行清理操作,一种方法是使用c++,使用类变量,并定义显式析构函数。)

A similar situation arises when you call malloc. In this function:

当您调用malloc时,也会出现类似的情况。在这个函数:

void f()
{
    char *p = malloc(10);
}

we call malloc to allocate 10 bytes of memory and store the returned pointer in a local pointer variable p, which disappears when function f returns. So we lose the pointer to the allocated memory, but there's no call to free(), so the memory remains allocated. (This is an example of a memory leak.)

我们调用malloc来分配10字节的内存,并将返回的指针存储在本地指针变量p中,当函数f返回时,该变量将消失。因此我们丢失了指向已分配内存的指针,但是没有调用free(),因此内存仍然被分配。(这是一个内存泄漏的例子。)