summaryrefslogtreecommitdiffhomepage
path: root/pkg/syserror/syserror.go
diff options
context:
space:
mode:
authorDean Deng <deandeng@google.com>2020-08-18 19:26:55 -0700
committerRahat Mahmood <46939889+mrahatm@users.noreply.github.com>2020-08-19 11:38:34 -0700
commitb99fce30936ea42bf00e2c7270dc4ca797f766eb (patch)
treed983846a99f38882c48d8e433572e3bb10b8fe99 /pkg/syserror/syserror.go
parentdbade2ec35aa836e8e3b02b0c145b658662728b3 (diff)
Move ERESTART* error definitions to syserror package.
This is needed to avoid circular dependencies between the vfs and kernel packages. PiperOrigin-RevId: 327355524
Diffstat (limited to 'pkg/syserror/syserror.go')
-rw-r--r--pkg/syserror/syserror.go67
1 files changed, 67 insertions, 0 deletions
diff --git a/pkg/syserror/syserror.go b/pkg/syserror/syserror.go
index 798e07b01..fe9f50169 100644
--- a/pkg/syserror/syserror.go
+++ b/pkg/syserror/syserror.go
@@ -153,6 +153,73 @@ func ConvertIntr(err, intr error) error {
return err
}
+// SyscallRestartErrno represents a ERESTART* errno defined in the Linux's kernel
+// include/linux/errno.h. These errnos are never returned to userspace
+// directly, but are used to communicate the expected behavior of an
+// interrupted syscall from the syscall to signal handling.
+type SyscallRestartErrno int
+
+// These numeric values are significant because ptrace syscall exit tracing can
+// observe them.
+//
+// For all of the following errnos, if the syscall is not interrupted by a
+// signal delivered to a user handler, the syscall is restarted.
+const (
+ // ERESTARTSYS is returned by an interrupted syscall to indicate that it
+ // should be converted to EINTR if interrupted by a signal delivered to a
+ // user handler without SA_RESTART set, and restarted otherwise.
+ ERESTARTSYS = SyscallRestartErrno(512)
+
+ // ERESTARTNOINTR is returned by an interrupted syscall to indicate that it
+ // should always be restarted.
+ ERESTARTNOINTR = SyscallRestartErrno(513)
+
+ // ERESTARTNOHAND is returned by an interrupted syscall to indicate that it
+ // should be converted to EINTR if interrupted by a signal delivered to a
+ // user handler, and restarted otherwise.
+ ERESTARTNOHAND = SyscallRestartErrno(514)
+
+ // ERESTART_RESTARTBLOCK is returned by an interrupted syscall to indicate
+ // that it should be restarted using a custom function. The interrupted
+ // syscall must register a custom restart function by calling
+ // Task.SetRestartSyscallFn.
+ ERESTART_RESTARTBLOCK = SyscallRestartErrno(516)
+)
+
+// Error implements error.Error.
+func (e SyscallRestartErrno) Error() string {
+ // Descriptions are borrowed from strace.
+ switch e {
+ case ERESTARTSYS:
+ return "to be restarted if SA_RESTART is set"
+ case ERESTARTNOINTR:
+ return "to be restarted"
+ case ERESTARTNOHAND:
+ return "to be restarted if no handler"
+ case ERESTART_RESTARTBLOCK:
+ return "interrupted by signal"
+ default:
+ return "(unknown interrupt error)"
+ }
+}
+
+// SyscallRestartErrnoFromReturn returns the SyscallRestartErrno represented by
+// rv, the value in a syscall return register.
+func SyscallRestartErrnoFromReturn(rv uintptr) (SyscallRestartErrno, bool) {
+ switch int(rv) {
+ case -int(ERESTARTSYS):
+ return ERESTARTSYS, true
+ case -int(ERESTARTNOINTR):
+ return ERESTARTNOINTR, true
+ case -int(ERESTARTNOHAND):
+ return ERESTARTNOHAND, true
+ case -int(ERESTART_RESTARTBLOCK):
+ return ERESTART_RESTARTBLOCK, true
+ default:
+ return 0, false
+ }
+}
+
func init() {
AddErrorTranslation(ErrWouldBlock, syscall.EWOULDBLOCK)
AddErrorTranslation(ErrInterrupted, syscall.EINTR)