...

Source file src/runtime/os_plan9.go

     1	// Copyright 2010 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package runtime
     6	
     7	import (
     8		"runtime/internal/atomic"
     9		"unsafe"
    10	)
    11	
    12	type mOS struct {
    13		waitsemacount uint32
    14		notesig       *int8
    15		errstr        *byte
    16		ignoreHangup  bool
    17	}
    18	
    19	func closefd(fd int32) int32
    20	
    21	//go:noescape
    22	func open(name *byte, mode, perm int32) int32
    23	
    24	//go:noescape
    25	func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
    26	
    27	//go:noescape
    28	func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
    29	
    30	func seek(fd int32, offset int64, whence int32) int64
    31	
    32	//go:noescape
    33	func exits(msg *byte)
    34	
    35	//go:noescape
    36	func brk_(addr unsafe.Pointer) int32
    37	
    38	func sleep(ms int32) int32
    39	
    40	func rfork(flags int32) int32
    41	
    42	//go:noescape
    43	func plan9_semacquire(addr *uint32, block int32) int32
    44	
    45	//go:noescape
    46	func plan9_tsemacquire(addr *uint32, ms int32) int32
    47	
    48	//go:noescape
    49	func plan9_semrelease(addr *uint32, count int32) int32
    50	
    51	//go:noescape
    52	func notify(fn unsafe.Pointer) int32
    53	
    54	func noted(mode int32) int32
    55	
    56	//go:noescape
    57	func nsec(*int64) int64
    58	
    59	//go:noescape
    60	func sigtramp(ureg, note unsafe.Pointer)
    61	
    62	func setfpmasks()
    63	
    64	//go:noescape
    65	func tstart_plan9(newm *m)
    66	
    67	func errstr() string
    68	
    69	type _Plink uintptr
    70	
    71	//go:linkname os_sigpipe os.sigpipe
    72	func os_sigpipe() {
    73		throw("too many writes on closed pipe")
    74	}
    75	
    76	func sigpanic() {
    77		g := getg()
    78		if !canpanic(g) {
    79			throw("unexpected signal during runtime execution")
    80		}
    81	
    82		note := gostringnocopy((*byte)(unsafe.Pointer(g.m.notesig)))
    83		switch g.sig {
    84		case _SIGRFAULT, _SIGWFAULT:
    85			i := index(note, "addr=")
    86			if i >= 0 {
    87				i += 5
    88			} else if i = index(note, "va="); i >= 0 {
    89				i += 3
    90			} else {
    91				panicmem()
    92			}
    93			addr := note[i:]
    94			g.sigcode1 = uintptr(atolwhex(addr))
    95			if g.sigcode1 < 0x1000 || g.paniconfault {
    96				panicmem()
    97			}
    98			print("unexpected fault address ", hex(g.sigcode1), "\n")
    99			throw("fault")
   100		case _SIGTRAP:
   101			if g.paniconfault {
   102				panicmem()
   103			}
   104			throw(note)
   105		case _SIGINTDIV:
   106			panicdivide()
   107		case _SIGFLOAT:
   108			panicfloat()
   109		default:
   110			panic(errorString(note))
   111		}
   112	}
   113	
   114	func atolwhex(p string) int64 {
   115		for hasPrefix(p, " ") || hasPrefix(p, "\t") {
   116			p = p[1:]
   117		}
   118		neg := false
   119		if hasPrefix(p, "-") || hasPrefix(p, "+") {
   120			neg = p[0] == '-'
   121			p = p[1:]
   122			for hasPrefix(p, " ") || hasPrefix(p, "\t") {
   123				p = p[1:]
   124			}
   125		}
   126		var n int64
   127		switch {
   128		case hasPrefix(p, "0x"), hasPrefix(p, "0X"):
   129			p = p[2:]
   130			for ; len(p) > 0; p = p[1:] {
   131				if '0' <= p[0] && p[0] <= '9' {
   132					n = n*16 + int64(p[0]-'0')
   133				} else if 'a' <= p[0] && p[0] <= 'f' {
   134					n = n*16 + int64(p[0]-'a'+10)
   135				} else if 'A' <= p[0] && p[0] <= 'F' {
   136					n = n*16 + int64(p[0]-'A'+10)
   137				} else {
   138					break
   139				}
   140			}
   141		case hasPrefix(p, "0"):
   142			for ; len(p) > 0 && '0' <= p[0] && p[0] <= '7'; p = p[1:] {
   143				n = n*8 + int64(p[0]-'0')
   144			}
   145		default:
   146			for ; len(p) > 0 && '0' <= p[0] && p[0] <= '9'; p = p[1:] {
   147				n = n*10 + int64(p[0]-'0')
   148			}
   149		}
   150		if neg {
   151			n = -n
   152		}
   153		return n
   154	}
   155	
   156	type sigset struct{}
   157	
   158	// Called to initialize a new m (including the bootstrap m).
   159	// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   160	func mpreinit(mp *m) {
   161		// Initialize stack and goroutine for note handling.
   162		mp.gsignal = malg(32 * 1024)
   163		mp.gsignal.m = mp
   164		mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, true))
   165		// Initialize stack for handling strings from the
   166		// errstr system call, as used in package syscall.
   167		mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, true))
   168	}
   169	
   170	func msigsave(mp *m) {
   171	}
   172	
   173	func msigrestore(sigmask sigset) {
   174	}
   175	
   176	//go:nosplit
   177	//go:nowritebarrierrec
   178	func clearSignalHandlers() {
   179	}
   180	
   181	func sigblock() {
   182	}
   183	
   184	// Called to initialize a new m (including the bootstrap m).
   185	// Called on the new thread, cannot allocate memory.
   186	func minit() {
   187		if atomic.Load(&exiting) != 0 {
   188			exits(&emptystatus[0])
   189		}
   190		// Mask all SSE floating-point exceptions
   191		// when running on the 64-bit kernel.
   192		setfpmasks()
   193	}
   194	
   195	// Called from dropm to undo the effect of an minit.
   196	func unminit() {
   197	}
   198	
   199	var sysstat = []byte("/dev/sysstat\x00")
   200	
   201	func getproccount() int32 {
   202		var buf [2048]byte
   203		fd := open(&sysstat[0], _OREAD, 0)
   204		if fd < 0 {
   205			return 1
   206		}
   207		ncpu := int32(0)
   208		for {
   209			n := read(fd, unsafe.Pointer(&buf), int32(len(buf)))
   210			if n <= 0 {
   211				break
   212			}
   213			for i := int32(0); i < n; i++ {
   214				if buf[i] == '\n' {
   215					ncpu++
   216				}
   217			}
   218		}
   219		closefd(fd)
   220		if ncpu == 0 {
   221			ncpu = 1
   222		}
   223		return ncpu
   224	}
   225	
   226	var devswap = []byte("/dev/swap\x00")
   227	var pagesize = []byte(" pagesize\n")
   228	
   229	func getPageSize() uintptr {
   230		var buf [2048]byte
   231		var pos int
   232		fd := open(&devswap[0], _OREAD, 0)
   233		if fd < 0 {
   234			// There's not much we can do if /dev/swap doesn't
   235			// exist. However, nothing in the memory manager uses
   236			// this on Plan 9, so it also doesn't really matter.
   237			return minPhysPageSize
   238		}
   239		for pos < len(buf) {
   240			n := read(fd, unsafe.Pointer(&buf[pos]), int32(len(buf)-pos))
   241			if n <= 0 {
   242				break
   243			}
   244			pos += int(n)
   245		}
   246		closefd(fd)
   247		text := buf[:pos]
   248		// Find "<n> pagesize" line.
   249		bol := 0
   250		for i, c := range text {
   251			if c == '\n' {
   252				bol = i + 1
   253			}
   254			if bytesHasPrefix(text[i:], pagesize) {
   255				// Parse number at the beginning of this line.
   256				return uintptr(_atoi(text[bol:]))
   257			}
   258		}
   259		// Again, the page size doesn't really matter, so use a fallback.
   260		return minPhysPageSize
   261	}
   262	
   263	func bytesHasPrefix(s, prefix []byte) bool {
   264		if len(s) < len(prefix) {
   265			return false
   266		}
   267		for i, p := range prefix {
   268			if s[i] != p {
   269				return false
   270			}
   271		}
   272		return true
   273	}
   274	
   275	var pid = []byte("#c/pid\x00")
   276	
   277	func getpid() uint64 {
   278		var b [20]byte
   279		fd := open(&pid[0], 0, 0)
   280		if fd >= 0 {
   281			read(fd, unsafe.Pointer(&b), int32(len(b)))
   282			closefd(fd)
   283		}
   284		c := b[:]
   285		for c[0] == ' ' || c[0] == '\t' {
   286			c = c[1:]
   287		}
   288		return uint64(_atoi(c))
   289	}
   290	
   291	func osinit() {
   292		initBloc()
   293		ncpu = getproccount()
   294		physPageSize = getPageSize()
   295		getg().m.procid = getpid()
   296		notify(unsafe.Pointer(funcPC(sigtramp)))
   297	}
   298	
   299	//go:nosplit
   300	func crash() {
   301		notify(nil)
   302		*(*int)(nil) = 0
   303	}
   304	
   305	//go:nosplit
   306	func getRandomData(r []byte) {
   307		extendRandom(r, 0)
   308	}
   309	
   310	func goenvs() {
   311	}
   312	
   313	func initsig(preinit bool) {
   314	}
   315	
   316	//go:nosplit
   317	func osyield() {
   318		sleep(0)
   319	}
   320	
   321	//go:nosplit
   322	func usleep(µs uint32) {
   323		ms := int32(µs / 1000)
   324		if ms == 0 {
   325			ms = 1
   326		}
   327		sleep(ms)
   328	}
   329	
   330	//go:nosplit
   331	func nanotime() int64 {
   332		var scratch int64
   333		ns := nsec(&scratch)
   334		// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
   335		if ns == 0 {
   336			return scratch
   337		}
   338		return ns
   339	}
   340	
   341	var goexits = []byte("go: exit ")
   342	var emptystatus = []byte("\x00")
   343	var exiting uint32
   344	
   345	func goexitsall(status *byte) {
   346		var buf [_ERRMAX]byte
   347		if !atomic.Cas(&exiting, 0, 1) {
   348			return
   349		}
   350		getg().m.locks++
   351		n := copy(buf[:], goexits)
   352		n = copy(buf[n:], gostringnocopy(status))
   353		pid := getpid()
   354		for mp := (*m)(atomic.Loadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
   355			if mp.procid != 0 && mp.procid != pid {
   356				postnote(mp.procid, buf[:])
   357			}
   358		}
   359		getg().m.locks--
   360	}
   361	
   362	var procdir = []byte("/proc/")
   363	var notefile = []byte("/note\x00")
   364	
   365	func postnote(pid uint64, msg []byte) int {
   366		var buf [128]byte
   367		var tmp [32]byte
   368		n := copy(buf[:], procdir)
   369		n += copy(buf[n:], itoa(tmp[:], pid))
   370		copy(buf[n:], notefile)
   371		fd := open(&buf[0], _OWRITE, 0)
   372		if fd < 0 {
   373			return -1
   374		}
   375		len := findnull(&msg[0])
   376		if write(uintptr(fd), unsafe.Pointer(&msg[0]), int32(len)) != int64(len) {
   377			closefd(fd)
   378			return -1
   379		}
   380		closefd(fd)
   381		return 0
   382	}
   383	
   384	//go:nosplit
   385	func exit(e int32) {
   386		var status []byte
   387		if e == 0 {
   388			status = emptystatus
   389		} else {
   390			// build error string
   391			var tmp [32]byte
   392			status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0)
   393		}
   394		goexitsall(&status[0])
   395		exits(&status[0])
   396	}
   397	
   398	// May run with m.p==nil, so write barriers are not allowed.
   399	//go:nowritebarrier
   400	func newosproc(mp *m) {
   401		if false {
   402			print("newosproc mp=", mp, " ostk=", &mp, "\n")
   403		}
   404		pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT)
   405		if pid < 0 {
   406			throw("newosproc: rfork failed")
   407		}
   408		if pid == 0 {
   409			tstart_plan9(mp)
   410		}
   411	}
   412	
   413	func exitThread(wait *uint32) {
   414		// We should never reach exitThread on Plan 9 because we let
   415		// the OS clean up threads.
   416		throw("exitThread")
   417	}
   418	
   419	//go:nosplit
   420	func semacreate(mp *m) {
   421	}
   422	
   423	//go:nosplit
   424	func semasleep(ns int64) int {
   425		_g_ := getg()
   426		if ns >= 0 {
   427			ms := timediv(ns, 1000000, nil)
   428			if ms == 0 {
   429				ms = 1
   430			}
   431			ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms)
   432			if ret == 1 {
   433				return 0 // success
   434			}
   435			return -1 // timeout or interrupted
   436		}
   437		for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 {
   438			// interrupted; try again (c.f. lock_sema.go)
   439		}
   440		return 0 // success
   441	}
   442	
   443	//go:nosplit
   444	func semawakeup(mp *m) {
   445		plan9_semrelease(&mp.waitsemacount, 1)
   446	}
   447	
   448	//go:nosplit
   449	func read(fd int32, buf unsafe.Pointer, n int32) int32 {
   450		return pread(fd, buf, n, -1)
   451	}
   452	
   453	//go:nosplit
   454	func write(fd uintptr, buf unsafe.Pointer, n int32) int64 {
   455		return int64(pwrite(int32(fd), buf, n, -1))
   456	}
   457	
   458	var _badsignal = []byte("runtime: signal received on thread not created by Go.\n")
   459	
   460	// This runs on a foreign stack, without an m or a g. No stack split.
   461	//go:nosplit
   462	func badsignal2() {
   463		pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1)
   464		exits(&_badsignal[0])
   465	}
   466	
   467	func raisebadsignal(sig uint32) {
   468		badsignal2()
   469	}
   470	
   471	func _atoi(b []byte) int {
   472		n := 0
   473		for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
   474			n = n*10 + int(b[0]) - '0'
   475			b = b[1:]
   476		}
   477		return n
   478	}
   479	
   480	func signame(sig uint32) string {
   481		if sig >= uint32(len(sigtable)) {
   482			return ""
   483		}
   484		return sigtable[sig].name
   485	}
   486	

View as plain text