Retrying is also not necessarily safe for all syscalls after interruption.
If connect() fails, consider the state of the socket as unspecified. Portable applications should close the socket and create a new one for reconnecting.
Also, I'm not sure if it'll work OOTB with existing debuggers. Usually debuggers want to be aware of signals/they'll catch them. But you probably don't want your program stopping at every cancelation.
While being traced, the tracee will stop each time a signal is delivered, even if the signal is being ignored.
Sure, but I don't see how that applies to the points I made? Reframing the questions if that's helpful:
Does the abstraction make it look like every API supports cancelation (even though it can't in a way that the caller might expect?)?
The post makes it sound like that's the case, but it's not clear to me as I'm not that familiar with how the APIs are used.
I skimmed the implementation and it looks like it adds a retry loop around syscalls with continue on EINTR (that short-circuits if the operation was canceled). For example:
Here, it seems like it's retrying the syscall on EINTR. But it seems like that's not the desired behavior according to POSIX? Now, this particular point still applies even if you didn't have the try syscall.checkCancel(); but it wouldn't have applied if the EINTR handling was (say) the caller's responsibility.
Without further investigation, it's not clear to me that advice from the informative section of the posix specification is better followed or better ignored. Assuming it is worth heeding, it's a trivial fix, since there is only one callsite to the function you pasted, and at that callsite is also where it creates the socket. So that can simply go into the retry loop.
The interface specifies error.Canceled to be included in the error set of most I/O functions, and then leaves it up to the I/O implementation to define the cancelation granularity that is provided. The topic of this article, std.Io.Threaded, does in fact support cancelation for all of the operations on all posix operating systems, as well as macOS and Windows. I am not aware of any exceptions to this, other than the fact that there is still some work left "todo" in the DNS resolution implementation to take advantage of e.g. getaddrinfo_a / gai_cancel.
Could you argue that POSIX enforces some idea of general idea of how syscalls would go, through? I understand this is much of a muchness seeing it’s not adhered by the letter from what I can see…
.NET does the same thing with async CancellationToken. It's understood to be a "best effort" cancellation, not a true one. If the underlying syscall doesn't support cancellation, CancellationTokenSource.Cancel() does nothing. It's just something the developer needs to know.
typesanitizer | a day ago
Isn't pretending that all syscalls can be canceled a lie? Not all syscalls guarantee that they are interruptible (naively, a user might expect that any long-running syscall may be promptly interrupted). https://stackoverflow.com/questions/14542987/why-doing-i-o-in-linux-is-uninterruptible
Retrying is also not necessarily safe for all syscalls after interruption.
https://man7.org/linux/man-pages/man2/connect.2.html
Also, I'm not sure if it'll work OOTB with existing debuggers. Usually debuggers want to be aware of signals/they'll catch them. But you probably don't want your program stopping at every cancelation.
https://man7.org/linux/man-pages/man2/ptrace.2.html
andrewrk | a day ago
Zig's
std.Iointerface is a cross platform abstraction; it doesn't necessarily map one-to-one with syscalls.typesanitizer | 22 hours ago
Sure, but I don't see how that applies to the points I made? Reframing the questions if that's helpful:
continueon EINTR (that short-circuits if the operation was canceled). For example:Here, it seems like it's retrying the syscall on EINTR. But it seems like that's not the desired behavior according to POSIX? Now, this particular point still applies even if you didn't have the
try syscall.checkCancel();but it wouldn't have applied if the EINTR handling was (say) the caller's responsibility.andrewrk | 21 hours ago
Without further investigation, it's not clear to me that advice from the informative section of the posix specification is better followed or better ignored. Assuming it is worth heeding, it's a trivial fix, since there is only one callsite to the function you pasted, and at that callsite is also where it creates the socket. So that can simply go into the retry loop.
The interface specifies
error.Canceledto be included in the error set of most I/O functions, and then leaves it up to the I/O implementation to define the cancelation granularity that is provided. The topic of this article,std.Io.Threaded, does in fact support cancelation for all of the operations on all posix operating systems, as well as macOS and Windows. I am not aware of any exceptions to this, other than the fact that there is still some work left "todo" in the DNS resolution implementation to take advantage of e.g.getaddrinfo_a/gai_cancel.ombredog | a day ago
Could you argue that POSIX enforces some idea of general idea of how syscalls would go, through? I understand this is much of a muchness seeing it’s not adhered by the letter from what I can see…
benburkert | a day ago
On Linux isn't the tracee normally stopped (twice) per syscall already?
typesanitizer | 22 hours ago
That should only happen if the tracee is started with PTRACE_SYSCALL. Otherwise, normal debuggers would have way too much overhead.
colejohnson66 | 13 hours ago
.NET does the same thing with async
CancellationToken. It's understood to be a "best effort" cancellation, not a true one. If the underlying syscall doesn't support cancellation,CancellationTokenSource.Cancel()does nothing. It's just something the developer needs to know.travisgriggs | 23 hours ago
I love these nuggets when technical explanation and prosaic illustration overlap.
Rest of the article was good too.