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 }