Search code examples
csocketsioasyncsocketmultiplexing

Does IO multiplexing on one single read-only fd help get better performance than simply blocking read on it?


According to my knowledge, I think if I only need to perform reading operation on one single fd, IO multiplexing like select/poll will not help on performance, it even causes more overhead than just reading fd blockingly.

But the linux auditd project however use select on one single reading socket. Could someone explain what the meaning of it?

The auditd code alse use libev on 1 socket/ 1 pipe and 5 signals. Is it better to use blocking read if I only care about the main netlink socket?

I think possible scenarios may be a listening udp receiver socket etc.

Code block is attached for convenience. Thanks in advance!

925 static int get_reply(int fd, struct audit_reply *rep, int seq)
926 {
927         int rc, i;
928         int timeout = 30; /* tenths of seconds */
929 
930         for (i = 0; i < timeout; i++) {
931                 struct timeval t;
932                 fd_set read_mask;
933 
934                 t.tv_sec  = 0;
935                 t.tv_usec = 100000; /* .1 second */
936                 FD_ZERO(&read_mask);
937                 FD_SET(fd, &read_mask);
938                 do {
939                         rc = select(fd+1, &read_mask, NULL, NULL, &t);
940                 } while (rc < 0 && errno == EINTR);
941                 rc = audit_get_reply(fd, rep, 
942                         GET_REPLY_NONBLOCKING, 0);
943                 if (rc > 0) {
944                         /* Don't make decisions based on wrong packet */
945                         if (rep->nlh->nlmsg_seq != seq)
946                                 continue;
947 
948                         /* If its not what we are expecting, keep looping */
949                         if (rep->type == AUDIT_SIGNAL_INFO)
950                                 return 1;
951 
952                         /* If we get done or error, break out */
953                         if (rep->type == NLMSG_DONE || rep->type == NLMSG_ERROR)
954                                 break;
955                 }
956         }
957         return -1;
958 }

Solution

  • The performance would likely be variable depending on the platform (in this case Linux) but it shouldn't be quicker.

    It seems the main reason the code is using select is for its timeout abilities. It allows a read-with-timeout without actually modifying the timeout (SO_SNDTIMEO, SO_RCVTIMEO) of the socket [or if the socket at all even supports timeouts].