是否有任何平台在 fd_set(对于 select() 或 pselect())上使用结构副本会导致问题? [英] Are there any platforms where using structure copy on an fd_set (for select() or pselect()) causes problems?

查看:29
本文介绍了是否有任何平台在 fd_set(对于 select() 或 pselect())上使用结构副本会导致问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

select()pselect() 系统调用修改它们的参数('fd_set *' 参数),因此输入值告诉系统要检查哪些文件描述符,返回值告诉系统程序员当前可用的文件描述符.

The select() and pselect() system calls modify their arguments (the 'fd_set *' arguments), so the input value tells the system which file descriptors to check and the return values tell the programmer which file descriptors are currently usable.

如果您要为同一组文件描述符重复调用它们,则需要确保每次调用都有一个新的描述符副本.最明显的方法是使用结构副本:

If you are going to call them repeatedly for the same set of file descriptors, you need to ensure that you have a fresh copy of the descriptors for each call. The obvious way to do that is to use a structure copy:

fd_set ref_set_rd;
fd_set ref_set_wr;
fd_set ref_set_er;
...
...code to set the reference fd_set_xx values...
...
while (!done)
{
    fd_set act_set_rd = ref_set_rd;
    fd_set act_set_wr = ref_set_wr;
    fd_set act_set_er = ref_set_er;
    int bits_set = select(max_fd, &act_set_rd, &act_set_wr,
                          &act_set_er, &timeout);
    if (bits_set > 0)
    {
        ...process the output values of act_set_xx...
    }
 }

(编辑以删除不正确的 struct fd_set 引用 - 正如 'R..' 所指出的那样.)

(Edited to remove incorrect struct fd_set references - as pointed out by 'R..'.)

我的问题:

  • 是否有任何平台不安全地对 fd_set 值进行结构复制,如图所示?
  • Are there any platforms where it is not safe to do a structure copy of the fd_set values as shown?

我担心会出现隐藏的内存分配或任何类似的意外情况.(有宏/函数 FD_SET()、FD_CLR()、FD_ZERO() 和 FD_ISSET() 来屏蔽应用程序的内部.)

I'm concerned lest there be hidden memory allocation or anything unexpected like that. (There are macros/functions FD_SET(), FD_CLR(), FD_ZERO() and FD_ISSET() to mask the internals from the application.)

我可以看到 MacOS X (Darwin) 是安全的;因此,其他基于 BSD 的系统可能是安全的.您可以通过在回答中记录您认为安全的其他系统来提供帮助.

I can see that MacOS X (Darwin) is safe; other BSD-based systems are likely to be safe, therefore. You can help by documenting other systems that you know are safe in your answers.

(我确实有点担心 fd_set 在处理超过 8192 个打开的文件描述符时的效果——默认的最大打开文件数仅为 256,但最大数为无限制". 另外,由于结构是 1 KB,所以复制代码的效率并不高,但是在每个循环中运行文件描述符列表以重新创建输入掩码也不一定有效.也许你不能做 select() 当您打开了那么多文件描述符时,尽管这是您最有可能需要该功能的时候.)

(I do have minor concerns about how well the fd_set would work with more than 8192 open file descriptors - the default maximum number of open files is only 256, but the maximum number is 'unlimited'. Also, since the structures are 1 KB, the copying code is not dreadfully efficient, but then running through a list of file descriptors to recreate the input mask on each cycle is not necessarily efficient either. Maybe you can't do select() when you have that many file descriptors open, though that is when you are most likely to need the functionality.)

有一个相关的 SO 问题 - 询问 'poll() vsselect()' 解决了与此问题不同的一系列问题.

There's a related SO question - asking about 'poll() vs select()' which addresses a different set of issues from this question.

请注意,在 MacOS X 上 - 大概是更普遍的 BSD - 有一个 FD_COPY() 宏或函数,具有有效的原型:

Note that on MacOS X - and presumably BSD more generally - there is an FD_COPY() macro or function, with the effective prototype:

  • extern void FD_COPY(constrestrict fd_set *from,restrict fd_set *to);.

在尚不可用的平台上可能值得效仿.

推荐答案

由于 struct fd_set 只是一个常规的 C 结构,所以应该总是没问题的.我个人不喜欢通过 = 运算符进行结构复制,因为我在许多无法访问正常编译器内部函数集的平台上工作过.在我的书中,显式使用 memcpy() 而不是让编译器插入函数调用是更好的方法.

Since struct fd_set is just a regular C structure, that should always be fine. I personally don't like doing structure copying via the = operator, since I've worked on plenty of platforms that didn't have access to the normal set of compiler intrinsics. Using memcpy() explicitly rather than having the compiler insert a function call is a better way to go, in my book.

来自 C 规范的6.5.16.1 简单赋值部分(为简洁起见,在此处进行了编辑):

From the C spec, section 6.5.16.1 Simple assignment (edited here for brevity):

符合下列条件之一:

...

  • 左操作数具有与右操作数类型兼容的结构或联合类型的限定或非限定版本;

...

简单赋值(=)中,右操作数的值被转换为赋值表达式的类型,并替换左操作数指定的对象中存储的值.

In simple assignment (=), the value of the right operand is converted to the type of the assignment expression and replaces the value stored in the object designated by the left operand.

如果存储在一个对象中的值是从另一个对象中读取的,该对象以任何方式与第一个对象的存储重叠,那么重叠应该是精确的,并且两个对象应该具有兼容类型的合格或不合格版本;否则,行为未定义.

If the value being stored in an object is read from another object that overlaps in any way the storage of the first object, then the overlap shall be exact and the two objects shall have qualified or unqualified versions of a compatible type; otherwise, the behavior is undefined.

所以你去了,只要 struct fd_set 实际上是一个普通的 C struct,你就可以保证成功.然而,它确实依赖于你的编译器发出某种代码来完成它,或者依赖于它用于结构分配的任何 memcpy() 内在函数.如果您的平台由于某种原因无法链接到编译器的内部库,则它可能无法正常工作.

So there you go, as long as struct fd_set is a actually a regular C struct, you're guaranteed success. It does depend, however, on your compiler emitting some kind of code to do it, or relying on whatever memcpy() intrinsic it uses for structure assignment. If your platform can't link against the compiler's intrinsic libraries for some reason, it may not work.

如果您打开的文件描述符多于 struct fd_set 的容量,您将不得不玩一些技巧.linux 手册页说:

You will have to play some tricks if you have more open file descriptors than will fit into struct fd_set. The linux man page says:

fd_set 是一个固定大小的缓冲区.执行 FD_CLR()FD_SET()fd 值为负或等于或大于 FD_SETSIZEcode> 将导致未定义的行为.此外,POSIX 要求 fd 是有效的文件描述符.

An fd_set is a fixed size buffer. Executing FD_CLR() or FD_SET() with a value of fd that is negative or is equal to or larger than FD_SETSIZE will result in undefined behavior. Moreover, POSIX requires fd to be a valid file descriptor.

如下所述,证明您的代码在所有系统上都是安全的可能并不值得.FD_COPY() 就是为了这样的用途而提供的,并且大概总是有保证的:

As mentioned below, it might not be worth the effort to prove that your code is safe on all systems. FD_COPY() is provided for just such a use, and is, presumably, always guaranteed:

FD_COPY(&fdset_orig, &fdset_copy)&fdset_orig 的副本替换已经分配的 &fdset_copy 文件描述符集>.

FD_COPY(&fdset_orig, &fdset_copy) replaces an already allocated &fdset_copy file descriptor set with a copy of &fdset_orig.

这篇关于是否有任何平台在 fd_set(对于 select() 或 pselect())上使用结构副本会导致问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆