Commit 0e4c013b authored by Richard Musiol's avatar Richard Musiol Committed by Richard Musiol

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: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 1961d8d7
...@@ -81,15 +81,15 @@ func Open(path string, openmode int, perm uint32) (int, error) { ...@@ -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") 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 { if err != nil {
return 0, err return 0, err
} }
fd := jsFD.Int() fd := jsFD.Int()
var entries []string var entries []string
if stat, err := fsCall("fstatSync", fd); err == nil && stat.Call("isDirectory").Bool() { if stat, err := fsCall("fstat", fd); err == nil && stat.Call("isDirectory").Bool() {
dir, err := fsCall("readdirSync", path) dir, err := fsCall("readdir", path)
if err != nil { if err != nil {
return 0, err return 0, err
} }
...@@ -113,7 +113,7 @@ func Close(fd int) error { ...@@ -113,7 +113,7 @@ func Close(fd int) error {
filesMu.Lock() filesMu.Lock()
delete(files, fd) delete(files, fd)
filesMu.Unlock() filesMu.Unlock()
_, err := fsCall("closeSync", fd) _, err := fsCall("close", fd)
return err return err
} }
...@@ -125,7 +125,7 @@ func Mkdir(path string, perm uint32) error { ...@@ -125,7 +125,7 @@ func Mkdir(path string, perm uint32) error {
if err := checkPath(path); err != nil { if err := checkPath(path); err != nil {
return err return err
} }
_, err := fsCall("mkdirSync", path, perm) _, err := fsCall("mkdir", path, perm)
return err return err
} }
...@@ -182,7 +182,7 @@ func Stat(path string, st *Stat_t) error { ...@@ -182,7 +182,7 @@ func Stat(path string, st *Stat_t) error {
if err := checkPath(path); err != nil { if err := checkPath(path); err != nil {
return err return err
} }
jsSt, err := fsCall("statSync", path) jsSt, err := fsCall("stat", path)
if err != nil { if err != nil {
return err return err
} }
...@@ -194,7 +194,7 @@ func Lstat(path string, st *Stat_t) error { ...@@ -194,7 +194,7 @@ func Lstat(path string, st *Stat_t) error {
if err := checkPath(path); err != nil { if err := checkPath(path); err != nil {
return err return err
} }
jsSt, err := fsCall("lstatSync", path) jsSt, err := fsCall("lstat", path)
if err != nil { if err != nil {
return err return err
} }
...@@ -203,7 +203,7 @@ func Lstat(path string, st *Stat_t) error { ...@@ -203,7 +203,7 @@ func Lstat(path string, st *Stat_t) error {
} }
func Fstat(fd int, 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 { if err != nil {
return err return err
} }
...@@ -215,7 +215,7 @@ func Unlink(path string) error { ...@@ -215,7 +215,7 @@ func Unlink(path string) error {
if err := checkPath(path); err != nil { if err := checkPath(path); err != nil {
return err return err
} }
_, err := fsCall("unlinkSync", path) _, err := fsCall("unlink", path)
return err return err
} }
...@@ -223,7 +223,7 @@ func Rmdir(path string) error { ...@@ -223,7 +223,7 @@ func Rmdir(path string) error {
if err := checkPath(path); err != nil { if err := checkPath(path); err != nil {
return err return err
} }
_, err := fsCall("rmdirSync", path) _, err := fsCall("rmdir", path)
return err return err
} }
...@@ -231,12 +231,12 @@ func Chmod(path string, mode uint32) error { ...@@ -231,12 +231,12 @@ func Chmod(path string, mode uint32) error {
if err := checkPath(path); err != nil { if err := checkPath(path); err != nil {
return err return err
} }
_, err := fsCall("chmodSync", path, mode) _, err := fsCall("chmod", path, mode)
return err return err
} }
func Fchmod(fd int, mode uint32) error { func Fchmod(fd int, mode uint32) error {
_, err := fsCall("fchmodSync", fd, mode) _, err := fsCall("fchmod", fd, mode)
return err return err
} }
...@@ -267,7 +267,7 @@ func UtimesNano(path string, ts []Timespec) error { ...@@ -267,7 +267,7 @@ func UtimesNano(path string, ts []Timespec) error {
} }
atime := ts[0].Sec atime := ts[0].Sec
mtime := ts[1].Sec mtime := ts[1].Sec
_, err := fsCall("utimesSync", path, atime, mtime) _, err := fsCall("utimes", path, atime, mtime)
return err return err
} }
...@@ -278,7 +278,7 @@ func Rename(from, to string) error { ...@@ -278,7 +278,7 @@ func Rename(from, to string) error {
if err := checkPath(to); err != nil { if err := checkPath(to); err != nil {
return err return err
} }
_, err := fsCall("renameSync", from, to) _, err := fsCall("rename", from, to)
return err return err
} }
...@@ -286,12 +286,12 @@ func Truncate(path string, length int64) error { ...@@ -286,12 +286,12 @@ func Truncate(path string, length int64) error {
if err := checkPath(path); err != nil { if err := checkPath(path); err != nil {
return err return err
} }
_, err := fsCall("truncateSync", path, length) _, err := fsCall("truncate", path, length)
return err return err
} }
func Ftruncate(fd int, length int64) error { func Ftruncate(fd int, length int64) error {
_, err := fsCall("ftruncateSync", fd, length) _, err := fsCall("ftruncate", fd, length)
return err return err
} }
...@@ -299,7 +299,7 @@ func Getcwd(buf []byte) (n int, err error) { ...@@ -299,7 +299,7 @@ func Getcwd(buf []byte) (n int, err error) {
defer recoverErr(&err) defer recoverErr(&err)
cwd := jsProcess.Call("cwd").String() cwd := jsProcess.Call("cwd").String()
n = copy(buf, cwd) n = copy(buf, cwd)
return n, nil return
} }
func Chdir(path string) (err error) { func Chdir(path string) (err error) {
...@@ -323,7 +323,7 @@ func Readlink(path string, buf []byte) (n int, err error) { ...@@ -323,7 +323,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
if err := checkPath(path); err != nil { if err := checkPath(path); err != nil {
return 0, err return 0, err
} }
dst, err := fsCall("readlinkSync", path) dst, err := fsCall("readlink", path)
if err != nil { if err != nil {
return 0, err return 0, err
} }
...@@ -338,7 +338,7 @@ func Link(path, link string) error { ...@@ -338,7 +338,7 @@ func Link(path, link string) error {
if err := checkPath(link); err != nil { if err := checkPath(link); err != nil {
return err return err
} }
_, err := fsCall("linkSync", path, link) _, err := fsCall("link", path, link)
return err return err
} }
...@@ -349,12 +349,12 @@ func Symlink(path, link string) error { ...@@ -349,12 +349,12 @@ func Symlink(path, link string) error {
if err := checkPath(link); err != nil { if err := checkPath(link); err != nil {
return err return err
} }
_, err := fsCall("symlinkSync", path, link) _, err := fsCall("symlink", path, link)
return err return err
} }
func Fsync(fd int) error { func Fsync(fd int) error {
_, err := fsCall("fsyncSync", fd) _, err := fsCall("fsync", fd)
return err return err
} }
...@@ -371,7 +371,7 @@ func Read(fd int, b []byte) (int, error) { ...@@ -371,7 +371,7 @@ func Read(fd int, b []byte) (int, error) {
} }
a := js.TypedArrayOf(b) 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() a.Release()
if err != nil { if err != nil {
return 0, err return 0, err
...@@ -394,7 +394,7 @@ func Write(fd int, b []byte) (int, error) { ...@@ -394,7 +394,7 @@ func Write(fd int, b []byte) (int, error) {
} }
a := js.TypedArrayOf(b) 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() a.Release()
if err != nil { if err != nil {
return 0, err return 0, err
...@@ -406,7 +406,7 @@ func Write(fd int, b []byte) (int, error) { ...@@ -406,7 +406,7 @@ func Write(fd int, b []byte) (int, error) {
func Pread(fd int, b []byte, offset int64) (int, error) { func Pread(fd int, b []byte, offset int64) (int, error) {
a := js.TypedArrayOf(b) 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() a.Release()
if err != nil { if err != nil {
return 0, err return 0, err
...@@ -416,7 +416,7 @@ func Pread(fd int, b []byte, offset int64) (int, error) { ...@@ -416,7 +416,7 @@ func Pread(fd int, b []byte, offset int64) (int, error) {
func Pwrite(fd int, b []byte, offset int64) (int, error) { func Pwrite(fd int, b []byte, offset int64) (int, error) {
a := js.TypedArrayOf(b) 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() a.Release()
if err != nil { if err != nil {
return 0, err return 0, err
...@@ -467,10 +467,31 @@ func Pipe(fd []int) error { ...@@ -467,10 +467,31 @@ func Pipe(fd []int) error {
return ENOSYS return ENOSYS
} }
func fsCall(name string, args ...interface{}) (res js.Value, err error) { func fsCall(name string, args ...interface{}) (js.Value, error) {
defer recoverErr(&err) type callResult struct {
res = jsFS.Call(name, args...) val js.Value
return 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. // checkPath checks that the path is not empty and that it contains no null characters.
...@@ -492,10 +513,15 @@ func recoverErr(errPtr *error) { ...@@ -492,10 +513,15 @@ func recoverErr(errPtr *error) {
if !ok { if !ok {
panic(err) panic(err)
} }
errno, ok := errnoByCode[jsErr.Get("code").String()] *errPtr = mapJSError(jsErr.Value)
if !ok { }
panic(err) }
}
*errPtr = errnoErr(Errno(errno)) // 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))
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment