Skip to content

Commit

Permalink
First pass at setTimeout
Browse files Browse the repository at this point in the history
  • Loading branch information
ry committed May 18, 2018
1 parent 360c50b commit 0a46a3e
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 2 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ TS_FILES = \
msg.pb.js \
os.ts \
runtime.ts \
timers.ts \
util.ts

deno: assets.go msg.pb.go main.go
Expand Down
49 changes: 48 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ import (
"os"
"path"
"runtime"
"sync"
"time"
)

var wg sync.WaitGroup
var resChan chan *Msg

func SourceCodeHash(filename string, sourceCodeBuf []byte) string {
h := md5.New()
h.Write([]byte(filename))
Expand Down Expand Up @@ -70,6 +75,22 @@ func HandleSourceCodeCache(filename string, sourceCode string,
return out
}

func HandleTimerStart(id int32, interval bool, duration int32) []byte {
wg.Add(1)
go func() {
defer wg.Done()
time.Sleep(time.Duration(duration) * time.Millisecond)
resChan <- &Msg{
Payload: &Msg_TimerReady{
TimerReady: &TimerReadyMsg{
Id: id,
},
},
}
}()
return nil
}

func UserHomeDir() string {
if runtime.GOOS == "windows" {
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
Expand Down Expand Up @@ -121,7 +142,11 @@ func recv(buf []byte) []byte {
return HandleSourceCodeFetch(payload.Filename)
case *Msg_SourceCodeCache:
payload := msg.GetSourceCodeCache()
return HandleSourceCodeCache(payload.Filename, payload.SourceCode, payload.OutputCode)
return HandleSourceCodeCache(payload.Filename, payload.SourceCode,
payload.OutputCode)
case *Msg_TimerStart:
payload := msg.GetTimerStart()
return HandleTimerStart(payload.Id, payload.Interval, payload.Duration)
default:
panic("Unexpected message")
}
Expand All @@ -137,6 +162,9 @@ func main() {
cwd, err := os.Getwd()
check(err)

resChan = make(chan *Msg)
doneChan := make(chan bool)

out, err := proto.Marshal(&Msg{
Payload: &Msg_Start{
Start: &StartMsg{
Expand All @@ -151,4 +179,23 @@ func main() {
os.Stderr.WriteString(err.Error())
os.Exit(1)
}

// 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
}
}
}
4 changes: 4 additions & 0 deletions main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { main as pb } from "./msg.pb";
import "./util";
import * as runtime from "./runtime";
import * as timers from "./timers";
import * as path from "path";

function start(cwd: string, argv: string[]): void {
Expand All @@ -17,6 +18,9 @@ V8Worker2.recv((ab: ArrayBuffer) => {
case "start":
start(msg.start.cwd, msg.start.argv);
break;
case "timerReady":
timers.timerReady(msg.timerReady.id, msg.timerReady.done);
break;
default:
console.log("Unknown message", msg);
break;
Expand Down
13 changes: 13 additions & 0 deletions msg.proto
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ message Msg {
SourceCodeFetchResMsg source_code_fetch_res = 12;
SourceCodeCacheMsg source_code_cache = 13;
ExitMsg exit = 14;
TimerStartMsg timer_start = 15;
TimerReadyMsg timer_ready = 16;
}
}

Expand All @@ -33,3 +35,14 @@ message SourceCodeCacheMsg {
}

message ExitMsg { int32 code = 1; }

message TimerStartMsg {
int32 id = 1;
bool interval = 2;
int32 duration = 3; // In milliseconds.
}

message TimerReadyMsg {
int32 id = 1;
bool done = 2;
}
2 changes: 1 addition & 1 deletion os.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function typedArrayToArrayBuffer(ta: TypedArray): ArrayBuffer {
return ab as ArrayBuffer;
}

function sendMsgFromObject(obj: pb.IMsg): null | pb.Msg {
export function sendMsgFromObject(obj: pb.IMsg): null | pb.Msg {
const msg = pb.Msg.fromObject(obj);
const ui8 = pb.Msg.encode(msg).finish();
const ab = typedArrayToArrayBuffer(ui8);
Expand Down
5 changes: 5 additions & 0 deletions testdata/004_set_timeout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
setTimeout(function() {
console.log("World");
}, 10);

console.log("Hello");
2 changes: 2 additions & 0 deletions testdata/004_set_timeout.ts.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Hello
World
43 changes: 43 additions & 0 deletions timers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { _global } from "./util";
import { sendMsgFromObject } from "./os";

let nextTimerId = 1;

// tslint:disable-next-line:no-any
type TimerCallback = (...args: any[]) => void;

interface Timer {
id: number;
cb: TimerCallback;
interval: boolean;
duration: number; // milliseconds
}

const timers = new Map<number, Timer>();

export function setTimeout(cb: TimerCallback, duration: number): number {
const timer = {
id: nextTimerId++,
interval: false,
duration,
cb
};
timers.set(timer.id, timer);
sendMsgFromObject({
timerStart: {
id: timer.id,
interval: false,
duration
}
});
return timer.id;
}
_global["setTimeout"] = setTimeout;

export function timerReady(id: number, done: boolean): void {
const timer = timers.get(id);
timer.cb();
if (done) {
timers.delete(id);
}
}

0 comments on commit 0a46a3e

Please sign in to comment.