www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - SIGUSR2 from GC interrupts application system calls on Linux

reply ikod <geller.garry gmail.com> writes:
Hello,

On linux, in the code below, receive() returns -1 with 
errno=EINTR if syscall is interrupted by GC (so you can see 
several "insterrupted") when GC enabled, and prints nothing (this 
is desired and expected behavior) when GC disabled.

Looks like the reason of the problem is call sigaction(2) without 
SA_RESTART for SIGUSR2 (used by GC to restart suspended thread) 
in core.thread.

Is there any recommended workaround for this problem? Is this a 
bug?

Thanks for your help with this problem

import std.stdio;
import std.format;
import std.socket;
import std.conv: to;
import core.stdc.errno;
import core.memory;
import std.datetime;

auto myRequest(string x)
{
     auto data = new byte[100240];
     ubyte[16*1024] buffer;
     auto timeout = 5.seconds;
     uint delay = to!uint(x) % 5;
     auto addresses = getAddress("httpbin.org", 80);
     auto s = new Socket(AddressFamily.INET, SocketType.STREAM, 
ProtocolType.TCP);
     scope(exit) {
         s.close();
     }
     s.setOption(SocketOptionLevel.SOCKET, SocketOption.SNDTIMEO, 
timeout);
     s.connect(addresses[0]);
     s.send("GET /delay/%d HTTP/1.1\r\nHost: 
httpbin.org\r\n\r\n".format(delay));
     s.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, 
timeout);
     auto r = s.receive(buffer);
     if ( r <= 0 ) {
         if ( errno == EINTR ) {
             writeln("interrupted");
             return "fail";
         }
     }
     return "ok";
};

void main() {
     import std.parallelism;
     import std.range: iota;
     import std.algorithm: map;
     //GC.disable();
     defaultPoolThreads(8);
     auto r = iota(0, 100).map!(to!string);
     auto p = taskPool.map!myRequest(r); // fails
}
May 26 2016
next sibling parent safety0ff <safety0ff.dev gmail.com> writes:
On Thursday, 26 May 2016 at 18:44:22 UTC, ikod wrote:
 Hello,

 On linux, in the code below, receive() returns -1 with 
 errno=EINTR if syscall is interrupted by GC (so you can see 
 several "insterrupted") when GC enabled, and prints nothing 
 (this is desired and expected behavior) when GC disabled.

 Is there any recommended workaround for this problem? Is this a 
 bug?
Looks like recv is non-restartable and it should be called in a loop.
 Looks like the reason of the problem is call sigaction(2) 
 without SA_RESTART for SIGUSR2 (used by GC to restart suspended 
 thread) in core.thread.
This isn't the cause, manually adding SA_RESTART using sigaction made no difference: import core.sys.posix.signal; sigaction_t tmp; sigaction(SIGUSR2, null, &tmp); tmp.sa_flags |= SA_RESTART; sigaction(SIGUSR2, &tmp, null); This is because SIGUSR1 is the signal that actually interrupts the system call, when SIGUSR2 is received the syscall is already interrupted so the flag does not make a difference.
May 26 2016
prev sibling parent reply Claude <no no.no> writes:
On Thursday, 26 May 2016 at 18:44:22 UTC, ikod wrote:
 Is there any recommended workaround for this problem? Is this a 
 bug?
I don't think it's a bug. Even without a GC, on GNU/Linux OS, I would enclose the receive function (or any blocking system function like poll etc) in a do-while loop testing specifically for EINTR. I had the same kind of problem in C. int r; do { r = s.receive(buffer); } while (r < 0 && errno == EINTR);
May 26 2016
parent reply ikod <geller.garry gmail.com> writes:
On Thursday, 26 May 2016 at 19:40:35 UTC, Claude wrote:
 On Thursday, 26 May 2016 at 18:44:22 UTC, ikod wrote:
 Is there any recommended workaround for this problem? Is this 
 a bug?
I don't think it's a bug. Even without a GC, on GNU/Linux OS, I would enclose the receive function (or any blocking system function like poll etc) in a do-while loop testing specifically for EINTR. I had the same kind of problem in C. int r; do { r = s.receive(buffer); } while (r < 0 && errno == EINTR);
Will it not hang in the loop if you send it SIGINT? Looks like not, but is strange for me. Thanks, will do more testing.
May 26 2016
parent Claude <no no.no> writes:
On Thursday, 26 May 2016 at 20:10:57 UTC, ikod wrote:
 Will it not hang in the loop if you send it SIGINT?
 Looks like not, but is strange for me.
Yes, I had the same feeling the first time I came across that. I remember why we had to use that loop in C: when we were using gdb to do some debugging, it would interrupt the sys call, which was not desired. We use that in production code, I've never had any problem with it.
May 27 2016