]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgo/syscalls/exec_helpers.go
Add Go frontend, libgo library, and Go testsuite.
[thirdparty/gcc.git] / libgo / syscalls / exec_helpers.go
1 // exec_helpers.go -- helper functions used with fork, exec, wait.
2
3 // Copyright 2010 The Go Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
6
7 package syscall
8
9 import "sync"
10
11 // Lock synchronizing creation of new file descriptors with fork.
12 //
13 // We want the child in a fork/exec sequence to inherit only the
14 // file descriptors we intend. To do that, we mark all file
15 // descriptors close-on-exec and then, in the child, explicitly
16 // unmark the ones we want the exec'ed program to keep.
17 // Unix doesn't make this easy: there is, in general, no way to
18 // allocate a new file descriptor close-on-exec. Instead you
19 // have to allocate the descriptor and then mark it close-on-exec.
20 // If a fork happens between those two events, the child's exec
21 // will inherit an unwanted file descriptor.
22 //
23 // This lock solves that race: the create new fd/mark close-on-exec
24 // operation is done holding ForkLock for reading, and the fork itself
25 // is done holding ForkLock for writing. At least, that's the idea.
26 // There are some complications.
27 //
28 // Some system calls that create new file descriptors can block
29 // for arbitrarily long times: open on a hung NFS server or named
30 // pipe, accept on a socket, and so on. We can't reasonably grab
31 // the lock across those operations.
32 //
33 // It is worse to inherit some file descriptors than others.
34 // If a non-malicious child accidentally inherits an open ordinary file,
35 // that's not a big deal. On the other hand, if a long-lived child
36 // accidentally inherits the write end of a pipe, then the reader
37 // of that pipe will not see EOF until that child exits, potentially
38 // causing the parent program to hang. This is a common problem
39 // in threaded C programs that use popen.
40 //
41 // Luckily, the file descriptors that are most important not to
42 // inherit are not the ones that can take an arbitrarily long time
43 // to create: pipe returns instantly, and the net package uses
44 // non-blocking I/O to accept on a listening socket.
45 // The rules for which file descriptor-creating operations use the
46 // ForkLock are as follows:
47 //
48 // 1) Pipe. Does not block. Use the ForkLock.
49 // 2) Socket. Does not block. Use the ForkLock.
50 // 3) Accept. If using non-blocking mode, use the ForkLock.
51 // Otherwise, live with the race.
52 // 4) Open. Can block. Use O_CLOEXEC if available (Linux).
53 // Otherwise, live with the race.
54 // 5) Dup. Does not block. Use the ForkLock.
55 // On Linux, could use fcntl F_DUPFD_CLOEXEC
56 // instead of the ForkLock, but only for dup(fd, -1).
57
58 type WaitStatus int
59
60 var ForkLock sync.RWMutex
61
62 // Convert array of string to array
63 // of NUL-terminated byte pointer.
64 func StringArrayPtr(ss []string) []*byte {
65 bb := make([]*byte, len(ss)+1);
66 for i := 0; i < len(ss); i++ {
67 bb[i] = StringBytePtr(ss[i]);
68 }
69 bb[len(ss)] = nil;
70 return bb;
71 }
72
73 func CloseOnExec(fd int) {
74 fcntl(fd, F_SETFD, FD_CLOEXEC);
75 }
76
77 func SetNonblock(fd int, nonblocking bool) (errno int) {
78 flag, err := fcntl(fd, F_GETFL, 0);
79 if err != 0 {
80 return err;
81 }
82 if nonblocking {
83 flag |= O_NONBLOCK;
84 } else {
85 flag &= ^O_NONBLOCK;
86 }
87 flag, err = fcntl(fd, F_SETFL, flag);
88 return err;
89 }
90
91 // Wait status is 7 bits at bottom, either 0 (exited),
92 // 0x7F (stopped), or a signal number that caused an exit.
93 // The 0x80 bit is whether there was a core dump.
94 // An extra number (exit code, signal causing a stop)
95 // is in the high bits. At least that's the idea.
96 // There are various irregularities. For example, the
97 // "continued" status is 0xFFFF, distinguishing itself
98 // from stopped via the core dump bit.
99
100 const (
101 mask = 0x7F;
102 core = 0x80;
103 exited = 0x00;
104 stopped = 0x7F;
105 shift = 8;
106 )
107
108 func (w WaitStatus) Exited() bool {
109 return w&mask == exited;
110 }
111
112 func (w WaitStatus) Signaled() bool {
113 return w&mask != stopped && w&mask != exited;
114 }
115
116 func (w WaitStatus) Stopped() bool {
117 return w&0xFF == stopped;
118 }
119
120 func (w WaitStatus) Continued() bool {
121 return w == 0xFFFF;
122 }
123
124 func (w WaitStatus) CoreDump() bool {
125 return w.Signaled() && w&core != 0;
126 }
127
128 func (w WaitStatus) ExitStatus() int {
129 if !w.Exited() {
130 return -1;
131 }
132 return int(w >> shift) & 0xFF;
133 }
134
135 func (w WaitStatus) Signal() int {
136 if !w.Signaled() {
137 return -1;
138 }
139 return int(w & mask);
140 }
141
142 func (w WaitStatus) StopSignal() int {
143 if !w.Stopped() {
144 return -1;
145 }
146 return int(w >> shift) & 0xFF;
147 }
148
149 func (w WaitStatus) TrapCause() int {
150 if w.StopSignal() != SIGTRAP {
151 return -1;
152 }
153 return int(w >> shift) >> 8;
154 }