您的位置:首页 > 运维架构 > Linux

对比windows和linux的对父进程的文件描述符继承的设置

2016-01-11 19:24 701 查看
需要实现一个fopen中的子进程是否继承父进程的文件句柄的功能。

由于在多平台上,所以需要考虑windows和Linux及类Unix系统。

Linux实现的阻碍:

Linux中是默认子进程能够继承fd的。

1.由于需要在fopen函数中实现,但是看了下关于O_CLOEXEC属性(since Linux 2.6.23)是在open函数中的。

其含义就是在获取新的文件描述符时,使能close-on-exec flag,即使得在调用exec函数集时主动预先关闭父进程的文件描述符。

这在open中是一个Flag,也就是说是一个int型值。

2.正由于open中是一个int型值,而其他的文件属性相关的大部分在fopen都是rw等以char*形式提供的mode。所以出现了不好统一的的情况。

汇集一点:open中提供了对应的int型的flag,但是我们要打开的是文件需要调用fopen,fopen又没有提供int型的设置参数,只有字符串类型的mode作为设置参数。

解决办法:

还是查资料,发现了在glibc中,fopen已经提供了类似的参数在mode中,以字符'e'表示O_CLOEXEC
flag。但是这里有一个限制,就是必须要是glibc 2.7版本以后才会有这种解析。如果是之前的版本,就只好先用open接口加上O_CLOEXEC的flag做为参数获取到fd,然后再利用fdopen,来进行mode的设置。

windows的实现阻碍:

windows中是默认子进程能够不能继承fd的,因为要提前设置好条件。

其实关键在于,这个实现的有没有意义。因为下面的资料上也有提及,如果要继承父进程的句柄,则需要有两步

1.在创建获取句柄(类似于文件描述符)的时候,就要明确在属性中设置是可以用于子进程继承的。

2.在创建子子进程时,是否允许继承的参数就要设置成true,否则仍然不能继承。

摘自:http://man7.org/linux/man-pages/man3/fopen.3.htm


NAME top

fopen, fdopen, freopen - stream open functions


SYNOPSIS top

#include <stdio.h>

FILE *fopen(const char *path, const char *mode);

FILE *fdopen(int fd, const char *mode);

FILE *freopen(const char *path, const char *mode, FILE *stream);

Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

fdopen(): _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE


DESCRIPTION top

The fopen() function opens the file whose name is the string pointed
to by path and associates a stream with it.

The argument mode points to a string beginning with one of the
following sequences (possibly followed by additional characters, as
described below):

r      Open text file for reading.  The stream is positioned at the
beginning of the file.

r+     Open for reading and writing.  The stream is positioned at the
beginning of the file.

w      Truncate file to zero length or create text file for writing.
The stream is positioned at the beginning of the file.

w+     Open for reading and writing.  The file is created if it does
not exist, otherwise it is truncated.  The stream is
positioned at the beginning of the file.

a      Open for appending (writing at end of file).  The file is
created if it does not exist.  The stream is positioned at the
end of the file.

a+     Open for reading and appending (writing at end of file).  The
file is created if it does not exist.  The initial file
position for reading is at the beginning of the file, but
output is always appended to the end of the file.

The mode string can also include the letter 'b' either as a last
character or as a character between the characters in any of the two-
character strings described above.  This is strictly for
compatibility with C89 and has no effect; the 'b' is ignored on all
POSIX conforming systems, including Linux.  (Other systems may treat
text files and binary files differently, and adding the 'b' may be a
good idea if you do I/O to a binary file and expect that your program
may be ported to non-UNIX environments.)

See NOTES below for details of glibc extensions for mode.

Any created files will have mode S_IRUSR | S_IWUSR | S_IRGRP |
S_IWGRP | S_IROTH | S_IWOTH (0666), as modified by the process's
umask value (see umask(2)).

Reads and writes may be intermixed on read/write streams in any
order.  Note that ANSI C requires that a file positioning function
intervene between output and input, unless an input operation
encounters end-of-file.  (If this condition is not met, then a read
is allowed to return the result of writes other than the most
recent.)  Therefore it is good practice (and indeed sometimes
necessary under Linux) to put an fseek(3) or fgetpos(3) operation
between write and read operations on such a stream.  This operation
may be an apparent no-op (as in fseek(..., 0L, SEEK_CUR) called for
its synchronizing side effect).

Opening a file in append mode (a as the first character of mode)
causes all subsequent write operations to this stream to occur at
end-of-file, as if preceded the call:

fseek(stream, 0, SEEK_END);

The fdopen() function associates a stream with the existing file
descriptor, fd.  The mode of the stream (one of the values "r", "r+",
"w", "w+", "a", "a+") must be compatible with the mode of the file
descriptor.  The file position indicator of the new stream is set to
that belonging to fd, and the error and end-of-file indicators are
cleared.  Modes "w" or "w+" do not cause truncation of the file.  The
file descriptor is not dup'ed, and will be closed when the stream
created by fdopen() is closed.  The result of applying fdopen() to a
shared memory object is undefined.

The freopen() function opens the file whose name is the string
pointed to by path and associates the stream pointed to by stream
with it.  The original stream (if it exists) is closed.  The mode
argument is used just as in the fopen() function.  The primary use of
the freopen() function is to change the file associated with a
standard text stream (stderr, stdin, or stdout).


RETURN VALUE top

Upon successful completion fopen(), fdopen() and freopen() return a
FILE pointer.  Otherwise, NULL is returned and errno is set to
indicate the error.


NOTES top

Glibc notes
The GNU C library allows the following extensions for the string
specified in mode:

c (since glibc 2.3.3)
Do not make the open operation, or subsequent read and write
operations, thread cancellation points.  This flag is ignored
for fdopen().

e (since glibc 2.7)
Open the file with the O_CLOEXEC flag.  See open(2) for more
information.  This flag is ignored for fdopen().

m (since glibc 2.3)
Attempt to access the file using mmap(2), rather than I/O
system calls (read(2), write(2)).  Currently, use of mmap(2)
is attempted only for a file opened for reading.

x      Open the file exclusively (like the O_EXCL flag of open(2)).
If the file already exists, fopen() fails, and sets errno to
EEXIST.  This flag is ignored for fdopen().

In addition to the above characters, fopen() and freopen() support
the following syntax in mode:

,ccs=string

The given string is taken as the name of a coded character set and
the stream is marked as wide-oriented.  Thereafter, internal
conversion functions convert I/O to and from the character set
string.  If the ,ccs=string syntax is not specified, then the wide-
orientation of the stream is determined by the first file operation.
If that operation is a wide-character operation, the stream is marked
wide-oriented, and functions to convert to the coded character set
are loaded.


BUGS top

摘自:https://msdn.microsoft.com/en-us/library/windows/desktop/ms683463(v=vs.85).aspx


Inheritance

A child process can inherit several properties and resources from its parent process. You can also prevent a child process from inheriting properties from its parent process. The following can be inherited:

Open handles returned by the CreateFile function.
This includes handles to files, console input buffers, console screen buffers, named pipes, serial communication devices, and mailslots.
Open handles to process, thread, mutex, event, semaphore, named-pipe, anonymous-pipe, and file-mapping objects. These are returned by the CreateProcess, CreateThread, CreateMutex, CreateEvent, CreateSemaphore, CreateNamedPipe,CreatePipe,
and CreateFileMapping functions,
respectively.
Environment variables.
The current directory.
The console, unless the process is detached or a new console is created. A child console process can also inherits the parent's standard handles, as well as access to the input buffer and the active screen buffer.
The error mode, as set by the SetErrorMode function.
The process affinity mask.
The association with a job.

The child process does not inherit the following:

Priority class.
Handles returned by LocalAlloc, GlobalAlloc, HeapCreate,
and HeapAlloc.
Pseudo handles, as in the handles returned by the GetCurrentProcess or GetCurrentThread function.
These handles are valid only for the calling process.
DLL module handles returned by the LoadLibrary function.
GDI or USER handles, such as HBITMAP or HMENU.


Inheriting
Handles

A child process can inherit some of its parent's handles, but not inherit others. To cause a handle to be inherited, you must do two things:

Specify that the handle is to be inherited when you create, open, or duplicate the handle. Creation functions typically use thebInheritHandle member of a SECURITY_ATTRIBUTES structure
for this purpose. DuplicateHandle uses
the bInheritHandlesparameter.
Specify that inheritable handles are to be inherited by setting the bInheritHandles parameter to TRUE when calling theCreateProcess function.
Additionally, to inherit the standard input, standard output, and standard error handles, the dwFlagsmember of the STARTUPINFO structure
must include STARTF_USESTDHANDLES.

An inherited handle refers to the same object in the child process as it does in the parent process. It also has the same value and access privileges. Therefore, when one process changes the state of the object, the change affects both processes. To use a handle,
the child process must retrieve the handle value and "know" the object to which it refers. Usually, the parent process communicates this information to the child process through its command line, environment block, or some form of interprocess
communication.

The DuplicateHandle function
is useful if a process has an inheritable open handle that you do not want to be inherited by the child process. In this case, use DuplicateHandle to open a duplicate of the handle that cannot be inherited, then use theCloseHandle function
to close the inheritable handle. You can also use the DuplicateHandle function to open an inheritable duplicate of a handle that cannot be inherited.


Inheriting
Environment Variables

A child process inherits the environment variables of its parent process by default. However, CreateProcess enables
the parent process to specify a different block of environment variables. For more information, see Environment
Variables.


Inheriting
the Current Directory

The GetCurrentDirectory function
retrieves the current directory of the calling process. A child process inherits the current directory of its parent process by default. However, CreateProcess enables
the parent process to specify a different current directory for the child process. To change the current directory of the calling process, use the SetCurrentDirectory function.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: