forked from denoland/deno
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
244 additions
and
124 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/golang/protobuf/proto" | ||
"github.com/ry/v8worker2" | ||
"sync" | ||
) | ||
|
||
// There is a single global worker for this process. | ||
// This file should be the only part of deno that directly access it, so that | ||
// all interaction with V8 can go through a single point. | ||
var worker *v8worker2.Worker | ||
|
||
var channels = make(map[string][]Subscriber) | ||
|
||
type Subscriber func(payload []byte) []byte | ||
|
||
func createWorker() { | ||
worker = v8worker2.New(recv) | ||
} | ||
|
||
func recv(buf []byte) (response []byte) { | ||
msg := &BaseMsg{} | ||
check(proto.Unmarshal(buf, msg)) | ||
assert(len(msg.Payload) > 0, "BaseMsg has empty payload.") | ||
subscribers, ok := channels[msg.Channel] | ||
if !ok { | ||
panic("No subscribers for channel " + msg.Channel) | ||
} | ||
for i := 0; i < len(subscribers); i++ { | ||
s := subscribers[i] | ||
r := s(msg.Payload) | ||
if r != nil { | ||
response = r | ||
} | ||
} | ||
return response | ||
} | ||
|
||
func Sub(channel string, cb Subscriber) { | ||
subscribers, ok := channels[channel] | ||
if !ok { | ||
subscribers = make([]Subscriber, 0) | ||
} | ||
subscribers = append(subscribers, cb) | ||
channels[channel] = subscribers | ||
} | ||
|
||
func Pub(channel string, payload []byte) { | ||
resChan <- &BaseMsg{ | ||
Channel: channel, | ||
Payload: payload, | ||
} | ||
} | ||
|
||
var resChan = make(chan *BaseMsg, 10) | ||
var doneChan = make(chan bool) | ||
var wg sync.WaitGroup | ||
|
||
func DispatchLoop() { | ||
wg.Add(1) | ||
first := true | ||
|
||
// In a goroutine, we wait on for all goroutines to complete (for example | ||
// timers). We use this to signal to the main thread to exit. | ||
go func() { | ||
wg.Wait() | ||
doneChan <- true | ||
}() | ||
|
||
for { | ||
select { | ||
case msg := <-resChan: | ||
out, err := proto.Marshal(msg) | ||
err = worker.SendBytes(out) | ||
check(err) | ||
case <-doneChan: | ||
// All goroutines have completed. Now we can exit main(). | ||
return | ||
} | ||
|
||
// We don't want to exit until we've received at least one message. | ||
// This is so the program doesn't exit after sending the "start" | ||
// message. | ||
if first { | ||
wg.Done() | ||
} | ||
first = false | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { typedArrayToArrayBuffer } from "./util"; | ||
import { _global } from "./globals"; | ||
import { main as pb } from "./msg.pb"; | ||
|
||
type MessageCallback = (msg: Uint8Array) => void; | ||
|
||
const send = V8Worker2.send; | ||
const channels = new Map<string, MessageCallback[]>(); | ||
|
||
export function sub(channel: string, cb: MessageCallback): void { | ||
let subscribers = channels.get(channel); | ||
if (!subscribers) { | ||
subscribers = []; | ||
channels.set(channel, subscribers); | ||
} | ||
subscribers.push(cb); | ||
} | ||
|
||
export function pub(channel: string, payload: Uint8Array): null | ArrayBuffer { | ||
const msg = pb.BaseMsg.fromObject({ channel, payload }); | ||
const ui8 = pb.BaseMsg.encode(msg).finish(); | ||
const ab = typedArrayToArrayBuffer(ui8); | ||
return send(ab); | ||
} | ||
|
||
// Internal version of "pub". | ||
// TODO add internal version of "sub" | ||
// TODO rename to pubInternal() | ||
export function sendMsgFromObject( | ||
channel: string, | ||
obj: pb.IMsg | ||
): null | pb.Msg { | ||
const msg = pb.Msg.fromObject(obj); | ||
const ui8 = pb.Msg.encode(msg).finish(); | ||
const resBuf = pub(channel, ui8); | ||
if (resBuf != null && resBuf.byteLength > 0) { | ||
const res = pb.Msg.decode(new Uint8Array(resBuf)); | ||
if (res != null && res.error != null && res.error.length > 0) { | ||
throw Error(res.error); | ||
} | ||
return res; | ||
} else { | ||
return null; | ||
} | ||
} | ||
|
||
V8Worker2.recv((ab: ArrayBuffer) => { | ||
const msg = pb.BaseMsg.decode(new Uint8Array(ab)); | ||
const subscribers = channels.get(msg.channel); | ||
if (subscribers == null) { | ||
throw Error(`No subscribers for channel "${msg.channel}".`); | ||
} | ||
|
||
for (const subscriber of subscribers) { | ||
subscriber(msg.payload); | ||
} | ||
}); | ||
|
||
// Delete the V8Worker2 from the global object, so that no one else can receive | ||
// messages. | ||
_global["V8Worker2"] = null; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,33 @@ | ||
import * as dispatch from "./dispatch"; | ||
import { main as pb } from "./msg.pb"; | ||
import "./util"; | ||
|
||
import * as runtime from "./runtime"; | ||
import * as timers from "./timers"; | ||
import * as util from "./util"; | ||
|
||
// These have top-level functions that need to execute. | ||
import { initTimers } from "./timers"; | ||
|
||
// To control internal logging output | ||
// Set with the -debug command-line flag. | ||
export let debug = false; | ||
let startCalled = false; | ||
|
||
dispatch.sub("start", (payload: Uint8Array) => { | ||
if (startCalled) { | ||
throw Error("start message received more than once!"); | ||
} | ||
startCalled = true; | ||
|
||
const msg = pb.Msg.decode(payload); | ||
const { cwd, argv, debugFlag, mainJs, mainMap } = msg.start; | ||
|
||
function start( | ||
cwd: string, | ||
argv: string[], | ||
debugFlag: boolean, | ||
mainJs: string, | ||
mainMap: string | ||
): void { | ||
debug = debugFlag; | ||
util.log("start", { cwd, argv, debugFlag }); | ||
|
||
initTimers(); | ||
runtime.setup(mainJs, mainMap); | ||
|
||
const inputFn = argv[0]; | ||
const mod = runtime.resolveModule(inputFn, cwd + "/"); | ||
mod.compileAndRun(); | ||
} | ||
|
||
V8Worker2.recv((ab: ArrayBuffer) => { | ||
const msg = pb.Msg.decode(new Uint8Array(ab)); | ||
switch (msg.payload) { | ||
case "start": | ||
start( | ||
msg.start.cwd, | ||
msg.start.argv, | ||
msg.start.debugFlag, | ||
msg.start.mainJs, | ||
msg.start.mainMap | ||
); | ||
break; | ||
case "timerReady": | ||
timers.timerReady(msg.timerReady.id, msg.timerReady.done); | ||
break; | ||
default: | ||
console.log("Unknown message", msg); | ||
break; | ||
} | ||
}); |
Oops, something went wrong.