locks
This commit is contained in:
		
							parent
							
								
									2a22ca2a7f
								
							
						
					
					
						commit
						6029286b43
					
				
							
								
								
									
										39
									
								
								bridge.go
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								bridge.go
									
									
									
									
									
								
							@ -1,8 +1,10 @@
 | 
			
		||||
package wasm
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"encoding/binary"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"math"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"sync"
 | 
			
		||||
@ -16,7 +18,7 @@ import (
 | 
			
		||||
var undefined = &struct{}{}
 | 
			
		||||
var bridges = map[string]*Bridge{}
 | 
			
		||||
var mu sync.RWMutex // to protect bridges
 | 
			
		||||
type context struct{ n string }
 | 
			
		||||
type bctx struct{ n string }
 | 
			
		||||
 | 
			
		||||
func getCtxData(b *Bridge) (unsafe.Pointer, error) {
 | 
			
		||||
	mu.Lock()
 | 
			
		||||
@ -26,12 +28,12 @@ func getCtxData(b *Bridge) (unsafe.Pointer, error) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bridges[b.name] = b
 | 
			
		||||
	return unsafe.Pointer(&context{n: b.name}), nil
 | 
			
		||||
	return unsafe.Pointer(&bctx{n: b.name}), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getBridge(ctx unsafe.Pointer) *Bridge {
 | 
			
		||||
	ictx := wasmer.IntoInstanceContext(ctx)
 | 
			
		||||
	c := (*context)(ictx.Data())
 | 
			
		||||
	c := (*bctx)(ictx.Data())
 | 
			
		||||
	mu.RLock()
 | 
			
		||||
	defer mu.RUnlock()
 | 
			
		||||
	return bridges[c.n]
 | 
			
		||||
@ -40,12 +42,13 @@ func getBridge(ctx unsafe.Pointer) *Bridge {
 | 
			
		||||
type Bridge struct {
 | 
			
		||||
	name     string
 | 
			
		||||
	instance wasmer.Instance
 | 
			
		||||
	done     chan bool
 | 
			
		||||
	exitCode int
 | 
			
		||||
	values   []interface{}
 | 
			
		||||
	valuesMu sync.RWMutex
 | 
			
		||||
	refs     map[interface{}]int
 | 
			
		||||
	memory   []byte
 | 
			
		||||
	exited   bool
 | 
			
		||||
	cancF    context.CancelFunc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BridgeFromBytes(name string, bytes []byte, imports *wasmer.Imports) (*Bridge, error) {
 | 
			
		||||
@ -175,11 +178,10 @@ func (b *Bridge) check() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Run start the wasm instance.
 | 
			
		||||
func (b *Bridge) Run(init chan error, done chan bool) {
 | 
			
		||||
func (b *Bridge) Run(ctx context.Context, init chan error) {
 | 
			
		||||
	b.check()
 | 
			
		||||
	defer b.instance.Close()
 | 
			
		||||
 | 
			
		||||
	b.done = done
 | 
			
		||||
	run := b.instance.Exports["run"]
 | 
			
		||||
	_, err := run(0, 0)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@ -187,9 +189,15 @@ func (b *Bridge) Run(init chan error, done chan bool) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx, cancF := context.WithCancel(ctx)
 | 
			
		||||
	b.cancF = cancF
 | 
			
		||||
	init <- nil
 | 
			
		||||
	<-b.done
 | 
			
		||||
	fmt.Printf("WASM exited with code: %v\n", b.exitCode)
 | 
			
		||||
	select {
 | 
			
		||||
	case <-ctx.Done():
 | 
			
		||||
		log.Printf("stopping WASM[%s] instance...\n", b.name)
 | 
			
		||||
		b.exited = true
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) mem() []byte {
 | 
			
		||||
@ -297,6 +305,9 @@ func (b *Bridge) loadValue(addr int32) interface{} {
 | 
			
		||||
		return f
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	b.valuesMu.RLock()
 | 
			
		||||
	defer b.valuesMu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	return b.values[b.getUint32(addr)]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -353,9 +364,11 @@ func (b *Bridge) storeValue(addr int32, v interface{}) {
 | 
			
		||||
 | 
			
		||||
	ref, ok := b.refs[v]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		b.valuesMu.RLock()
 | 
			
		||||
		ref = len(b.values)
 | 
			
		||||
		b.values = append(b.values, v)
 | 
			
		||||
		b.refs[v] = ref
 | 
			
		||||
		b.valuesMu.RUnlock()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	typeFlag := 0
 | 
			
		||||
@ -422,7 +435,9 @@ type funcWrapper struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) makeFuncWrapper(id, this interface{}, args *[]interface{}) (interface{}, error) {
 | 
			
		||||
	b.valuesMu.RLock()
 | 
			
		||||
	goObj := b.values[7].(*object)
 | 
			
		||||
	b.valuesMu.RUnlock()
 | 
			
		||||
	event := propObject("_pendingEvent", map[string]interface{}{
 | 
			
		||||
		"id":   id,
 | 
			
		||||
		"this": nil,
 | 
			
		||||
@ -440,15 +455,21 @@ func (b *Bridge) makeFuncWrapper(id, this interface{}, args *[]interface{}) (int
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) CallFunc(fn string, args []interface{}) (interface{}, error) {
 | 
			
		||||
	b.check()
 | 
			
		||||
	b.valuesMu.RLock()
 | 
			
		||||
	fw, ok := b.values[5].(*object).props[fn]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		return nil, fmt.Errorf("missing function: %v", fn)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return b.makeFuncWrapper(fw.(*funcWrapper).id, b.values[7], &args)
 | 
			
		||||
	this := b.values[7]
 | 
			
		||||
	b.valuesMu.RUnlock()
 | 
			
		||||
 | 
			
		||||
	return b.makeFuncWrapper(fw.(*funcWrapper).id, this, &args)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Bridge) SetFunc(fname string, fn Func) error {
 | 
			
		||||
	b.valuesMu.RLock()
 | 
			
		||||
	defer b.valuesMu.RUnlock()
 | 
			
		||||
	b.values[5].(*object).props[fname] = &fn
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,36 +1,51 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"context"
 | 
			
		||||
	"log"
 | 
			
		||||
 | 
			
		||||
	"github.com/vedhavyas/go-wasm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func proxy(b *wasm.Bridge) wasm.Func {
 | 
			
		||||
func addProxy(b *wasm.Bridge) wasm.Func {
 | 
			
		||||
	return func(args []interface{}) (i interface{}, e error) {
 | 
			
		||||
		log.Println("In Go", args)
 | 
			
		||||
		return b.CallFunc("addition", args)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	b, err := wasm.BridgeFromFile("test", "./examples/wasm/main.wasm", nil)
 | 
			
		||||
func multiply(b *wasm.Bridge, a int) (int, error) {
 | 
			
		||||
	m, err := b.CallFunc("multiplier", nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
		return 0, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = b.SetFunc("proxy", proxy(b))
 | 
			
		||||
	return a * int(m.(float64)), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	b, err := wasm.BridgeFromFile("test", "./examples/wasm/main.wasm", nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	init, done := make(chan error), make(chan bool)
 | 
			
		||||
	go b.Run(init, done)
 | 
			
		||||
	err = b.SetFunc("addProxy", addProxy(b))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	init := make(chan error)
 | 
			
		||||
	ctx, cancF := context.WithCancel(context.Background())
 | 
			
		||||
	defer cancF()
 | 
			
		||||
	go b.Run(ctx, init)
 | 
			
		||||
	err = <-init
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	<-done
 | 
			
		||||
	log.Println("wasm exited", err)
 | 
			
		||||
	mul, err := multiply(b, 10)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	log.Printf("Multiplier: %v\n", mul)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -13,14 +13,18 @@ func addition(this js.Value, args []js.Value) interface{} {
 | 
			
		||||
	return a + b
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func multiplier(this js.Value, args []js.Value) interface{} {
 | 
			
		||||
	return 10
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	ch := make(chan bool)
 | 
			
		||||
 | 
			
		||||
	// register functions
 | 
			
		||||
	fun := js.FuncOf(addition)
 | 
			
		||||
	js.Global().Set("addition", fun)
 | 
			
		||||
	js.Global().Set("addition", js.FuncOf(addition))
 | 
			
		||||
	js.Global().Set("multiplier", js.FuncOf(multiplier))
 | 
			
		||||
 | 
			
		||||
	res := js.Global().Get("proxy").Invoke(1, 2)
 | 
			
		||||
	res := js.Global().Get("addProxy").Invoke(1, 2)
 | 
			
		||||
	log.Printf("1 + 2 = %d\n", res.Int())
 | 
			
		||||
	<-ch
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										24
									
								
								imports.go
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								imports.go
									
									
									
									
									
								
							@ -29,6 +29,7 @@ import "C"
 | 
			
		||||
import (
 | 
			
		||||
	"crypto/rand"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
@ -38,16 +39,15 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//export debug
 | 
			
		||||
func debug(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
	fmt.Println(sp)
 | 
			
		||||
func debug(_ unsafe.Pointer, sp int32) {
 | 
			
		||||
	log.Println(sp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//export wexit
 | 
			
		||||
func wexit(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
	b := getBridge(ctx)
 | 
			
		||||
	b.exitCode = int(b.getUint32(sp + 8))
 | 
			
		||||
	b.exited = true
 | 
			
		||||
	close(b.done)
 | 
			
		||||
	b.cancF()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//export wwrite
 | 
			
		||||
@ -56,7 +56,10 @@ func wwrite(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
	fd := int(b.getInt64(sp + 8))
 | 
			
		||||
	p := int(b.getInt64(sp + 16))
 | 
			
		||||
	l := int(b.getInt32(sp + 24))
 | 
			
		||||
	syscall.Write(fd, b.mem()[p:p+l])
 | 
			
		||||
	_, err := syscall.Write(fd, b.mem()[p:p+l])
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(fmt.Errorf("wasm-write: %v", err))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//export nanotime
 | 
			
		||||
@ -76,12 +79,12 @@ func walltime(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//export scheduleCallback
 | 
			
		||||
func scheduleCallback(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
func scheduleCallback(_ unsafe.Pointer, _ int32) {
 | 
			
		||||
	panic("schedule callback")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//export clearScheduledCallback
 | 
			
		||||
func clearScheduledCallback(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
func clearScheduledCallback(_ unsafe.Pointer, _ int32) {
 | 
			
		||||
	panic("clear scheduled callback")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -89,7 +92,6 @@ func clearScheduledCallback(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
func getRandomData(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
	s := getBridge(ctx).loadSlice(sp + 8)
 | 
			
		||||
	_, err := rand.Read(s)
 | 
			
		||||
	// TODO how to pass error?
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic("failed: getRandomData")
 | 
			
		||||
	}
 | 
			
		||||
@ -146,7 +148,7 @@ func valueIndex(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//export valueSetIndex
 | 
			
		||||
func valueSetIndex(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
func valueSetIndex(_ unsafe.Pointer, _ int32) {
 | 
			
		||||
	panic("valueSetIndex")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -234,12 +236,12 @@ func valueLoadString(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//export scheduleTimeoutEvent
 | 
			
		||||
func scheduleTimeoutEvent(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
func scheduleTimeoutEvent(_ unsafe.Pointer, _ int32) {
 | 
			
		||||
	panic("scheduleTimeoutEvent")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//export clearTimeoutEvent
 | 
			
		||||
func clearTimeoutEvent(ctx unsafe.Pointer, sp int32) {
 | 
			
		||||
func clearTimeoutEvent(_ unsafe.Pointer, _ int32) {
 | 
			
		||||
	panic("clearTimeoutEvent")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user