mirror of
https://github.com/golang/go
synced 2024-09-05 07:54:46 +00:00
syscall: use asynchronous operations on js/wasm
This commit makes syscall on js/wasm use the asynchronous variants of functions in Node.js' fs module. This enables concurrency and allows the API of the fs module to be implemented with an alternative backend that only supports asynchronous operations. Updates #26051. Change-Id: Ibe1dcc988469fc11c3b8d8d49de439c12ddaafce Reviewed-on: https://go-review.googlesource.com/c/137236 TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
1961d8d72a
commit
0e4c013b67
|
@ -81,15 +81,15 @@ func Open(path string, openmode int, perm uint32) (int, error) {
|
|||
return 0, errors.New("syscall.Open: O_SYNC is not supported by js/wasm")
|
||||
}
|
||||
|
||||
jsFD, err := fsCall("openSync", path, flags, perm)
|
||||
jsFD, err := fsCall("open", path, flags, perm)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
fd := jsFD.Int()
|
||||
|
||||
var entries []string
|
||||
if stat, err := fsCall("fstatSync", fd); err == nil && stat.Call("isDirectory").Bool() {
|
||||
dir, err := fsCall("readdirSync", path)
|
||||
if stat, err := fsCall("fstat", fd); err == nil && stat.Call("isDirectory").Bool() {
|
||||
dir, err := fsCall("readdir", path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ func Close(fd int) error {
|
|||
filesMu.Lock()
|
||||
delete(files, fd)
|
||||
filesMu.Unlock()
|
||||
_, err := fsCall("closeSync", fd)
|
||||
_, err := fsCall("close", fd)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ func Mkdir(path string, perm uint32) error {
|
|||
if err := checkPath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := fsCall("mkdirSync", path, perm)
|
||||
_, err := fsCall("mkdir", path, perm)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ func Stat(path string, st *Stat_t) error {
|
|||
if err := checkPath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
jsSt, err := fsCall("statSync", path)
|
||||
jsSt, err := fsCall("stat", path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ func Lstat(path string, st *Stat_t) error {
|
|||
if err := checkPath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
jsSt, err := fsCall("lstatSync", path)
|
||||
jsSt, err := fsCall("lstat", path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ func Lstat(path string, st *Stat_t) error {
|
|||
}
|
||||
|
||||
func Fstat(fd int, st *Stat_t) error {
|
||||
jsSt, err := fsCall("fstatSync", fd)
|
||||
jsSt, err := fsCall("fstat", fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ func Unlink(path string) error {
|
|||
if err := checkPath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := fsCall("unlinkSync", path)
|
||||
_, err := fsCall("unlink", path)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -223,7 +223,7 @@ func Rmdir(path string) error {
|
|||
if err := checkPath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := fsCall("rmdirSync", path)
|
||||
_, err := fsCall("rmdir", path)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -231,12 +231,12 @@ func Chmod(path string, mode uint32) error {
|
|||
if err := checkPath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := fsCall("chmodSync", path, mode)
|
||||
_, err := fsCall("chmod", path, mode)
|
||||
return err
|
||||
}
|
||||
|
||||
func Fchmod(fd int, mode uint32) error {
|
||||
_, err := fsCall("fchmodSync", fd, mode)
|
||||
_, err := fsCall("fchmod", fd, mode)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -267,7 +267,7 @@ func UtimesNano(path string, ts []Timespec) error {
|
|||
}
|
||||
atime := ts[0].Sec
|
||||
mtime := ts[1].Sec
|
||||
_, err := fsCall("utimesSync", path, atime, mtime)
|
||||
_, err := fsCall("utimes", path, atime, mtime)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -278,7 +278,7 @@ func Rename(from, to string) error {
|
|||
if err := checkPath(to); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := fsCall("renameSync", from, to)
|
||||
_, err := fsCall("rename", from, to)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -286,12 +286,12 @@ func Truncate(path string, length int64) error {
|
|||
if err := checkPath(path); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := fsCall("truncateSync", path, length)
|
||||
_, err := fsCall("truncate", path, length)
|
||||
return err
|
||||
}
|
||||
|
||||
func Ftruncate(fd int, length int64) error {
|
||||
_, err := fsCall("ftruncateSync", fd, length)
|
||||
_, err := fsCall("ftruncate", fd, length)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -299,7 +299,7 @@ func Getcwd(buf []byte) (n int, err error) {
|
|||
defer recoverErr(&err)
|
||||
cwd := jsProcess.Call("cwd").String()
|
||||
n = copy(buf, cwd)
|
||||
return n, nil
|
||||
return
|
||||
}
|
||||
|
||||
func Chdir(path string) (err error) {
|
||||
|
@ -323,7 +323,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
|
|||
if err := checkPath(path); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dst, err := fsCall("readlinkSync", path)
|
||||
dst, err := fsCall("readlink", path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ func Link(path, link string) error {
|
|||
if err := checkPath(link); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := fsCall("linkSync", path, link)
|
||||
_, err := fsCall("link", path, link)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -349,12 +349,12 @@ func Symlink(path, link string) error {
|
|||
if err := checkPath(link); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err := fsCall("symlinkSync", path, link)
|
||||
_, err := fsCall("symlink", path, link)
|
||||
return err
|
||||
}
|
||||
|
||||
func Fsync(fd int) error {
|
||||
_, err := fsCall("fsyncSync", fd)
|
||||
_, err := fsCall("fsync", fd)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -371,7 +371,7 @@ func Read(fd int, b []byte) (int, error) {
|
|||
}
|
||||
|
||||
a := js.TypedArrayOf(b)
|
||||
n, err := fsCall("readSync", fd, a, 0, len(b))
|
||||
n, err := fsCall("read", fd, a, 0, len(b), nil)
|
||||
a.Release()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -394,7 +394,7 @@ func Write(fd int, b []byte) (int, error) {
|
|||
}
|
||||
|
||||
a := js.TypedArrayOf(b)
|
||||
n, err := fsCall("writeSync", fd, a, 0, len(b))
|
||||
n, err := fsCall("write", fd, a, 0, len(b), nil)
|
||||
a.Release()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -406,7 +406,7 @@ func Write(fd int, b []byte) (int, error) {
|
|||
|
||||
func Pread(fd int, b []byte, offset int64) (int, error) {
|
||||
a := js.TypedArrayOf(b)
|
||||
n, err := fsCall("readSync", fd, a, 0, len(b), offset)
|
||||
n, err := fsCall("read", fd, a, 0, len(b), offset)
|
||||
a.Release()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -416,7 +416,7 @@ func Pread(fd int, b []byte, offset int64) (int, error) {
|
|||
|
||||
func Pwrite(fd int, b []byte, offset int64) (int, error) {
|
||||
a := js.TypedArrayOf(b)
|
||||
n, err := fsCall("writeSync", fd, a, 0, len(b), offset)
|
||||
n, err := fsCall("write", fd, a, 0, len(b), offset)
|
||||
a.Release()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -467,10 +467,31 @@ func Pipe(fd []int) error {
|
|||
return ENOSYS
|
||||
}
|
||||
|
||||
func fsCall(name string, args ...interface{}) (res js.Value, err error) {
|
||||
defer recoverErr(&err)
|
||||
res = jsFS.Call(name, args...)
|
||||
return
|
||||
func fsCall(name string, args ...interface{}) (js.Value, error) {
|
||||
type callResult struct {
|
||||
val js.Value
|
||||
err error
|
||||
}
|
||||
|
||||
c := make(chan callResult)
|
||||
jsFS.Call(name, append(args, js.NewCallback(func(args []js.Value) {
|
||||
var res callResult
|
||||
|
||||
if len(args) >= 1 { // on Node.js 8, fs.utimes calls the callback without any arguments
|
||||
if jsErr := args[0]; jsErr != js.Null() {
|
||||
res.err = mapJSError(jsErr)
|
||||
}
|
||||
}
|
||||
|
||||
res.val = js.Undefined()
|
||||
if len(args) >= 2 {
|
||||
res.val = args[1]
|
||||
}
|
||||
|
||||
c <- res
|
||||
}))...)
|
||||
res := <-c
|
||||
return res.val, res.err
|
||||
}
|
||||
|
||||
// checkPath checks that the path is not empty and that it contains no null characters.
|
||||
|
@ -492,10 +513,15 @@ func recoverErr(errPtr *error) {
|
|||
if !ok {
|
||||
panic(err)
|
||||
}
|
||||
errno, ok := errnoByCode[jsErr.Get("code").String()]
|
||||
if !ok {
|
||||
panic(err)
|
||||
}
|
||||
*errPtr = errnoErr(Errno(errno))
|
||||
*errPtr = mapJSError(jsErr.Value)
|
||||
}
|
||||
}
|
||||
|
||||
// mapJSError maps an error given by Node.js to the appropriate Go error
|
||||
func mapJSError(jsErr js.Value) error {
|
||||
errno, ok := errnoByCode[jsErr.Get("code").String()]
|
||||
if !ok {
|
||||
panic(jsErr)
|
||||
}
|
||||
return errnoErr(Errno(errno))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue