Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(722)

Delta Between Two Patch Sets: src/pkg/syscall/exec_plan9.go

Issue 3816043: code review 3816043: syscall: Plan 9 support for x86. (Closed)
Left Patch Set: diff -r fad73d342108 https://go.googlecode.com/hg/ Created 13 years, 11 months ago
Right Patch Set: diff -r a15522fba283 https://go.googlecode.com/hg/ Created 13 years, 11 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/syscall/asm_plan9_386.s ('k') | src/pkg/syscall/mkall.sh » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // Copyright 2009 The Go Authors. All rights reserved. 1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 // Fork, exec, wait, etc. 5 // Fork, exec, wait, etc.
6 6
7 package syscall 7 package syscall
8 8
9 import ( 9 import (
10 "sync" 10 "sync"
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 // of NUL-terminated byte pointer. 64 // of NUL-terminated byte pointer.
65 func StringArrayPtr(ss []string) []*byte { 65 func StringArrayPtr(ss []string) []*byte {
66 bb := make([]*byte, len(ss)+1) 66 bb := make([]*byte, len(ss)+1)
67 for i := 0; i < len(ss); i++ { 67 for i := 0; i < len(ss); i++ {
68 bb[i] = StringBytePtr(ss[i]) 68 bb[i] = StringBytePtr(ss[i])
69 } 69 }
70 bb[len(ss)] = nil 70 bb[len(ss)] = nil
71 return bb 71 return bb
72 } 72 }
73 73
74 // Read a 16-bit numeric value from a 9P 74 // gbit16 reads a 16-bit numeric value from a 9P protocol message strored in b,
75 // protocol message b, returning the value 75 // returning the value and the remaining slice of b.
76 // and the remaining slice of b.
77 func gbit16(b []byte) (uint16, []byte) { 76 func gbit16(b []byte) (uint16, []byte) {
78 return uint16(b[0]) | uint16(b[1])<<8, b[2:] 77 return uint16(b[0]) | uint16(b[1])<<8, b[2:]
79 } 78 }
80 79
81 // Read a string from a 9P protocol message b, 80 // gstring reads a string from a 9P protocol message strored in b,
82 // returning the value and the remaining slice of b. 81 // returning the value as a Go string and the remaining slice of b.
83 func gstring(b []byte) (string, []byte) { 82 func gstring(b []byte) (string, []byte) {
84 n, b := gbit16(b) 83 n, b := gbit16(b)
85 return string(b[0:n]), b[n:] 84 return string(b[0:n]), b[n:]
86 } 85 }
87 86
88 // Return file names inside a directory· 87 // readdirnames returns the names of files inside the directory represented by d irfd.
89 // already opened for reading dirfd.
90 func readdirnames(dirfd int) (names []string, err Error) { 88 func readdirnames(dirfd int) (names []string, err Error) {
91 result := make([]string, 0, 100) 89 result := make([]string, 0, 100)
92 var buf [STATMAX]byte 90 var buf [STATMAX]byte
93 91
94 for { 92 for {
95 n, e := Read(dirfd, buf[:]) 93 n, e := Read(dirfd, buf[:])
96 if e != nil { 94 if e != nil {
97 return []string{}, e 95 return []string{}, e
98 } 96 }
99 if n == 0 { 97 if n == 0 {
(...skipping 10 matching lines...) Expand all
110 108
111 name, _ := gstring(buf[i+41:]) 109 name, _ := gstring(buf[i+41:])
112 result = append(result, name) 110 result = append(result, name)
113 111
114 i += int(m) 112 i += int(m)
115 } 113 }
116 } 114 }
117 return []string{}, nil 115 return []string{}, nil
118 } 116 }
119 117
120 // Return a list of currently opened fds (excluding stdin, stdout, stderr) 118 // readdupdevice returns a list of currently opened fds (excluding stdin, stdout , stderr) from the dup device #d.
121 // by reading the special dup device #d. 119 // ForkLock should be write locked before calling, so that no new fds would be c reated while the fd list is being read.
122 // ForkLock should be write locked before calling,
123 // so that no new fds would be created while reading the fd list.
124 func readdupdevice() (fds []int, err Error) { 120 func readdupdevice() (fds []int, err Error) {
125 dupdevfd, err := Open("#d", O_RDONLY) 121 dupdevfd, err := Open("#d", O_RDONLY)
126 122
127 if err != nil { 123 if err != nil {
128 return 124 return
129 } 125 }
130 defer Close(dupdevfd) 126 defer Close(dupdevfd)
131 127
132 » file_names, err := readdirnames(dupdevfd) 128 » fileNames, err := readdirnames(dupdevfd)
133 if err != nil { 129 if err != nil {
134 return 130 return
135 } 131 }
136 132
137 » fds = make([]int, 0, len(file_names)>>1) 133 » fds = make([]int, 0, len(fileNames)>>1)
138 » for _, fdstr := range file_names { 134 » for _, fdstr := range fileNames {
139 if l := len(fdstr); l > 2 && fdstr[l-3] == 'c' && fdstr[l-2] == 't' && fdstr[l-1] == 'l' { 135 if l := len(fdstr); l > 2 && fdstr[l-3] == 'c' && fdstr[l-2] == 't' && fdstr[l-1] == 'l' {
140 continue 136 continue
141 } 137 }
142 138
143 fd := int(atoi([]byte(fdstr))) 139 fd := int(atoi([]byte(fdstr)))
144 140
145 if fd == 0 || fd == 1 || fd == 2 || fd == dupdevfd { 141 if fd == 0 || fd == 1 || fd == 2 || fd == dupdevfd {
146 continue 142 continue
147 } 143 }
148 144
149 fds = append(fds, fd) 145 fds = append(fds, fd)
150 } 146 }
151 147
152 return fds[0:len(fds)], nil 148 return fds[0:len(fds)], nil
153 } 149 }
154 150
155 var startup_fds []int 151 var startupFds []int
156 152
157 // Plan 9 does not allow clearing the OCEXEC flag 153 // Plan 9 does not allow clearing the OCEXEC flag
158 // from the underlying channel backing an open file descriptor, 154 // from the underlying channel backing an open file descriptor,
159 // therefore we store a list of already opened file descriptors 155 // therefore we store a list of already opened file descriptors
160 // inside startup_fds, and skip them when manually closing descriptors 156 // inside startupFds and skip them when manually closing descriptors
161 // not ment to be passed to a child exec. 157 // not meant to be passed to a child exec.
162 func init() { 158 func init() {
163 » startup_fds, _ = readdupdevice() 159 » startupFds, _ = readdupdevice()
164 } 160 }
165 161
166 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child. 162 // forkAndExecInChild forks the process, calling dup onto 0..len(fd)
167 // If a dup or exec fails, write the errstr int to pipe. 163 // and finally invoking exec(argv0, argvv, envv) in the child.
164 // If a dup or exec fails, it writes the error string to pipe.
168 // (The pipe write end is close-on-exec so if exec succeeds, it will be closed.) 165 // (The pipe write end is close-on-exec so if exec succeeds, it will be closed.)
166 //
169 // In the child, this function must not acquire any locks, because 167 // In the child, this function must not acquire any locks, because
170 // they might have been locked at the time of the fork. This means 168 // they might have been locked at the time of the fork. This means
171 // no rescheduling, no malloc calls, and no new stack segments. 169 // no rescheduling, no malloc calls, and no new stack segments.
172 // The calls to RawSyscall are okay because they are assembly 170 // The calls to RawSyscall are okay because they are assembly
173 // functions that do not grow the stack. 171 // functions that do not grow the stack.
174 func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at tr *ProcAttr, fdclose []int, pipe int) (pid int, err Error) { 172 func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, chroot, dir * byte, attr *ProcAttr, fdsToClose []int, pipe int) (pid int, err Error) {
175 // Declare all variables at top in case any 173 // Declare all variables at top in case any
176 // declarations require heap allocation (e.g., errbuf). 174 // declarations require heap allocation (e.g., errbuf).
177 var ( 175 var (
178 r1 uintptr 176 r1 uintptr
179 nextfd int 177 nextfd int
180 i int 178 i int
181 clearenv int 179 clearenv int
182 envfd int 180 envfd int
183 errbuf [ERRMAX]byte 181 errbuf [ERRMAX]byte
184 ) 182 )
(...skipping 13 matching lines...) Expand all
198 if int(r1) == -1 { 196 if int(r1) == -1 {
199 return 0, NewError(errstr()) 197 return 0, NewError(errstr())
200 } 198 }
201 // parent; return PID 199 // parent; return PID
202 return int(r1), nil 200 return int(r1), nil
203 } 201 }
204 202
205 // Fork succeeded, now in child. 203 // Fork succeeded, now in child.
206 204
207 // Close fds we don't need. 205 // Close fds we don't need.
208 » for i = 0; i < len(fdclose); i++ { 206 » for i = 0; i < len(fdsToClose); i++ {
209 » » r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(fdclose[i]), 0, 0) 207 » » r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(fdsToClose[i]), 0, 0)
210 if int(r1) == -1 { 208 if int(r1) == -1 {
211 goto childerror 209 goto childerror
212 } 210 }
213 } 211 }
214 212
215 if envv != nil { 213 if envv != nil {
216 // Write new environment variables. 214 // Write new environment variables.
217 for i = 0; i < len(envv); i++ { 215 for i = 0; i < len(envv); i++ {
218 r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer (envv[i].name)), uintptr(O_WRONLY), uintptr(0666)) 216 r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer (envv[i].name)), uintptr(O_WRONLY), uintptr(0666))
219 217
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
309 for { 307 for {
310 RawSyscall(SYS_EXITS, 0, 0, 0) 308 RawSyscall(SYS_EXITS, 0, 0, 0)
311 } 309 }
312 310
313 // Calling panic is not actually safe, 311 // Calling panic is not actually safe,
314 // but the for loop above won't break 312 // but the for loop above won't break
315 // and this shuts up the compiler. 313 // and this shuts up the compiler.
316 panic("unreached") 314 panic("unreached")
317 } 315 }
318 316
319 func itoa(n int) string {
320 var buf [64]byte
321 j := len(buf)
322 for n > 0 {
323 j--
324 buf[j] = (byte)((n % 10) + '0')
325 n /= 10
326 }
327 return string(buf[j:])
328 }
329
330 func cexecPipe(p []int) Error { 317 func cexecPipe(p []int) Error {
331 e := Pipe(p) 318 e := Pipe(p)
332 if e != nil { 319 if e != nil {
333 return e 320 return e
334 } 321 }
335 322
336 fd, e := Open("#d/"+itoa(p[1]), O_CLOEXEC) 323 fd, e := Open("#d/"+itoa(p[1]), O_CLOEXEC)
337 if e != nil { 324 if e != nil {
338 Close(p[0]) 325 Close(p[0])
339 Close(p[1]) 326 Close(p[1])
340 return e 327 return e
341 } 328 }
342 329
343 Close(fd) 330 Close(fd)
344 return nil 331 return nil
345 } 332 }
346 333
347 type envItem struct { 334 type envItem struct {
348 name *byte 335 name *byte
349 value *byte 336 value *byte
350 nvalue int 337 nvalue int
351 } 338 }
352 339
353 type ProcAttr struct { 340 type ProcAttr struct {
354 » Dir string // Current working directory. 341 » Dir string // Current working directory.
355 » Env []string // Environment. 342 » Env []string // Environment.
356 » Files []int // File descriptors. 343 » Files []int // File descriptors.
344 » Chroot string // Chroot.
357 } 345 }
358 346
359 var zeroAttributes ProcAttr 347 var zeroAttributes ProcAttr
360 348
361 349
362 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error) { 350 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err Error) {
363 var ( 351 var (
364 p [2]int 352 p [2]int
365 n int 353 n int
366 errbuf [ERRMAX]byte 354 errbuf [ERRMAX]byte
367 wmsg Waitmsg 355 wmsg Waitmsg
368 ) 356 )
369 357
370 if attr == nil { 358 if attr == nil {
371 attr = &zeroAttributes 359 attr = &zeroAttributes
372 } 360 }
373 361
374 p[0] = -1 362 p[0] = -1
375 p[1] = -1 363 p[1] = -1
376 364
377 // Convert args to C form. 365 // Convert args to C form.
378 argv0p := StringBytePtr(argv[0]) 366 argv0p := StringBytePtr(argv[0])
379 argvp := StringArrayPtr(argv) 367 argvp := StringArrayPtr(argv)
380 » var envv_parsed []envItem 368
381 369 » var chroot *byte
370 » if attr.Chroot != "" {
371 » » chroot = StringBytePtr(attr.Chroot)
372 » }
382 var dir *byte 373 var dir *byte
383 if attr.Dir != "" { 374 if attr.Dir != "" {
384 dir = StringBytePtr(attr.Dir) 375 dir = StringBytePtr(attr.Dir)
385 } 376 }
386 377 » var envvParsed []envItem
387 if attr.Env != nil { 378 if attr.Env != nil {
388 » » envv_parsed = make([]envItem, 0, len(attr.Env)) 379 » » envvParsed = make([]envItem, 0, len(attr.Env))
389 for _, v := range attr.Env { 380 for _, v := range attr.Env {
390 i := 0 381 i := 0
391 for i < len(v) && v[i] != '=' { 382 for i < len(v) && v[i] != '=' {
392 i++ 383 i++
393 } 384 }
394 385
395 » » » envv_parsed = append(envv_parsed, envItem{StringBytePtr( "/env/" + v[:i]), StringBytePtr(v[i+1:]), len(v) - i}) 386 » » » envvParsed = append(envvParsed, envItem{StringBytePtr("/ env/" + v[:i]), StringBytePtr(v[i+1:]), len(v) - i})
396 » » } 387 » » }
397 » } 388 » }
398 389
399 » // Acquire the fork lock so that no other threads 390 » // Acquire the fork lock to prevent other threads from creating new fds before we fork.
400 » // create new fds that are not yet close-on-exec
401 » // before we fork.
402 ForkLock.Lock() 391 ForkLock.Lock()
403 392
404 // get a list of open fds, excluding stdin,stdout and stderr that need t o be closed in the child. 393 // get a list of open fds, excluding stdin,stdout and stderr that need t o be closed in the child.
405 // no new fds can be created while we hold the ForkLock for writing. 394 // no new fds can be created while we hold the ForkLock for writing.
406 » fds_to_close, e := readdupdevice() 395 » openFds, e := readdupdevice()
407 396
408 if e != nil { 397 if e != nil {
409 ForkLock.Unlock() 398 ForkLock.Unlock()
410 return 0, e 399 return 0, e
411 } 400 }
412 401
402 fdsToClose := make([]int, 0, len(openFds))
413 // exclude fds opened from startup from the list of fds to be closed. 403 // exclude fds opened from startup from the list of fds to be closed.
414 » for _, reserved_fd := range startup_fds { 404 » for _, fd := range openFds {
415 » » for i := 0; i < len(fds_to_close); i++ { 405 » » isReserved := false
416 » » » if reserved_fd == fds_to_close[i] { 406 » » for _, reservedFd := range startupFds {
417 » » » » fds_to_close = append(fds_to_close[:i], fds_to_c lose[i+1:]...) 407 » » » if fd == reservedFd {
408 » » » » isReserved = true
418 break 409 break
419 } 410 }
420 } 411 }
412
413 if !isReserved {
414 fdsToClose = append(fdsToClose, fd)
415 }
421 } 416 }
422 417
423 // exclude fds requested by the caller from the list of fds to be closed . 418 // exclude fds requested by the caller from the list of fds to be closed .
424 » for _, reserved_fd := range attr.Files { 419 » for _, fd := range openFds {
425 » » for i := 0; i < len(fds_to_close); i++ { 420 » » isReserved := false
426 » » » if reserved_fd == fds_to_close[i] { 421 » » for _, reservedFd := range attr.Files {
427 » » » » fds_to_close = append(fds_to_close[:i], fds_to_c lose[i+1:]...) 422 » » » if fd == reservedFd {
423 » » » » isReserved = true
428 break 424 break
429 } 425 }
426 }
427
428 if !isReserved {
429 fdsToClose = append(fdsToClose, fd)
430 } 430 }
431 } 431 }
432 432
433 // Allocate child status pipe close on exec.···· 433 // Allocate child status pipe close on exec.····
434 e = cexecPipe(p[:]) 434 e = cexecPipe(p[:])
435 435
436 if e != nil { 436 if e != nil {
437 return 0, e 437 return 0, e
438 } 438 }
439 » fds_to_close = append(fds_to_close, p[0]) 439 » fdsToClose = append(fdsToClose, p[0])
440 440
441 // Kick off child. 441 // Kick off child.
442 » pid, err = forkAndExecInChild(argv0p, argvp, envv_parsed, dir, attr, fds _to_close, p[1]) 442 » pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, chroot, dir, at tr, fdsToClose, p[1])
443 443
444 if err != nil { 444 if err != nil {
445 if p[0] >= 0 { 445 if p[0] >= 0 {
446 Close(p[0]) 446 Close(p[0])
447 Close(p[1]) 447 Close(p[1])
448 } 448 }
449 ForkLock.Unlock() 449 ForkLock.Unlock()
450 return 0, err 450 return 0, err
451 } 451 }
452 ForkLock.Unlock() 452 ForkLock.Unlock()
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
491 if int(r1) == -1 { 491 if int(r1) == -1 {
492 return NewError(errstr()) 492 return NewError(errstr())
493 } 493 }
494 494
495 for _, v := range envv { 495 for _, v := range envv {
496 i := 0 496 i := 0
497 for i < len(v) && v[i] != '=' { 497 for i < len(v) && v[i] != '=' {
498 i++ 498 i++
499 } 499 }
500 500
501 » » » r1, _, _ := RawSyscall(SYS_CREATE, uintptr(unsafe.Pointe r(StringBytePtr("/env/"+v[:i]))), 501 » » » fd, e := Create("/env/"+v[:i], O_WRONLY, 0666)
502 » » » » uintptr(O_WRONLY), uintptr(0666)) 502 » » » if e != nil {
503 » » » if int(r1) == -1 { 503 » » » » return e
504 » » » » return NewError(errstr()) 504 » » » }
505 » » » } 505
506 506 » » » _, e = Write(fd, []byte(v[i+1:]))
507 » » » envfd := int(r1) 507 » » » if e != nil {
508 508 » » » » Close(fd)
509 » » » r1, _, _ = RawSyscall6(SYS_PWRITE, uintptr(envfd), uintp tr(unsafe.Pointer(StringBytePtr(v[i+1:]))), 509 » » » » return e
510 » » » » uintptr(len(v)-i), ^uintptr(0), ^uintptr(0), 0) 510 » » » }
511 » » » if int(r1) == -1 || int(r1) != (len(v)-i) { 511 » » » Close(fd)
512 » » » » return NewError(errstr())
513 » » » }
514
515 » » » r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(envfd), 0, 0)
516 » » » if int(r1) == -1 {
517 » » » » return NewError(errstr())
518 » » » }
519 } 512 }
520 } 513 }
521 514
522 _, _, e := Syscall(SYS_EXEC, 515 _, _, e := Syscall(SYS_EXEC,
523 uintptr(unsafe.Pointer(StringBytePtr(argv0))), 516 uintptr(unsafe.Pointer(StringBytePtr(argv0))),
524 uintptr(unsafe.Pointer(&StringArrayPtr(argv)[0])), 517 uintptr(unsafe.Pointer(&StringArrayPtr(argv)[0])),
525 0) 518 0)
526 519
527 return NewError(e) 520 return NewError(e)
528 } 521 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b