Source file src/runtime/os_wasip1.go

     1  // Copyright 2023 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  //go:build wasip1
     6  
     7  package runtime
     8  
     9  import (
    10  	"structs"
    11  	"unsafe"
    12  )
    13  
    14  // GOARCH=wasm currently has 64 bits pointers, but the WebAssembly host expects
    15  // pointers to be 32 bits so we use this type alias to represent pointers in
    16  // structs and arrays passed as arguments to WASI functions.
    17  //
    18  // Note that the use of an integer type prevents the compiler from tracking
    19  // pointers passed to WASI functions, so we must use KeepAlive to explicitly
    20  // retain the objects that could otherwise be reclaimed by the GC.
    21  type uintptr32 = uint32
    22  
    23  // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-size-u32
    24  type size = uint32
    25  
    26  // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-errno-variant
    27  type errno = uint32
    28  
    29  // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-filesize-u64
    30  type filesize = uint64
    31  
    32  // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-timestamp-u64
    33  type timestamp = uint64
    34  
    35  // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-clockid-variant
    36  type clockid = uint32
    37  
    38  const (
    39  	clockRealtime  clockid = 0
    40  	clockMonotonic clockid = 1
    41  )
    42  
    43  // https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-iovec-record
    44  type iovec struct {
    45  	buf    uintptr32
    46  	bufLen size
    47  }
    48  
    49  //go:wasmimport wasi_snapshot_preview1 proc_exit
    50  func exit(code int32)
    51  
    52  //go:wasmimport wasi_snapshot_preview1 args_get
    53  //go:noescape
    54  func args_get(argv *uintptr32, argvBuf *byte) errno
    55  
    56  //go:wasmimport wasi_snapshot_preview1 args_sizes_get
    57  //go:noescape
    58  func args_sizes_get(argc, argvBufLen *size) errno
    59  
    60  //go:wasmimport wasi_snapshot_preview1 clock_time_get
    61  //go:noescape
    62  func clock_time_get(clock_id clockid, precision timestamp, time *timestamp) errno
    63  
    64  //go:wasmimport wasi_snapshot_preview1 environ_get
    65  //go:noescape
    66  func environ_get(environ *uintptr32, environBuf *byte) errno
    67  
    68  //go:wasmimport wasi_snapshot_preview1 environ_sizes_get
    69  //go:noescape
    70  func environ_sizes_get(environCount, environBufLen *size) errno
    71  
    72  //go:wasmimport wasi_snapshot_preview1 fd_write
    73  //go:noescape
    74  func fd_write(fd int32, iovs unsafe.Pointer, iovsLen size, nwritten *size) errno
    75  
    76  //go:wasmimport wasi_snapshot_preview1 random_get
    77  //go:noescape
    78  func random_get(buf *byte, bufLen size) errno
    79  
    80  type eventtype = uint8
    81  
    82  const (
    83  	eventtypeClock eventtype = iota
    84  	eventtypeFdRead
    85  	eventtypeFdWrite
    86  )
    87  
    88  type eventrwflags = uint16
    89  
    90  const (
    91  	fdReadwriteHangup eventrwflags = 1 << iota
    92  )
    93  
    94  type userdata = uint64
    95  
    96  // The go:wasmimport directive currently does not accept values of type uint16
    97  // in arguments or returns of the function signature. Most WASI imports return
    98  // an errno value, which we have to define as uint32 because of that limitation.
    99  // However, the WASI errno type is intended to be a 16 bits integer, and in the
   100  // event struct the error field should be of type errno. If we used the errno
   101  // type for the error field it would result in a mismatching field alignment and
   102  // struct size because errno is declared as a 32 bits type, so we declare the
   103  // error field as a plain uint16.
   104  type event struct {
   105  	_           structs.HostLayout
   106  	userdata    userdata
   107  	error       uint16
   108  	typ         eventtype
   109  	fdReadwrite eventFdReadwrite
   110  }
   111  
   112  type eventFdReadwrite struct {
   113  	_      structs.HostLayout
   114  	nbytes filesize
   115  	flags  eventrwflags
   116  }
   117  
   118  type subclockflags = uint16
   119  
   120  const (
   121  	subscriptionClockAbstime subclockflags = 1 << iota
   122  )
   123  
   124  type subscriptionClock struct {
   125  	_         structs.HostLayout
   126  	id        clockid
   127  	timeout   timestamp
   128  	precision timestamp
   129  	flags     subclockflags
   130  }
   131  
   132  type subscriptionFdReadwrite struct {
   133  	_  structs.HostLayout
   134  	fd int32
   135  }
   136  
   137  type subscription struct {
   138  	_        structs.HostLayout
   139  	userdata userdata
   140  	u        subscriptionUnion
   141  }
   142  
   143  type subscriptionUnion [5]uint64
   144  
   145  func (u *subscriptionUnion) eventtype() *eventtype {
   146  	return (*eventtype)(unsafe.Pointer(&u[0]))
   147  }
   148  
   149  func (u *subscriptionUnion) subscriptionClock() *subscriptionClock {
   150  	return (*subscriptionClock)(unsafe.Pointer(&u[1]))
   151  }
   152  
   153  func (u *subscriptionUnion) subscriptionFdReadwrite() *subscriptionFdReadwrite {
   154  	return (*subscriptionFdReadwrite)(unsafe.Pointer(&u[1]))
   155  }
   156  
   157  //go:wasmimport wasi_snapshot_preview1 poll_oneoff
   158  //go:noescape
   159  func poll_oneoff(in *subscription, out *event, nsubscriptions size, nevents *size) errno
   160  
   161  func write1(fd uintptr, p unsafe.Pointer, n int32) int32 {
   162  	iov := iovec{
   163  		buf:    uintptr32(uintptr(p)),
   164  		bufLen: size(n),
   165  	}
   166  	var nwritten size
   167  	if fd_write(int32(fd), unsafe.Pointer(&iov), 1, &nwritten) != 0 {
   168  		throw("fd_write failed")
   169  	}
   170  	return int32(nwritten)
   171  }
   172  
   173  func usleep(usec uint32) {
   174  	var in subscription
   175  	var out event
   176  	var nevents size
   177  
   178  	eventtype := in.u.eventtype()
   179  	*eventtype = eventtypeClock
   180  
   181  	subscription := in.u.subscriptionClock()
   182  	subscription.id = clockMonotonic
   183  	subscription.timeout = timestamp(usec) * 1e3
   184  	subscription.precision = 1e3
   185  
   186  	if poll_oneoff(&in, &out, 1, &nevents) != 0 {
   187  		throw("wasi_snapshot_preview1.poll_oneoff")
   188  	}
   189  }
   190  
   191  func readRandom(r []byte) int {
   192  	if random_get(&r[0], size(len(r))) != 0 {
   193  		return 0
   194  	}
   195  	return len(r)
   196  }
   197  
   198  func goenvs() {
   199  	// arguments
   200  	var argc size
   201  	var argvBufLen size
   202  	if args_sizes_get(&argc, &argvBufLen) != 0 {
   203  		throw("args_sizes_get failed")
   204  	}
   205  
   206  	argslice = make([]string, argc)
   207  	if argc > 0 {
   208  		argv := make([]uintptr32, argc)
   209  		argvBuf := make([]byte, argvBufLen)
   210  		if args_get(&argv[0], &argvBuf[0]) != 0 {
   211  			throw("args_get failed")
   212  		}
   213  
   214  		for i := range argslice {
   215  			start := argv[i] - uintptr32(uintptr(unsafe.Pointer(&argvBuf[0])))
   216  			end := start
   217  			for argvBuf[end] != 0 {
   218  				end++
   219  			}
   220  			argslice[i] = string(argvBuf[start:end])
   221  		}
   222  	}
   223  
   224  	// environment
   225  	var environCount size
   226  	var environBufLen size
   227  	if environ_sizes_get(&environCount, &environBufLen) != 0 {
   228  		throw("environ_sizes_get failed")
   229  	}
   230  
   231  	envs = make([]string, environCount)
   232  	if environCount > 0 {
   233  		environ := make([]uintptr32, environCount)
   234  		environBuf := make([]byte, environBufLen)
   235  		if environ_get(&environ[0], &environBuf[0]) != 0 {
   236  			throw("environ_get failed")
   237  		}
   238  
   239  		for i := range envs {
   240  			start := environ[i] - uintptr32(uintptr(unsafe.Pointer(&environBuf[0])))
   241  			end := start
   242  			for environBuf[end] != 0 {
   243  				end++
   244  			}
   245  			envs[i] = string(environBuf[start:end])
   246  		}
   247  	}
   248  }
   249  
   250  func walltime() (sec int64, nsec int32) {
   251  	return walltime1()
   252  }
   253  
   254  func walltime1() (sec int64, nsec int32) {
   255  	var time timestamp
   256  	if clock_time_get(clockRealtime, 0, &time) != 0 {
   257  		throw("clock_time_get failed")
   258  	}
   259  	return int64(time / 1000000000), int32(time % 1000000000)
   260  }
   261  
   262  func nanotime1() int64 {
   263  	var time timestamp
   264  	if clock_time_get(clockMonotonic, 0, &time) != 0 {
   265  		throw("clock_time_get failed")
   266  	}
   267  	return int64(time)
   268  }
   269  

View as plain text