wa-lang.org/wazero@v1.0.2/imports/wasi_snapshot_preview1/clock.go (about)

     1  package wasi_snapshot_preview1
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"wa-lang.org/wazero/api"
     8  	"wa-lang.org/wazero/internal/wasm"
     9  )
    10  
    11  const (
    12  	functionClockResGet  = "clock_res_get"
    13  	functionClockTimeGet = "clock_time_get"
    14  )
    15  
    16  // https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clockid-enumu32
    17  const (
    18  	// clockIDRealtime is the name ID named "realtime" like sys.Walltime
    19  	clockIDRealtime = iota
    20  	// clockIDMonotonic is the name ID named "monotonic" like sys.Nanotime
    21  	clockIDMonotonic
    22  	// Note: clockIDProcessCputime and clockIDThreadCputime were removed by
    23  	// WASI maintainers: https://github.com/WebAssembly/wasi-libc/pull/294
    24  )
    25  
    26  // clockResGet is the WASI function named functionClockResGet that returns the
    27  // resolution of time values returned by clockTimeGet.
    28  //
    29  // # Parameters
    30  //
    31  //   - id: clock ID to use
    32  //   - resultResolution: offset to write the resolution to api.Memory
    33  //   - the resolution is an uint64 little-endian encoding
    34  //
    35  // Result (Errno)
    36  //
    37  // The return value is ErrnoSuccess except the following error conditions:
    38  //   - ErrnoNotsup: the clock ID is not supported.
    39  //   - ErrnoInval: the clock ID is invalid.
    40  //   - ErrnoFault: there is not enough memory to write results
    41  //
    42  // For example, if the resolution is 100ns, this function writes the below to
    43  // api.Memory:
    44  //
    45  //	                                   uint64le
    46  //	                   +-------------------------------------+
    47  //	                   |                                     |
    48  //	         []byte{?, 0x64, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ?}
    49  //	resultResolution --^
    50  //
    51  // Note: This is similar to `clock_getres` in POSIX.
    52  // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_res_getid-clockid---errno-timestamp
    53  // See https://linux.die.net/man/3/clock_getres
    54  var clockResGet = &wasm.HostFunc{
    55  	ExportNames: []string{functionClockResGet},
    56  	Name:        functionClockResGet,
    57  	ParamTypes:  []api.ValueType{i32, i32},
    58  	ParamNames:  []string{"id", "result.resolution"},
    59  	ResultTypes: []api.ValueType{i32},
    60  	Code: &wasm.Code{
    61  		IsHostFunction: true,
    62  		GoFunc:         wasiFunc(clockResGetFn),
    63  	},
    64  }
    65  
    66  func clockResGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
    67  	sysCtx := mod.(*wasm.CallContext).Sys
    68  	id, resultResolution := uint32(params[0]), uint32(params[1])
    69  
    70  	var resolution uint64 // ns
    71  	switch id {
    72  	case clockIDRealtime:
    73  		resolution = uint64(sysCtx.WalltimeResolution())
    74  	case clockIDMonotonic:
    75  		resolution = uint64(sysCtx.NanotimeResolution())
    76  	default:
    77  		return ErrnoInval
    78  	}
    79  
    80  	if !mod.Memory().WriteUint64Le(ctx, resultResolution, resolution) {
    81  		return ErrnoFault
    82  	}
    83  	return ErrnoSuccess
    84  }
    85  
    86  // clockTimeGet is the WASI function named functionClockTimeGet that returns
    87  // the time value of a name (time.Now).
    88  //
    89  // # Parameters
    90  //
    91  //   - id: clock ID to use
    92  //   - precision: maximum lag (exclusive) that the returned time value may have,
    93  //     compared to its actual value
    94  //   - resultTimestamp: offset to write the timestamp to api.Memory
    95  //   - the timestamp is epoch nanos encoded as a little-endian uint64
    96  //
    97  // Result (Errno)
    98  //
    99  // The return value is ErrnoSuccess except the following error conditions:
   100  //   - ErrnoNotsup: the clock ID is not supported.
   101  //   - ErrnoInval: the clock ID is invalid.
   102  //   - ErrnoFault: there is not enough memory to write results
   103  //
   104  // For example, if time.Now returned exactly midnight UTC 2022-01-01
   105  // (1640995200000000000), and parameters resultTimestamp=1, this function
   106  // writes the below to api.Memory:
   107  //
   108  //	                                    uint64le
   109  //	                  +------------------------------------------+
   110  //	                  |                                          |
   111  //	        []byte{?, 0x0, 0x0, 0x1f, 0xa6, 0x70, 0xfc, 0xc5, 0x16, ?}
   112  //	resultTimestamp --^
   113  //
   114  // Note: This is similar to `clock_gettime` in POSIX.
   115  // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_time_getid-clockid-precision-timestamp---errno-timestamp
   116  // See https://linux.die.net/man/3/clock_gettime
   117  var clockTimeGet = &wasm.HostFunc{
   118  	ExportNames: []string{functionClockTimeGet},
   119  	Name:        functionClockTimeGet,
   120  	ParamTypes:  []api.ValueType{i32, i64, i32},
   121  	ParamNames:  []string{"id", "precision", "result.timestamp"},
   122  	ResultTypes: []api.ValueType{i32},
   123  	Code: &wasm.Code{
   124  		IsHostFunction: true,
   125  		GoFunc:         wasiFunc(clockTimeGetFn),
   126  	},
   127  }
   128  
   129  func clockTimeGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
   130  	sysCtx := mod.(*wasm.CallContext).Sys
   131  	id := uint32(params[0])
   132  	// TODO: precision is currently ignored.
   133  	// precision = params[1]
   134  	resultTimestamp := uint32(params[2])
   135  
   136  	var val uint64
   137  	switch id {
   138  	case clockIDRealtime:
   139  		sec, nsec := sysCtx.Walltime(ctx)
   140  		val = (uint64(sec) * uint64(time.Second.Nanoseconds())) + uint64(nsec)
   141  	case clockIDMonotonic:
   142  		val = uint64(sysCtx.Nanotime(ctx))
   143  	default:
   144  		return ErrnoInval
   145  	}
   146  
   147  	if !mod.Memory().WriteUint64Le(ctx, resultTimestamp, val) {
   148  		return ErrnoFault
   149  	}
   150  	return ErrnoSuccess
   151  }