This is the mail archive of the libc-help@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: recvfrom interrupt


Whether or not the call returns with EINTR depends on whether it is
restarted upon signal delivery.
If the system call is restarted, you will not see EINTR on the user side.

You're using signal(2) to set up the handler. Does it set up the
signal handler with SA_RESTART?

Look at the strace output. On my system (Ubuntu 16 stock) I see:

[pid 12320] rt_sigaction(SIGQUIT, {0x40103c, [QUIT],
SA_RESTORER|SA_RESTART, 0x7f5cee65d4a0},  <unfinished ...>

Thus, the signal handler is set up to restart.

The man page for signal(2), on the other hand, appears out-of-date. It says:

       * On  glibc  2  and later, if the _BSD_SOURCE feature test
macro is not defined, then signal() provides System V
         semantics.  (The default implicit definition of _BSD_SOURCE
is not provided if one invokes gcc(1)  in  one  of
         its  standard  modes  (-std=xxx  or -ansi) or defines various
other feature test macros such as _POSIX_SOURCE,
         _XOPEN_SOURCE, or _SVID_SOURCE; see feature_test_macros(7).)

I checked that _BSD_SOURCE is not defined, yet signal(2) appears to
provide BSD semantics.

Conventional wisdom says to avoid signal(2) in favor of sigaction().

 - Godmar


On Sun, Aug 21, 2016 at 11:05 AM, Manfred <mx2927@gmail.com> wrote:
> Hi all,
>
> While debugging some old code, I encountered the problem that recvfrom calls
> do not get interrupted by a signal (SIG_QUIT).
> The code used to work in the past (a long far away past), anyway I have
> isolated the behavior in the code below, and reporting here because
> signal(7) clearly lists recvfrom as one of the calls that should get
> interrupted by a received signal.
>
> Could anyone give a hint on what am I missing here?
> Thanks in Advance,
> M.
>
>
> #include <stdio.h>
> #include <unistd.h>
>
> #include <sys/types.h>
> #include <sys/wait.h>
> #include <signal.h>
>
> #include <sys/socket.h>
> #include <linux/ipx.h>
>
> #include <stdlib.h>
> #include <string.h>
> #include <stdint.h>
> #include <errno.h>
>
> #include <netinet/in.h>
>
>
> void child();
> void sig_quit(int dummy);
> int create_socket( const char* who, struct sockaddr_ipx* addr, socklen_t*
> addr_len );
>
>
> int main(int argc, char*argv[])
> {
>   int status = 0;
>
>   pid_t pid_child = fork();
>   if(-1 == pid_child)
>   {
>     return 1;
>   }
>   if(0 == pid_child)
>   {
>     child();
>   }
>   else
>   {
>     puts("parent: running\n");
>     sleep(3);
>
>     puts("parent: signaling the child\n");
>     kill(pid_child, SIGQUIT);
>     if(pid_child == waitpid(pid_child, &status, 0))
>     {
>       puts("parent: child terminated\n");
>     }
>     else
>     {
>       puts("parent: ERROR terminating child\n");
>     }
>     puts("parent: terminated\n");
>   }
>
>   return 0;
> }
>
> void child()
> {
>   int sock = 0;
>
>   struct sockaddr_ipx addr;
>   socklen_t           addr_len = sizeof(addr);
>
>   unsigned char buf[256];
>   ssize_t       buflen = 0;
>
>   memset(&addr, 0, sizeof(addr));
>   addr.sipx_family = AF_IPX;
>
>   puts("child: running\n");
>
>   signal(SIGQUIT, sig_quit);
>
>   if((sock = create_socket("child", &addr, &addr_len)) == -1)
>   {
>     puts("child: ERROR creating socket\n");
>     exit(1);
>   }
>
>   memset(&addr, 0, sizeof(addr));
>   addr.sipx_family = AF_IPX;
>   addr_len = sizeof(addr);
>
>   puts("child: receiving datagram");
>   while((buflen = recvfrom(sock, buf, sizeof(buf), 0,
>       (struct sockaddr*)&addr, &addr_len )) != -1)
>   {
>     puts("child: data received\n");
>     for(ssize_t n = 0; n < buflen; ++n)
>     {
>       if(0 < n) printf(", ");
>       printf("%02x", buf[n]);
>       if(1) printf("\'%c\'", buf[n]);
>     }
>     printf("\n");
>   }
>
>   if(EINTR == errno) puts("child: recvfrom interrupted\n");
>   else puts("child: ERROR on recvfrom\n");
>
>
>   if(close(sock) == -1)
>   {
>     puts("client: ERROR closing socket\n");
>     exit(1);
>   }
>   puts("child: socket closed\n");
>   puts("child: terminated\n");
>
> }
>
> int create_socket( const char* who, struct sockaddr_ipx* addr, socklen_t*
> len )
> {
>   int sock = 0;
>   int opt = 1;
>
>   if((sock = socket(AF_IPX, SOCK_DGRAM, 0)) == -1)
>   {
>     printf("%s: ERROR creating socket(%d)\n", who, errno);
>     exit(1);
>   }
>   printf("%s: socket created\n", who);
>
>   if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
>                 &opt, sizeof(opt)) == -1)
>   {
>     printf("%s: ERROR setting socket options(%d)\n", who, errno);
>     exit(1);
>   }
>   printf("%s: socket options set\n", who);
>
>   if(bind(sock, (const struct sockaddr*)addr, *len) == -1)
>   {
>     printf("%s: ERROR binding socket (%d)\n", who, errno);
>     exit(1);
>   }
>   printf("%s: socket bound\n", who);
>
>   if(getsockname(sock, (struct sockaddr*)addr, len) == -1)
>   {
>     printf("%s: ERROR retrieving socket address(%d)\n", who, errno);
>     exit(1);
>   }
>
>   printf("%s: socket address\n\tNET:  %08x\n\tNODE:
> %02x:%02x:%02x:%02x:%02x:%02x:\n\tPORT: %04x\n\tTYPE: %02x\n",
>       who,
>       ntohl(addr->sipx_network),
>       addr->sipx_node[0], addr->sipx_node[1], addr->sipx_node[2],
> addr->sipx_node[3], addr->sipx_node[4], addr->sipx_node[5],
>       ntohs(addr->sipx_port),
>       addr->sipx_type);
>
>   return sock;
> }
>
>
> void sig_quit(int dummy)
> {
> }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]