diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ansi.rs | 5 | ||||
-rw-r--r-- | src/cli.rs | 90 | ||||
-rw-r--r-- | src/compiler.rs | 17 | ||||
-rw-r--r-- | src/isolate.rs | 799 | ||||
-rw-r--r-- | src/isolate_init.rs | 2 | ||||
-rw-r--r-- | src/isolate_state.rs | 110 | ||||
-rw-r--r-- | src/js_errors.rs | 53 | ||||
-rw-r--r-- | src/libdeno.rs | 192 | ||||
-rw-r--r-- | src/main.rs | 56 | ||||
-rw-r--r-- | src/modules.rs | 82 | ||||
-rw-r--r-- | src/msg.fbs | 7 | ||||
-rw-r--r-- | src/msg.rs | 5 | ||||
-rw-r--r-- | src/ops.rs | 486 | ||||
-rw-r--r-- | src/resources.rs | 42 | ||||
-rw-r--r-- | src/tokio_util.rs | 36 | ||||
-rw-r--r-- | src/workers.rs | 87 |
16 files changed, 726 insertions, 1343 deletions
diff --git a/src/ansi.rs b/src/ansi.rs index f9cd39ac4..95b5e0694 100644 --- a/src/ansi.rs +++ b/src/ansi.rs @@ -3,7 +3,6 @@ use ansi_term::Color::Fixed; use ansi_term::Color::Red; use ansi_term::Style; use regex::Regex; -use std::borrow::Cow; use std::env; use std::fmt; @@ -19,8 +18,8 @@ lazy_static! { } /// Helper function to strip ansi codes. -#[allow(dead_code)] -pub fn strip_ansi_codes(s: &str) -> Cow<str> { +#[cfg(test)] +pub fn strip_ansi_codes(s: &str) -> std::borrow::Cow<str> { STRIP_ANSI_RE.replace_all(s, "") } diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 000000000..d80587013 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,90 @@ +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +#![allow(unused_variables)] +#![allow(dead_code)] + +use crate::errors::DenoResult; +use crate::isolate_init::IsolateInit; +use crate::isolate_state::IsolateState; +use crate::ops; +use crate::permissions::DenoPermissions; +use deno_core::deno_buf; +use deno_core::deno_mod; +use deno_core::Behavior; +use deno_core::Op; +use std::sync::atomic::Ordering; +use std::sync::Arc; + +// Buf represents a byte array returned from a "Op". The message might be empty +// (which will be translated into a null object on the javascript side) or it is +// a heap allocated opaque sequence of bytes. Usually a flatbuffer message. +pub type Buf = Box<[u8]>; + +/// Implements deno_core::Behavior for the main Deno command-line. +pub struct Cli { + init: IsolateInit, + pub state: Arc<IsolateState>, + pub permissions: Arc<DenoPermissions>, // TODO(ry) move to IsolateState +} + +impl Cli { + pub fn new( + init: IsolateInit, + state: Arc<IsolateState>, + permissions: DenoPermissions, + ) -> Self { + Self { + init, + state, + permissions: Arc::new(permissions), + } + } + + #[inline] + pub fn check_read(&self, filename: &str) -> DenoResult<()> { + self.permissions.check_read(filename) + } + + #[inline] + pub fn check_write(&self, filename: &str) -> DenoResult<()> { + self.permissions.check_write(filename) + } + + #[inline] + pub fn check_env(&self) -> DenoResult<()> { + self.permissions.check_env() + } + + #[inline] + pub fn check_net(&self, filename: &str) -> DenoResult<()> { + self.permissions.check_net(filename) + } + + #[inline] + pub fn check_run(&self) -> DenoResult<()> { + self.permissions.check_run() + } +} + +impl Behavior for Cli { + fn startup_snapshot(&mut self) -> Option<deno_buf> { + self.init.snapshot.take() + } + + fn resolve(&mut self, specifier: &str, referrer: deno_mod) -> deno_mod { + self + .state + .metrics + .resolve_count + .fetch_add(1, Ordering::Relaxed); + let mut modules = self.state.modules.lock().unwrap(); + modules.resolve_cb(&self.state.dir, specifier, referrer) + } + + fn dispatch( + &mut self, + control: &[u8], + zero_copy: deno_buf, + ) -> (bool, Box<Op>) { + ops::dispatch(self, control, zero_copy) + } +} diff --git a/src/compiler.rs b/src/compiler.rs index dab166f47..9edae8cf9 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,18 +1,16 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -use crate::isolate::Buf; -use crate::isolate::IsolateState; +use crate::cli::Buf; use crate::isolate_init; +use crate::isolate_state::IsolateState; use crate::msg; use crate::permissions::{DenoPermissions, PermissionAccessor}; use crate::resources; use crate::resources::Resource; use crate::resources::ResourceId; use crate::workers; - use futures::Future; use serde_json; use std::str; -use std::sync::Arc; use std::sync::Mutex; lazy_static! { @@ -48,7 +46,7 @@ impl ModuleMetaData { } } -fn lazy_start(parent_state: &Arc<IsolateState>) -> Resource { +fn lazy_start(parent_state: &IsolateState) -> Resource { let mut cell = C_RID.lock().unwrap(); let isolate_init = isolate_init::compiler_isolate_init(); let permissions = DenoPermissions { @@ -57,10 +55,11 @@ fn lazy_start(parent_state: &Arc<IsolateState>) -> Resource { allow_net: PermissionAccessor::from(true), ..Default::default() }; + let rid = cell.get_or_insert_with(|| { let resource = workers::spawn( isolate_init, - parent_state.clone(), + parent_state, "compilerMain()".to_string(), permissions, ); @@ -79,7 +78,7 @@ fn req(specifier: &str, referrer: &str) -> Buf { } pub fn compile_sync( - parent_state: &Arc<IsolateState>, + parent_state: &IsolateState, specifier: &str, referrer: &str, module_meta_data: &ModuleMetaData, @@ -92,7 +91,9 @@ pub fn compile_sync( send_future.wait().unwrap(); let recv_future = resources::worker_recv_message(compiler.rid); - let res_msg = recv_future.wait().unwrap().unwrap(); + let result = recv_future.wait().unwrap(); + assert!(result.is_some()); + let res_msg = result.unwrap(); let res_json = std::str::from_utf8(&res_msg).unwrap(); match serde_json::from_str::<serde_json::Value>(res_json) { diff --git a/src/isolate.rs b/src/isolate.rs index 8a77777d2..7f3c0d919 100644 --- a/src/isolate.rs +++ b/src/isolate.rs @@ -1,353 +1,82 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -// Do not use FlatBuffers in this module. -// TODO Currently this module uses Tokio, but it would be nice if they were -// decoupled. - -#![allow(dead_code)] - +use crate::cli::Cli; use crate::compiler::compile_sync; use crate::compiler::ModuleMetaData; -use crate::deno_dir; use crate::errors::DenoError; -use crate::errors::DenoResult; use crate::errors::RustOrJsError; -use crate::flags; -use crate::global_timer::GlobalTimer; -use crate::isolate_init::IsolateInit; -use crate::js_errors::apply_source_map; -use crate::libdeno; -use crate::modules::Modules; +use crate::isolate_state::IsolateState; +use crate::js_errors; use crate::msg; -use crate::permissions::DenoPermissions; -use crate::tokio_util; +use deno_core; +use deno_core::deno_mod; use deno_core::JSError; -use futures::sync::mpsc as async_mpsc; +use futures::Async; use futures::Future; -use libc::c_char; -use libc::c_void; -use std; -use std::cell::Cell; -use std::cell::RefCell; -use std::env; -use std::ffi::CStr; -use std::ffi::CString; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::mpsc; use std::sync::Arc; -use std::sync::Mutex; -use std::sync::{Once, ONCE_INIT}; -use tokio; - -// Buf represents a byte array returned from a "Op". -// The message might be empty (which will be translated into a null object on -// the javascript side) or it is a heap allocated opaque sequence of bytes. -// Usually a flatbuffer message. -pub type Buf = Box<[u8]>; - -// JS promises in Deno map onto a specific Future -// which yields either a DenoError or a byte array. -pub type Op = dyn Future<Item = Buf, Error = DenoError> + Send; - -// Returns (is_sync, op) -pub type Dispatch = fn( - isolate: &Isolate, - buf: libdeno::deno_buf, - zero_copy_buf: libdeno::deno_buf, -) -> (bool, Box<Op>); - -pub struct Isolate { - libdeno_isolate: *const libdeno::isolate, - dispatch: Dispatch, - rx: mpsc::Receiver<(usize, Buf)>, - tx: mpsc::Sender<(usize, Buf)>, - ntasks: Cell<i32>, - pub modules: RefCell<Modules>, - pub state: Arc<IsolateState>, - pub permissions: Arc<DenoPermissions>, -} - -pub type WorkerSender = async_mpsc::Sender<Buf>; -pub type WorkerReceiver = async_mpsc::Receiver<Buf>; -pub type WorkerChannels = (WorkerSender, WorkerReceiver); - -// Isolate cannot be passed between threads but IsolateState can. -// IsolateState satisfies Send and Sync. -// So any state that needs to be accessed outside the main V8 thread should be -// inside IsolateState. -#[cfg_attr(feature = "cargo-clippy", allow(stutter))] -pub struct IsolateState { - pub dir: deno_dir::DenoDir, - pub argv: Vec<String>, - pub flags: flags::DenoFlags, - pub metrics: Metrics, - pub worker_channels: Option<Mutex<WorkerChannels>>, - pub global_timer: Mutex<GlobalTimer>, -} - -impl IsolateState { - pub fn new( - flags: flags::DenoFlags, - argv_rest: Vec<String>, - worker_channels: Option<WorkerChannels>, - ) -> Self { - let custom_root = env::var("DENO_DIR").map(|s| s.into()).ok(); - - Self { - dir: deno_dir::DenoDir::new(flags.reload, flags.recompile, custom_root) - .unwrap(), - argv: argv_rest, - flags, - metrics: Metrics::default(), - worker_channels: worker_channels.map(Mutex::new), - global_timer: Mutex::new(GlobalTimer::new()), - } - } - pub fn main_module(&self) -> Option<String> { - if self.argv.len() <= 1 { - None - } else { - let specifier = self.argv[1].clone(); - let referrer = "."; - match self.dir.resolve_module_url(&specifier, referrer) { - Ok(url) => Some(url.to_string()), - Err(e) => { - debug!("Potentially swallowed error {}", e); - None - } - } - } - } +type CoreIsolate = deno_core::Isolate<Cli>; - #[cfg(test)] - pub fn mock() -> Arc<IsolateState> { - let argv = vec![String::from("./deno"), String::from("hello.js")]; - // For debugging: argv.push_back(String::from("-D")); - let (flags, rest_argv, _) = flags::set_flags(argv).unwrap(); - Arc::new(IsolateState::new(flags, rest_argv, None)) - } - - fn metrics_op_dispatched( - &self, - bytes_sent_control: usize, - bytes_sent_data: usize, - ) { - self.metrics.ops_dispatched.fetch_add(1, Ordering::SeqCst); - self - .metrics - .bytes_sent_control - .fetch_add(bytes_sent_control, Ordering::SeqCst); - self - .metrics - .bytes_sent_data - .fetch_add(bytes_sent_data, Ordering::SeqCst); - } - - fn metrics_op_completed(&self, bytes_received: usize) { - self.metrics.ops_completed.fetch_add(1, Ordering::SeqCst); - self - .metrics - .bytes_received - .fetch_add(bytes_received, Ordering::SeqCst); - } -} - -// AtomicU64 is currently unstable -#[derive(Default)] -pub struct Metrics { - pub ops_dispatched: AtomicUsize, - pub ops_completed: AtomicUsize, - pub bytes_sent_control: AtomicUsize, - pub bytes_sent_data: AtomicUsize, - pub bytes_received: AtomicUsize, - pub resolve_count: AtomicUsize, +/// Wraps deno_core::Isolate to provide source maps, ops for the CLI, and +/// high-level module loading +pub struct Isolate { + inner: CoreIsolate, + state: Arc<IsolateState>, } -static DENO_INIT: Once = ONCE_INIT; - impl Isolate { - pub fn new( - init: IsolateInit, - state: Arc<IsolateState>, - dispatch: Dispatch, - permissions: DenoPermissions, - ) -> Self { - DENO_INIT.call_once(|| { - unsafe { libdeno::deno_init() }; - }); - let config = libdeno::deno_config { - will_snapshot: 0, - load_snapshot: match init.snapshot { - Some(s) => s, - None => libdeno::deno_buf::empty(), - }, - shared: libdeno::deno_buf::empty(), // TODO Use for message passing. - recv_cb: pre_dispatch, - }; - let libdeno_isolate = unsafe { libdeno::deno_new(config) }; - // This channel handles sending async messages back to the runtime. - let (tx, rx) = mpsc::channel::<(usize, Buf)>(); - - let new_isolate = Self { - libdeno_isolate, - dispatch, - rx, - tx, - ntasks: Cell::new(0), - modules: RefCell::new(Modules::new()), + pub fn new(cli: Cli) -> Isolate { + let state = cli.state.clone(); + Self { + inner: CoreIsolate::new(cli), state, - permissions: Arc::new(permissions), - }; - - // Run init script if present. - match init.init_script { - Some(init_script) => new_isolate - .execute2(init_script.filename.as_str(), init_script.source.as_str()) - .unwrap(), - None => {} - }; - - new_isolate - } - - #[inline] - pub fn as_raw_ptr(&self) -> *const c_void { - self as *const _ as *const c_void - } - - #[inline] - pub unsafe fn from_raw_ptr<'a>(ptr: *const c_void) -> &'a Self { - let ptr = ptr as *const _; - &*ptr - } - - #[inline] - pub fn check_read(&self, filename: &str) -> DenoResult<()> { - self.permissions.check_read(filename) - } - - #[inline] - pub fn check_write(&self, filename: &str) -> DenoResult<()> { - self.permissions.check_write(filename) - } - - #[inline] - pub fn check_env(&self) -> DenoResult<()> { - self.permissions.check_env() - } - - #[inline] - pub fn check_net(&self, filename: &str) -> DenoResult<()> { - self.permissions.check_net(filename) - } - - #[inline] - pub fn check_run(&self) -> DenoResult<()> { - self.permissions.check_run() - } - - pub fn last_exception(&self) -> Option<JSError> { - let ptr = unsafe { libdeno::deno_last_exception(self.libdeno_isolate) }; - if ptr.is_null() { - None - } else { - let cstr = unsafe { CStr::from_ptr(ptr) }; - let v8_exception = cstr.to_str().unwrap(); - debug!("v8_exception\n{}\n", v8_exception); - let js_error = JSError::from_v8_exception(v8_exception).unwrap(); - let js_error_mapped = apply_source_map(&js_error, &self.state.dir); - Some(js_error_mapped) } } /// Same as execute2() but the filename defaults to "<anonymous>". - pub fn execute(&self, js_source: &str) -> Result<(), JSError> { + pub fn execute(&mut self, js_source: &str) -> Result<(), JSError> { self.execute2("<anonymous>", js_source) } /// Executes the provided JavaScript source code. The js_filename argument is /// provided only for debugging purposes. pub fn execute2( - &self, + &mut self, js_filename: &str, js_source: &str, ) -> Result<(), JSError> { - let filename = CString::new(js_filename).unwrap(); - let source = CString::new(js_source).unwrap(); - unsafe { - libdeno::deno_execute( - self.libdeno_isolate, - self.as_raw_ptr(), - filename.as_ptr(), - source.as_ptr(), - ) - }; - if let Some(err) = self.last_exception() { - return Err(err); - } - Ok(()) - } - - pub fn mod_new( - &mut self, - main: bool, - name: String, - source: String, - ) -> Result<libdeno::deno_mod, JSError> { - let name_ = CString::new(name.clone()).unwrap(); - let name_ptr = name_.as_ptr() as *const c_char; - - let source_ = CString::new(source.clone()).unwrap(); - let source_ptr = source_.as_ptr() as *const c_char; - - let id = unsafe { - libdeno::deno_mod_new(self.libdeno_isolate, main, name_ptr, source_ptr) - }; - if let Some(js_error) = self.last_exception() { - assert_eq!(id, 0); - return Err(js_error); - } - - self.modules.borrow_mut().register(id, &name); - - Ok(id) + self.inner.execute(js_filename, js_source) } // TODO(ry) make this return a future. - pub fn mod_load_deps( - &mut self, - id: libdeno::deno_mod, - ) -> Result<(), RustOrJsError> { + fn mod_load_deps(&self, id: deno_mod) -> Result<(), RustOrJsError> { // basically iterate over the imports, start loading them. - let referrer_name = - { self.modules.borrow_mut().get_name(id).unwrap().clone() }; - let len = - unsafe { libdeno::deno_mod_imports_len(self.libdeno_isolate, id) }; - - for i in 0..len { - let specifier_ptr = - unsafe { libdeno::deno_mod_imports_get(self.libdeno_isolate, id, i) }; - let specifier_c: &CStr = unsafe { CStr::from_ptr(specifier_ptr) }; - let specifier: &str = specifier_c.to_str().unwrap(); + let referrer_name = { + let g = self.state.modules.lock().unwrap(); + g.get_name(id).unwrap().clone() + }; + for specifier in self.inner.mod_get_imports(id) { let (name, _local_filename) = self .state .dir - .resolve_module(specifier, &referrer_name) + .resolve_module(&specifier, &referrer_name) .map_err(DenoError::from) .map_err(RustOrJsError::from)?; - debug!("mod_load_deps {} {}", i, name); + debug!("mod_load_deps {}", name); - if !self.modules.borrow_mut().is_registered(&name) { + if !self.state.modules.lock().unwrap().is_registered(&name) { let out = fetch_module_meta_data_and_maybe_compile( &self.state, - specifier, + &specifier, &referrer_name, )?; - let child_id = - self.mod_new(false, out.module_name.clone(), out.js_source())?; + let child_id = self.mod_new_and_register( + false, + &out.module_name.clone(), + &out.js_source(), + )?; self.mod_load_deps(child_id)?; } @@ -356,140 +85,77 @@ impl Isolate { Ok(()) } - pub fn mod_instantiate(&self, id: libdeno::deno_mod) -> Result<(), JSError> { - unsafe { - libdeno::deno_mod_instantiate( - self.libdeno_isolate, - self.as_raw_ptr(), - id, - resolve_cb, - ) - }; - if let Some(js_error) = self.last_exception() { - return Err(js_error); - } - - Ok(()) - } - - pub fn mod_evaluate(&self, id: libdeno::deno_mod) -> Result<(), JSError> { - unsafe { - libdeno::deno_mod_evaluate(self.libdeno_isolate, self.as_raw_ptr(), id) - }; - if let Some(js_error) = self.last_exception() { - return Err(js_error); - } - Ok(()) - } - /// Executes the provided JavaScript module. pub fn execute_mod( &mut self, js_filename: &str, is_prefetch: bool, ) -> Result<(), RustOrJsError> { - let out = - fetch_module_meta_data_and_maybe_compile(&self.state, js_filename, ".") - .map_err(RustOrJsError::from)?; + // TODO move isolate_state::execute_mod impl here. + self + .execute_mod_inner(js_filename, is_prefetch) + .map_err(|err| match err { + RustOrJsError::Js(err) => RustOrJsError::Js(self.apply_source_map(err)), + x => x, + }) + } + + /// High-level way to execute modules. + /// This will issue HTTP requests and file system calls. + /// Blocks. TODO(ry) Don't block. + fn execute_mod_inner( + &mut self, + url: &str, + is_prefetch: bool, + ) -> Result<(), RustOrJsError> { + let out = fetch_module_meta_data_and_maybe_compile(&self.state, url, ".") + .map_err(RustOrJsError::from)?; let id = self - .mod_new(true, out.module_name.clone(), out.js_source()) + .mod_new_and_register(true, &out.module_name.clone(), &out.js_source()) .map_err(RustOrJsError::from)?; self.mod_load_deps(id)?; - self.mod_instantiate(id).map_err(RustOrJsError::from)?; + self + .inner + .mod_instantiate(id) + .map_err(RustOrJsError::from)?; if !is_prefetch { - self.mod_evaluate(id).map_err(RustOrJsError::from)?; - } - Ok(()) - } - - pub fn respond(&self, zero_copy_id: usize, buf: Buf) { - self.state.metrics_op_completed(buf.len()); - - // This will be cleaned up in the future. - if zero_copy_id > 0 { - unsafe { - libdeno::deno_zero_copy_release(self.libdeno_isolate, zero_copy_id) - } - } - - // deno_respond will memcpy the buf into V8's heap, - // so borrowing a reference here is sufficient. - unsafe { - libdeno::deno_respond( - self.libdeno_isolate, - self.as_raw_ptr(), - buf.as_ref().into(), - ) - } - } - - fn complete_op(&self, zero_copy_id: usize, buf: Buf) { - // Receiving a message on rx exactly corresponds to an async task - // completing. - self.ntasks_decrement(); - // Call into JS with the buf. - self.respond(zero_copy_id, buf); - } - - fn timeout(&self) { - let dummy_buf = libdeno::deno_buf::empty(); - unsafe { - libdeno::deno_respond(self.libdeno_isolate, self.as_raw_ptr(), dummy_buf) - } - } - - fn check_promise_errors(&self) { - unsafe { - libdeno::deno_check_promise_errors(self.libdeno_isolate); - } - } - - // TODO Use Park abstraction? Note at time of writing Tokio default runtime - // does not have new_with_park(). - pub fn event_loop(&self) -> Result<(), JSError> { - // Main thread event loop. - while !self.is_idle() { - match self.rx.recv() { - Ok((zero_copy_id, buf)) => self.complete_op(zero_copy_id, buf), - Err(e) => panic!("Isolate.rx.recv() failed: {:?}", e), - } - self.check_promise_errors(); - if let Some(err) = self.last_exception() { - return Err(err); - } - } - // Check on done - self.check_promise_errors(); - if let Some(err) = self.last_exception() { - return Err(err); + self.inner.mod_evaluate(id).map_err(RustOrJsError::from)?; } Ok(()) } - #[inline] - fn ntasks_increment(&self) { - assert!(self.ntasks.get() >= 0); - self.ntasks.set(self.ntasks.get() + 1); + /// Wraps Isolate::mod_new but registers with modules. + fn mod_new_and_register( + &self, + main: bool, + name: &str, + source: &str, + ) -> Result<deno_mod, JSError> { + let id = self.inner.mod_new(main, name, source)?; + self.state.modules.lock().unwrap().register(id, &name); + Ok(id) } - #[inline] - fn ntasks_decrement(&self) { - self.ntasks.set(self.ntasks.get() - 1); - assert!(self.ntasks.get() >= 0); + pub fn print_file_info(&self, module: &str) { + let m = self.state.modules.lock().unwrap(); + m.print_file_info(&self.state.dir, module.to_string()); } - #[inline] - fn is_idle(&self) -> bool { - self.ntasks.get() == 0 + /// Applies source map to the error. + fn apply_source_map(&self, err: JSError) -> JSError { + js_errors::apply_source_map(&err, &self.state.dir) } } -impl Drop for Isolate { - fn drop(&mut self) { - unsafe { libdeno::deno_delete(self.libdeno_isolate) } +impl Future for Isolate { + type Item = (); + type Error = JSError; + + fn poll(&mut self) -> Result<Async<()>, Self::Error> { + self.inner.poll().map_err(|err| self.apply_source_map(err)) } } @@ -511,308 +177,69 @@ fn fetch_module_meta_data_and_maybe_compile( Ok(out) } -extern "C" fn resolve_cb( - user_data: *mut c_void, - specifier_ptr: *const c_char, - referrer: libdeno::deno_mod, -) -> libdeno::deno_mod { - let isolate = unsafe { Isolate::from_raw_ptr(user_data) }; - let specifier_c: &CStr = unsafe { CStr::from_ptr(specifier_ptr) }; - let specifier: &str = specifier_c.to_str().unwrap(); - isolate - .state - .metrics - .resolve_count - .fetch_add(1, Ordering::Relaxed); - isolate.modules.borrow_mut().resolve_cb( - &isolate.state.dir, - specifier, - referrer, - ) -} - -// Dereferences the C pointer into the Rust Isolate object. -extern "C" fn pre_dispatch( - user_data: *mut c_void, - control_buf: libdeno::deno_buf, - zero_copy_buf: libdeno::deno_buf, -) { - // for metrics - let bytes_sent_control = control_buf.len(); - let bytes_sent_zero_copy = zero_copy_buf.len(); - - let zero_copy_id = zero_copy_buf.zero_copy_id; - - // We should ensure that there is no other `&mut Isolate` exists. - // And also, it should be in the same thread with other `&Isolate`s. - let isolate = unsafe { Isolate::from_raw_ptr(user_data) }; - let dispatch = isolate.dispatch; - let (is_sync, op) = dispatch(isolate, control_buf, zero_copy_buf); - - isolate - .state - .metrics_op_dispatched(bytes_sent_control, bytes_sent_zero_copy); - - if is_sync { - // Execute op synchronously. - let buf = tokio_util::block_on(op).unwrap(); - let buf_size = buf.len(); - - if buf_size == 0 { - // FIXME - isolate.state.metrics_op_completed(buf.len()); - } else { - // Set the synchronous response, the value returned from isolate.send(). - isolate.respond(zero_copy_id, buf); - } - } else { - // Execute op asynchronously. - let tx = isolate.tx.clone(); - - // TODO Ideally Tokio would could tell us how many tasks are executing, but - // it cannot currently. Therefore we track top-level promises/tasks - // manually. - isolate.ntasks_increment(); - - let task = op - .and_then(move |buf| { - let sender = tx; // tx is moved to new thread - sender.send((zero_copy_id, buf)).expect("tx.send error"); - Ok(()) - }).map_err(|_| ()); - tokio::spawn(task); - } -} - #[cfg(test)] mod tests { use super::*; - use futures; - - #[test] - fn test_dispatch_sync() { - let state = IsolateState::mock(); - let init = IsolateInit { - snapshot: None, - init_script: None, - }; - let isolate = - Isolate::new(init, state, dispatch_sync, DenoPermissions::default()); - tokio_util::init(|| { - isolate - .execute( - r#" - const m = new Uint8Array([4, 5, 6]); - let n = libdeno.send(m); - if (!(n.byteLength === 3 && - n[0] === 1 && - n[1] === 2 && - n[2] === 3)) { - throw Error("assert error"); - } - "#, - ).expect("execute error"); - isolate.event_loop().ok(); - }); - } - - fn dispatch_sync( - _isolate: &Isolate, - control: libdeno::deno_buf, - data: libdeno::deno_buf, - ) -> (bool, Box<Op>) { - assert_eq!(control[0], 4); - assert_eq!(control[1], 5); - assert_eq!(control[2], 6); - assert_eq!(data.len(), 0); - // Send back some sync response. - let vec: Vec<u8> = vec![1, 2, 3]; - let control = vec.into_boxed_slice(); - let op = Box::new(futures::future::ok(control)); - (true, op) - } - - #[test] - fn test_metrics_sync() { - let state = IsolateState::mock(); - let init = IsolateInit { - snapshot: None, - init_script: None, - }; - let isolate = Isolate::new( - init, - state, - metrics_dispatch_sync, - DenoPermissions::default(), - ); - tokio_util::init(|| { - // Verify that metrics have been properly initialized. - { - let metrics = &isolate.state.metrics; - assert_eq!(metrics.ops_dispatched.load(Ordering::SeqCst), 0); - assert_eq!(metrics.ops_completed.load(Ordering::SeqCst), 0); - assert_eq!(metrics.bytes_sent_control.load(Ordering::SeqCst), 0); - assert_eq!(metrics.bytes_sent_data.load(Ordering::SeqCst), 0); - assert_eq!(metrics.bytes_received.load(Ordering::SeqCst), 0); - } - - isolate - .execute( - r#" - const control = new Uint8Array([4, 5, 6]); - const data = new Uint8Array([42, 43, 44, 45, 46]); - libdeno.send(control, data); - "#, - ).expect("execute error");; - isolate.event_loop().unwrap(); - let metrics = &isolate.state.metrics; - assert_eq!(metrics.ops_dispatched.load(Ordering::SeqCst), 1); - assert_eq!(metrics.ops_completed.load(Ordering::SeqCst), 1); - assert_eq!(metrics.bytes_sent_control.load(Ordering::SeqCst), 3); - assert_eq!(metrics.bytes_sent_data.load(Ordering::SeqCst), 5); - assert_eq!(metrics.bytes_received.load(Ordering::SeqCst), 4); - }); - } - - #[test] - fn test_metrics_async() { - let state = IsolateState::mock(); - let init = IsolateInit { - snapshot: None, - init_script: None, - }; - let isolate = Isolate::new( - init, - state, - metrics_dispatch_async, - DenoPermissions::default(), - ); - tokio_util::init(|| { - // Verify that metrics have been properly initialized. - { - let metrics = &isolate.state.metrics; - assert_eq!(metrics.ops_dispatched.load(Ordering::SeqCst), 0); - assert_eq!(metrics.ops_completed.load(Ordering::SeqCst), 0); - assert_eq!(metrics.bytes_sent_control.load(Ordering::SeqCst), 0); - assert_eq!(metrics.bytes_sent_data.load(Ordering::SeqCst), 0); - assert_eq!(metrics.bytes_received.load(Ordering::SeqCst), 0); - } - - isolate - .execute( - r#" - const control = new Uint8Array([4, 5, 6]); - const data = new Uint8Array([42, 43, 44, 45, 46]); - let r = libdeno.send(control, data); - libdeno.recv(() => {}); - if (r != null) throw Error("expected null"); - "#, - ).expect("execute error"); - - // Make sure relevant metrics are updated before task is executed. - { - let metrics = &isolate.state.metrics; - assert_eq!(metrics.ops_dispatched.load(Ordering::SeqCst), 1); - assert_eq!(metrics.bytes_sent_control.load(Ordering::SeqCst), 3); - assert_eq!(metrics.bytes_sent_data.load(Ordering::SeqCst), 5); - // Note we cannot check ops_completed nor bytes_received because that - // would be a race condition. It might be nice to have use a oneshot - // with metrics_dispatch_async() to properly validate them. - } - - isolate.event_loop().unwrap(); - - // Make sure relevant metrics are updated after task is executed. - { - let metrics = &isolate.state.metrics; - assert_eq!(metrics.ops_dispatched.load(Ordering::SeqCst), 1); - assert_eq!(metrics.ops_completed.load(Ordering::SeqCst), 1); - assert_eq!(metrics.bytes_sent_control.load(Ordering::SeqCst), 3); - assert_eq!(metrics.bytes_sent_data.load(Ordering::SeqCst), 5); - assert_eq!(metrics.bytes_received.load(Ordering::SeqCst), 4); - } - }); - } - - fn metrics_dispatch_sync( - _isolate: &Isolate, - _control: libdeno::deno_buf, - _data: libdeno::deno_buf, - ) -> (bool, Box<Op>) { - // Send back some sync response - let vec: Box<[u8]> = vec![1, 2, 3, 4].into_boxed_slice(); - let op = Box::new(futures::future::ok(vec)); - (true, op) - } - - fn metrics_dispatch_async( - _isolate: &Isolate, - _control: libdeno::deno_buf, - _data: libdeno::deno_buf, - ) -> (bool, Box<Op>) { - // Send back some sync response - let vec: Box<[u8]> = vec![1, 2, 3, 4].into_boxed_slice(); - let op = Box::new(futures::future::ok(vec)); - (false, op) - } - - #[test] - fn thread_safety() { - fn is_thread_safe<T: Sync + Send>() {} - is_thread_safe::<IsolateState>(); - } + use crate::flags; + use crate::isolate_init::IsolateInit; + use crate::permissions::DenoPermissions; + use crate::tokio_util; + use futures::future::lazy; + use std::sync::atomic::Ordering; #[test] fn execute_mod() { let filename = std::env::current_dir() .unwrap() .join("tests/esm_imports_a.js"); - let filename = filename.to_str().unwrap(); + let filename = filename.to_str().unwrap().to_string(); - let argv = vec![String::from("./deno"), String::from(filename)]; + let argv = vec![String::from("./deno"), filename.clone()]; let (flags, rest_argv, _) = flags::set_flags(argv).unwrap(); let state = Arc::new(IsolateState::new(flags, rest_argv, None)); + let state_ = state.clone(); let init = IsolateInit { snapshot: None, init_script: None, }; - let mut isolate = - Isolate::new(init, state, dispatch_sync, DenoPermissions::default()); - tokio_util::init(|| { - isolate - .execute_mod(filename, false) - .expect("execute_mod error"); - isolate.event_loop().ok(); - }); - - let metrics = &isolate.state.metrics; + tokio_util::run(lazy(move || { + let cli = Cli::new(init, state.clone(), DenoPermissions::default()); + let mut isolate = Isolate::new(cli); + if let Err(err) = isolate.execute_mod(&filename, false) { + eprintln!("execute_mod err {:?}", err); + } + tokio_util::panic_on_error(isolate) + })); + + let metrics = &state_.metrics; assert_eq!(metrics.resolve_count.load(Ordering::SeqCst), 1); } #[test] fn execute_mod_circular() { let filename = std::env::current_dir().unwrap().join("tests/circular1.js"); - let filename = filename.to_str().unwrap(); + let filename = filename.to_str().unwrap().to_string(); - let argv = vec![String::from("./deno"), String::from(filename)]; + let argv = vec![String::from("./deno"), filename.clone()]; let (flags, rest_argv, _) = flags::set_flags(argv).unwrap(); let state = Arc::new(IsolateState::new(flags, rest_argv, None)); + let state_ = state.clone(); let init = IsolateInit { snapshot: None, init_script: None, }; - let mut isolate = - Isolate::new(init, state, dispatch_sync, DenoPermissions::default()); - tokio_util::init(|| { - isolate - .execute_mod(filename, false) - .expect("execute_mod error"); - isolate.event_loop().ok(); - }); - - let metrics = &isolate.state.metrics; + tokio_util::run(lazy(move || { + let cli = Cli::new(init, state.clone(), DenoPermissions::default()); + let mut isolate = Isolate::new(cli); + if let Err(err) = isolate.execute_mod(&filename, false) { + eprintln!("execute_mod err {:?}", err); + } + tokio_util::panic_on_error(isolate) + })); + + let metrics = &state_.metrics; assert_eq!(metrics.resolve_count.load(Ordering::SeqCst), 2); } } diff --git a/src/isolate_init.rs b/src/isolate_init.rs index 49fa0d96a..fbdfdd4a5 100644 --- a/src/isolate_init.rs +++ b/src/isolate_init.rs @@ -1,5 +1,5 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -use crate::libdeno::deno_buf; +use deno_core::deno_buf; pub struct IsolateInitScript { pub source: String, diff --git a/src/isolate_state.rs b/src/isolate_state.rs new file mode 100644 index 000000000..4cc010389 --- /dev/null +++ b/src/isolate_state.rs @@ -0,0 +1,110 @@ +// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. +use crate::cli::Buf; +use crate::deno_dir; +use crate::flags; +use crate::global_timer::GlobalTimer; +use crate::modules::Modules; +use futures::sync::mpsc as async_mpsc; +use std; +use std::env; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Mutex; + +pub type WorkerSender = async_mpsc::Sender<Buf>; +pub type WorkerReceiver = async_mpsc::Receiver<Buf>; +pub type WorkerChannels = (WorkerSender, WorkerReceiver); + +// AtomicU64 is currently unstable +#[derive(Default)] +pub struct Metrics { + pub ops_dispatched: AtomicUsize, + pub ops_completed: AtomicUsize, + pub bytes_sent_control: AtomicUsize, + pub bytes_sent_data: AtomicUsize, + pub bytes_received: AtomicUsize, + pub resolve_count: AtomicUsize, +} + +// Isolate cannot be passed between threads but IsolateState can. +// IsolateState satisfies Send and Sync. +// So any state that needs to be accessed outside the main V8 thread should be +// inside IsolateState. +#[cfg_attr(feature = "cargo-clippy", allow(stutter))] +pub struct IsolateState { + pub dir: deno_dir::DenoDir, + pub argv: Vec<String>, + pub flags: flags::DenoFlags, + pub metrics: Metrics, + pub modules: Mutex<Modules>, + pub worker_channels: Option<Mutex<WorkerChannels>>, + pub global_timer: Mutex<GlobalTimer>, +} + +impl IsolateState { + pub fn new( + flags: flags::DenoFlags, + argv_rest: Vec<String>, + worker_channels: Option<WorkerChannels>, + ) -> Self { + let custom_root = env::var("DENO_DIR").map(|s| s.into()).ok(); + + Self { + dir: deno_dir::DenoDir::new(flags.reload, flags.recompile, custom_root) + .unwrap(), + argv: argv_rest, + flags, + metrics: Metrics::default(), + modules: Mutex::new(Modules::new()), + worker_channels: worker_channels.map(Mutex::new), + global_timer: Mutex::new(GlobalTimer::new()), + } + } + + pub fn main_module(&self) -> Option<String> { + if self.argv.len() <= 1 { + None + } else { + let specifier = self.argv[1].clone(); + let referrer = "."; + match self.dir.resolve_module_url(&specifier, referrer) { + Ok(url) => Some(url.to_string()), + Err(e) => { + debug!("Potentially swallowed error {}", e); + None + } + } + } + } + + #[cfg(test)] + pub fn mock() -> IsolateState { + let argv = vec![String::from("./deno"), String::from("hello.js")]; + // For debugging: argv.push_back(String::from("-D")); + let (flags, rest_argv, _) = flags::set_flags(argv).unwrap(); + IsolateState::new(flags, rest_argv, None) + } + + pub fn metrics_op_dispatched( + &self, + bytes_sent_control: usize, + bytes_sent_data: usize, + ) { + self.metrics.ops_dispatched.fetch_add(1, Ordering::SeqCst); + self + .metrics + .bytes_sent_control + .fetch_add(bytes_sent_control, Ordering::SeqCst); + self + .metrics + .bytes_sent_data + .fetch_add(bytes_sent_data, Ordering::SeqCst); + } + + pub fn metrics_op_completed(&self, bytes_received: usize) { + self.metrics.ops_completed.fetch_add(1, Ordering::SeqCst); + self + .metrics + .bytes_received + .fetch_add(bytes_received, Ordering::SeqCst); + } +} diff --git a/src/js_errors.rs b/src/js_errors.rs index f42d9cb51..90c9f2007 100644 --- a/src/js_errors.rs +++ b/src/js_errors.rs @@ -206,36 +206,41 @@ pub fn apply_source_map( } } -fn parse_map_string( - script_name: &str, - getter: &dyn SourceMapGetter, -) -> Option<SourceMap> { +// The bundle does not get built for 'cargo check', so we don't embed the +// bundle source map. +#[cfg(feature = "check-only")] +fn builtin_source_map(script_name: &str) -> Option<Vec<u8>> { + None +} + +#[cfg(not(feature = "check-only"))] +fn builtin_source_map(script_name: &str) -> Option<Vec<u8>> { match script_name { - // The bundle does not get built for 'cargo check', so we don't embed the - // bundle source map. - #[cfg(not(feature = "check-only"))] - "gen/bundle/main.js" => { - let s = - include_str!(concat!(env!("GN_OUT_DIR"), "/gen/bundle/main.js.map")); - SourceMap::from_json(s) - } - #[cfg(not(feature = "check-only"))] - "gen/bundle/compiler.js" => { - let s = include_str!(concat!( + "gen/bundle/main.js" => Some( + include_bytes!(concat!(env!("GN_OUT_DIR"), "/gen/bundle/main.js.map")) + .to_vec(), + ), + "gen/bundle/compiler.js" => Some( + include_bytes!(concat!( env!("GN_OUT_DIR"), "/gen/bundle/compiler.js.map" - )); - SourceMap::from_json(s) - } - _ => match getter.get_source_map(script_name) { - None => None, - Some(raw_source_map) => { - SourceMap::from_json(str::from_utf8(&raw_source_map).unwrap()) - } - }, + )).to_vec(), + ), + _ => None, } } +fn parse_map_string( + script_name: &str, + getter: &dyn SourceMapGetter, +) -> Option<SourceMap> { + builtin_source_map(script_name) + .or_else(|| getter.get_source_map(script_name)) + .and_then(|raw_source_map| { + SourceMap::from_json(str::from_utf8(&raw_source_map).unwrap()) + }) +} + fn get_mappings<'a>( script_name: &str, mappings_map: &'a mut CachedMaps, diff --git a/src/libdeno.rs b/src/libdeno.rs deleted file mode 100644 index 6696a382b..000000000 --- a/src/libdeno.rs +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. - -// TODO Remove. While core is being developed, it may not use the complete -// libdeno API. Thus we allow dead code until things settle. -#![allow(dead_code)] - -use libc::c_char; -use libc::c_int; -use libc::c_void; -use libc::size_t; -use std::ops::{Deref, DerefMut}; -use std::ptr::null; - -// TODO(F001): change this definition to `extern { pub type isolate; }` -// After RFC 1861 is stablized. See https://github.com/rust-lang/rust/issues/43467. -#[repr(C)] -pub struct isolate { - _unused: [u8; 0], -} - -/// If "alloc_ptr" is not null, this type represents a buffer which is created -/// in C side, and then passed to Rust side by `deno_recv_cb`. Finally it should -/// be moved back to C side by `deno_respond`. If it is not passed to -/// `deno_respond` in the end, it will be leaked. -/// -/// If "alloc_ptr" is null, this type represents a borrowed slice. -#[repr(C)] -pub struct deno_buf { - alloc_ptr: *const u8, - alloc_len: usize, - data_ptr: *const u8, - data_len: usize, - pub zero_copy_id: usize, -} - -/// `deno_buf` can not clone, and there is no interior mutability. -/// This type satisfies Send bound. -unsafe impl Send for deno_buf {} - -impl deno_buf { - #[inline] - pub fn empty() -> Self { - Self { - alloc_ptr: null(), - alloc_len: 0, - data_ptr: null(), - data_len: 0, - zero_copy_id: 0, - } - } - - #[inline] - pub unsafe fn from_raw_parts(ptr: *const u8, len: usize) -> Self { - Self { - alloc_ptr: null(), - alloc_len: 0, - data_ptr: ptr, - data_len: len, - zero_copy_id: 0, - } - } -} - -/// Converts Rust &Buf to libdeno `deno_buf`. -impl<'a> From<&'a [u8]> for deno_buf { - #[inline] - fn from(x: &'a [u8]) -> Self { - Self { - alloc_ptr: null(), - alloc_len: 0, - data_ptr: x.as_ref().as_ptr(), - data_len: x.len(), - zero_copy_id: 0, - } - } -} - -impl Deref for deno_buf { - type Target = [u8]; - #[inline] - fn deref(&self) -> &[u8] { - unsafe { std::slice::from_raw_parts(self.data_ptr, self.data_len) } - } -} - -impl DerefMut for deno_buf { - #[inline] - fn deref_mut(&mut self) -> &mut [u8] { - unsafe { - if self.alloc_ptr.is_null() { - panic!("Can't modify the buf"); - } - std::slice::from_raw_parts_mut(self.data_ptr as *mut u8, self.data_len) - } - } -} - -impl AsRef<[u8]> for deno_buf { - #[inline] - fn as_ref(&self) -> &[u8] { - &*self - } -} - -impl AsMut<[u8]> for deno_buf { - #[inline] - fn as_mut(&mut self) -> &mut [u8] { - if self.alloc_ptr.is_null() { - panic!("Can't modify the buf"); - } - &mut *self - } -} - -#[allow(non_camel_case_types)] -type deno_recv_cb = unsafe extern "C" fn( - user_data: *mut c_void, - control_buf: deno_buf, // deprecated - zero_copy_buf: deno_buf, -); - -#[allow(non_camel_case_types)] -pub type deno_mod = i32; - -#[allow(non_camel_case_types)] -type deno_resolve_cb = unsafe extern "C" fn( - user_data: *mut c_void, - specifier: *const c_char, - referrer: deno_mod, -) -> deno_mod; - -#[repr(C)] -pub struct deno_config { - pub will_snapshot: c_int, - pub load_snapshot: deno_buf, - pub shared: deno_buf, - pub recv_cb: deno_recv_cb, -} - -extern "C" { - pub fn deno_init(); - pub fn deno_v8_version() -> *const c_char; - pub fn deno_set_v8_flags(argc: *mut c_int, argv: *mut *mut c_char); - pub fn deno_new(config: deno_config) -> *const isolate; - pub fn deno_delete(i: *const isolate); - pub fn deno_last_exception(i: *const isolate) -> *const c_char; - pub fn deno_check_promise_errors(i: *const isolate); - pub fn deno_lock(i: *const isolate); - pub fn deno_unlock(i: *const isolate); - pub fn deno_respond( - i: *const isolate, - user_data: *const c_void, - buf: deno_buf, - ); - pub fn deno_zero_copy_release(i: *const isolate, zero_copy_id: usize); - pub fn deno_execute( - i: *const isolate, - user_data: *const c_void, - js_filename: *const c_char, - js_source: *const c_char, - ); - - // Modules - - pub fn deno_mod_new( - i: *const isolate, - main: bool, - name: *const c_char, - source: *const c_char, - ) -> deno_mod; - - pub fn deno_mod_imports_len(i: *const isolate, id: deno_mod) -> size_t; - - pub fn deno_mod_imports_get( - i: *const isolate, - id: deno_mod, - index: size_t, - ) -> *const c_char; - - pub fn deno_mod_instantiate( - i: *const isolate, - user_data: *const c_void, - id: deno_mod, - resolve_cb: deno_resolve_cb, - ); - - pub fn deno_mod_evaluate( - i: *const isolate, - user_data: *const c_void, - id: deno_mod, - ); -} diff --git a/src/main.rs b/src/main.rs index 7bafe5c3c..9afbbb8a9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ extern crate futures; extern crate serde_json; mod ansi; +pub mod cli; pub mod compiler; pub mod deno_dir; pub mod errors; @@ -19,8 +20,8 @@ mod http_body; mod http_util; pub mod isolate; pub mod isolate_init; +pub mod isolate_state; pub mod js_errors; -pub mod libdeno; pub mod modules; pub mod msg; pub mod msg_util; @@ -37,6 +38,12 @@ pub mod workers; #[cfg(unix)] mod eager_unix; +use crate::cli::Cli; +use crate::errors::RustOrJsError; +use crate::isolate::Isolate; +use crate::isolate_state::IsolateState; +use futures::lazy; +use futures::Future; use log::{LevelFilter, Metadata, Record}; use std::env; use std::sync::Arc; @@ -58,11 +65,20 @@ impl log::Log for Logger { fn flush(&self) {} } -fn print_err_and_exit(err: errors::RustOrJsError) { +fn print_err_and_exit(err: RustOrJsError) { eprintln!("{}", err.to_string()); std::process::exit(1); } +fn js_check<E>(r: Result<(), E>) +where + E: Into<RustOrJsError>, +{ + if let Err(err) = r { + print_err_and_exit(err.into()); + } +} + fn main() { #[cfg(windows)] ansi_term::enable_ansi_support().ok(); // For Windows 10 @@ -95,39 +111,33 @@ fn main() { let should_prefetch = flags.prefetch || flags.info; let should_display_info = flags.info; - let state = Arc::new(isolate::IsolateState::new(flags, rest_argv, None)); + let state = Arc::new(IsolateState::new(flags, rest_argv, None)); + let state_ = state.clone(); let isolate_init = isolate_init::deno_isolate_init(); let permissions = permissions::DenoPermissions::from_flags(&state.flags); - let mut isolate = - isolate::Isolate::new(isolate_init, state, ops::dispatch, permissions); + let cli = Cli::new(isolate_init, state_, permissions); + let mut isolate = Isolate::new(cli); - tokio_util::init(|| { + let main_future = lazy(move || { // Setup runtime. - isolate - .execute("denoMain();") - .map_err(errors::RustOrJsError::from) - .unwrap_or_else(print_err_and_exit); + js_check(isolate.execute("denoMain()")); // Execute main module. - if let Some(main_module) = isolate.state.main_module() { + if let Some(main_module) = state.main_module() { debug!("main_module {}", main_module); - isolate - .execute_mod(&main_module, should_prefetch) - .unwrap_or_else(print_err_and_exit); + js_check(isolate.execute_mod(&main_module, should_prefetch)); if should_display_info { // Display file info and exit. Do not run file - modules::print_file_info( - &isolate.modules.borrow(), - &isolate.state.dir, - main_module, - ); + isolate.print_file_info(&main_module); std::process::exit(0); } } - isolate - .event_loop() - .map_err(errors::RustOrJsError::from) - .unwrap_or_else(print_err_and_exit); + isolate.then(|result| { + js_check(result); + Ok(()) + }) }); + + tokio_util::run(main_future); } diff --git a/src/modules.rs b/src/modules.rs index 67be47dd4..908c31b6d 100644 --- a/src/modules.rs +++ b/src/modules.rs @@ -1,8 +1,8 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. use crate::ansi; use crate::deno_dir::DenoDir; -use crate::libdeno::deno_mod; use crate::msg; +use deno_core::deno_mod; use std::collections::HashMap; use std::collections::HashSet; use std::fmt; @@ -86,6 +86,44 @@ impl Modules { return 0; } } + + pub fn print_file_info(&self, deno_dir: &DenoDir, filename: String) { + let maybe_out = deno_dir.fetch_module_meta_data(&filename, "."); + if maybe_out.is_err() { + println!("{}", maybe_out.unwrap_err()); + return; + } + let out = maybe_out.unwrap(); + + println!("{} {}", ansi::bold("local:".to_string()), &(out.filename)); + println!( + "{} {}", + ansi::bold("type:".to_string()), + msg::enum_name_media_type(out.media_type) + ); + if out.maybe_output_code_filename.is_some() { + println!( + "{} {}", + ansi::bold("compiled:".to_string()), + out.maybe_output_code_filename.as_ref().unwrap(), + ); + } + if out.maybe_source_map_filename.is_some() { + println!( + "{} {}", + ansi::bold("map:".to_string()), + out.maybe_source_map_filename.as_ref().unwrap() + ); + } + + let deps = Deps::new(self, &out.module_name); + println!("{}{}", ansi::bold("deps:\n".to_string()), deps.name); + if let Some(ref depsdeps) = deps.deps { + for d in depsdeps { + println!("{}", d); + } + } + } } pub struct Deps { @@ -164,45 +202,3 @@ impl fmt::Display for Deps { Ok(()) } } - -pub fn print_file_info( - modules: &Modules, - deno_dir: &DenoDir, - filename: String, -) { - let maybe_out = deno_dir.fetch_module_meta_data(&filename, "."); - if maybe_out.is_err() { - println!("{}", maybe_out.unwrap_err()); - return; - } - let out = maybe_out.unwrap(); - - println!("{} {}", ansi::bold("local:".to_string()), &(out.filename)); - println!( - "{} {}", - ansi::bold("type:".to_string()), - msg::enum_name_media_type(out.media_type) - ); - if out.maybe_output_code_filename.is_some() { - println!( - "{} {}", - ansi::bold("compiled:".to_string()), - out.maybe_output_code_filename.as_ref().unwrap(), - ); - } - if out.maybe_source_map_filename.is_some() { - println!( - "{} {}", - ansi::bold("map:".to_string()), - out.maybe_source_map_filename.as_ref().unwrap() - ); - } - - let deps = Deps::new(modules, &out.module_name); - println!("{}{}", ansi::bold("deps:\n".to_string()), deps.name); - if let Some(ref depsdeps) = deps.deps { - for d in depsdeps { - println!("{}", d); - } - } -} diff --git a/src/msg.fbs b/src/msg.fbs index 279264a45..243034cfb 100644 --- a/src/msg.fbs +++ b/src/msg.fbs @@ -139,13 +139,6 @@ enum MediaType: byte { Unknown } -table Shared { - lock: bool; - head: int; - tail: int; - ring: [Base]; -} - table Base { cmd_id: uint32; sync: bool = false; diff --git a/src/msg.rs b/src/msg.rs index 74027d3d6..080f39de8 100644 --- a/src/msg.rs +++ b/src/msg.rs @@ -5,6 +5,7 @@ feature = "cargo-clippy", allow(clippy::all, clippy::pedantic) )] +use crate::isolate_state; use flatbuffers; use std::sync::atomic::Ordering; @@ -12,8 +13,8 @@ use std::sync::atomic::Ordering; // build_extra/rust/run.py (for the GN+Ninja build). include!(concat!(env!("GN_OUT_DIR"), "/gen/msg_generated.rs")); -impl<'a> From<&'a super::isolate::Metrics> for MetricsResArgs { - fn from(m: &'a super::isolate::Metrics) -> Self { +impl<'a> From<&'a isolate_state::Metrics> for MetricsResArgs { + fn from(m: &'a isolate_state::Metrics) -> Self { MetricsResArgs { ops_dispatched: m.ops_dispatched.load(Ordering::SeqCst) as u64, ops_completed: m.ops_completed.load(Ordering::SeqCst) as u64, diff --git a/src/ops.rs b/src/ops.rs index 495540b22..33a7d7cdd 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -1,18 +1,15 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. - use atty; use crate::ansi; +use crate::cli::Buf; +use crate::cli::Cli; use crate::errors; use crate::errors::{permission_denied, DenoError, DenoResult, ErrorKind}; use crate::fs as deno_fs; use crate::http_util; -use crate::isolate::Buf; -use crate::isolate::Isolate; -use crate::isolate::IsolateState; -use crate::isolate::Op; +use crate::isolate_state::IsolateState; use crate::js_errors::apply_source_map; use crate::js_errors::JSErrorColor; -use crate::libdeno; use crate::msg; use crate::msg_util; use crate::repl; @@ -22,7 +19,9 @@ use crate::resources::table_entries; use crate::resources::Resource; use crate::tokio_util; use crate::version; +use deno_core::deno_buf; use deno_core::JSError; +use deno_core::Op; use flatbuffers::FlatBufferBuilder; use futures; use futures::Async; @@ -54,11 +53,12 @@ use std::os::unix::process::ExitStatusExt; type OpResult = DenoResult<Buf>; -// TODO Ideally we wouldn't have to box the Op being returned. +pub type OpWithError = dyn Future<Item = Buf, Error = DenoError> + Send; + +// TODO Ideally we wouldn't have to box the OpWithError being returned. // The box is just to make it easier to get a prototype refactor working. type OpCreator = - fn(isolate: &Isolate, base: &msg::Base<'_>, data: libdeno::deno_buf) - -> Box<Op>; + fn(cli: &Cli, base: &msg::Base<'_>, data: deno_buf) -> Box<OpWithError>; #[inline] fn empty_buf() -> Buf { @@ -70,16 +70,18 @@ fn empty_buf() -> Buf { /// control corresponds to the first argument of libdeno.send(). /// data corresponds to the second argument of libdeno.send(). pub fn dispatch( - isolate: &Isolate, - control: libdeno::deno_buf, - data: libdeno::deno_buf, + cli: &Cli, + control: &[u8], + zero_copy: deno_buf, ) -> (bool, Box<Op>) { + let bytes_sent_control = control.len(); + let bytes_sent_zero_copy = zero_copy.len(); let base = msg::get_root_as_base(&control); let is_sync = base.sync(); let inner_type = base.inner_type(); let cmd_id = base.cmd_id(); - let op: Box<Op> = { + let op: Box<OpWithError> = { // Handle regular ops. let op_creator: OpCreator = match inner_type { msg::Any::Accept => op_accept, @@ -132,11 +134,16 @@ pub fn dispatch( msg::enum_name_any(inner_type) )), }; - op_creator(&isolate, &base, data) + op_creator(&cli, &base, zero_copy) }; + cli + .state + .metrics_op_dispatched(bytes_sent_control, bytes_sent_zero_copy); + let state = cli.state.clone(); + let boxed_op = Box::new( - op.or_else(move |err: DenoError| -> DenoResult<Buf> { + op.or_else(move |err: DenoError| -> Result<Buf, ()> { debug!("op err {}", err); // No matter whether we got an Err or Ok, we want a serialized message to // send back. So transform the DenoError into a deno_buf. @@ -151,7 +158,7 @@ pub fn dispatch( ..Default::default() }, )) - }).and_then(move |buf: Buf| -> DenoResult<Buf> { + }).and_then(move |buf: Buf| -> Result<Buf, ()> { // Handle empty responses. For sync responses we just want // to send null. For async we want to send a small message // with the cmd_id. @@ -167,8 +174,9 @@ pub fn dispatch( }, ) }; + state.metrics_op_completed(buf.len()); Ok(buf) - }), + }).map_err(|err| panic!("unexpected error {:?}", err)), ); debug!( @@ -180,10 +188,10 @@ pub fn dispatch( } fn op_now( - _isolate: &Isolate, + _cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let start = SystemTime::now(); let since_the_epoch = start.duration_since(UNIX_EPOCH).unwrap(); @@ -204,10 +212,10 @@ fn op_now( } fn op_is_tty( - _isolate: &Isolate, + _cli: &Cli, base: &msg::Base<'_>, - _data: libdeno::deno_buf, -) -> Box<Op> { + _data: deno_buf, +) -> Box<OpWithError> { let builder = &mut FlatBufferBuilder::new(); let inner = msg::IsTTYRes::create( builder, @@ -229,23 +237,23 @@ fn op_is_tty( } fn op_exit( - _isolate: &Isolate, + _cli: &Cli, base: &msg::Base<'_>, - _data: libdeno::deno_buf, -) -> Box<Op> { + _data: deno_buf, +) -> Box<OpWithError> { let inner = base.inner_as_exit().unwrap(); std::process::exit(inner.code()) } fn op_start( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let mut builder = FlatBufferBuilder::new(); - let argv = isolate + let argv = cli .state .argv .iter() @@ -266,10 +274,7 @@ fn op_start( let deno_version = version::DENO; let deno_version_off = builder.create_string(deno_version); - let main_module = isolate - .state - .main_module() - .map(|m| builder.create_string(&m)); + let main_module = cli.state.main_module().map(|m| builder.create_string(&m)); let inner = msg::StartRes::create( &mut builder, @@ -278,9 +283,9 @@ fn op_start( pid: std::process::id(), argv: Some(argv_off), main_module, - debug_flag: isolate.state.flags.log_debug, - types_flag: isolate.state.flags.types, - version_flag: isolate.state.flags.version, + debug_flag: cli.state.flags.log_debug, + types_flag: cli.state.flags.types, + version_flag: cli.state.flags.version, v8_version: Some(v8_version_off), deno_version: Some(deno_version_off), no_color: !ansi::use_color(), @@ -301,16 +306,16 @@ fn op_start( } fn op_format_error( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_format_error().unwrap(); let orig_error = String::from(inner.error().unwrap()); let js_error = JSError::from_v8_exception(&orig_error).unwrap(); - let js_error_mapped = apply_source_map(&js_error, &isolate.state.dir); + let js_error_mapped = apply_source_map(&js_error, &cli.state.dir); let js_error_string = JSErrorColor(&js_error_mapped).to_string(); let mut builder = FlatBufferBuilder::new(); @@ -349,22 +354,22 @@ fn serialize_response( } #[inline] -pub fn ok_future(buf: Buf) -> Box<Op> { +pub fn ok_future(buf: Buf) -> Box<OpWithError> { Box::new(futures::future::ok(buf)) } // Shout out to Earl Sweatshirt. #[inline] -pub fn odd_future(err: DenoError) -> Box<Op> { +pub fn odd_future(err: DenoError) -> Box<OpWithError> { Box::new(futures::future::err(err)) } // https://github.com/denoland/deno/blob/golang/os.go#L100-L154 fn op_fetch_module_meta_data( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_fetch_module_meta_data().unwrap(); let cmd_id = base.cmd_id(); @@ -372,35 +377,32 @@ fn op_fetch_module_meta_data( let referrer = inner.referrer().unwrap(); // Check for allow read since this operation could be used to read from the file system. - if !isolate.permissions.allows_read() { + if !cli.permissions.allows_read() { debug!("No read permission for fetch_module_meta_data"); return odd_future(permission_denied()); } // Check for allow write since this operation could be used to write to the file system. - if !isolate.permissions.allows_write() { + if !cli.permissions.allows_write() { debug!("No network permission for fetch_module_meta_data"); return odd_future(permission_denied()); } // Check for allow net since this operation could be used to make https/http requests. - if !isolate.permissions.allows_net() { + if !cli.permissions.allows_net() { debug!("No network permission for fetch_module_meta_data"); return odd_future(permission_denied()); } assert_eq!( - isolate.state.dir.root.join("gen"), - isolate.state.dir.gen, + cli.state.dir.root.join("gen"), + cli.state.dir.gen, "Sanity check" ); Box::new(futures::future::result(|| -> OpResult { let builder = &mut FlatBufferBuilder::new(); - let out = isolate - .state - .dir - .fetch_module_meta_data(specifier, referrer)?; + let out = cli.state.dir.fetch_module_meta_data(specifier, referrer)?; let data_off = builder.create_vector(out.source_code.as_slice()); let msg_args = msg::FetchModuleMetaDataResArgs { module_name: Some(builder.create_string(&out.module_name)), @@ -422,10 +424,10 @@ fn op_fetch_module_meta_data( } fn op_chdir( - _isolate: &Isolate, + _cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_chdir().unwrap(); let directory = inner.directory().unwrap(); @@ -436,22 +438,22 @@ fn op_chdir( } fn op_global_timer_stop( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert!(base.sync()); assert_eq!(data.len(), 0); - let mut t = isolate.state.global_timer.lock().unwrap(); + let mut t = cli.state.global_timer.lock().unwrap(); t.cancel(); ok_future(empty_buf()) } fn op_global_timer( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert!(!base.sync()); assert_eq!(data.len(), 0); let cmd_id = base.cmd_id(); @@ -459,7 +461,7 @@ fn op_global_timer( let val = inner.timeout(); assert!(val >= 0); - let mut t = isolate.state.global_timer.lock().unwrap(); + let mut t = cli.state.global_timer.lock().unwrap(); let deadline = Instant::now() + Duration::from_millis(val as u64); let f = t.new_timeout(deadline); @@ -480,30 +482,26 @@ fn op_global_timer( } fn op_set_env( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_set_env().unwrap(); let key = inner.key().unwrap(); let value = inner.value().unwrap(); - if let Err(e) = isolate.check_env() { + if let Err(e) = cli.check_env() { return odd_future(e); } std::env::set_var(key, value); ok_future(empty_buf()) } -fn op_env( - isolate: &Isolate, - base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { +fn op_env(cli: &Cli, base: &msg::Base<'_>, data: deno_buf) -> Box<OpWithError> { assert_eq!(data.len(), 0); let cmd_id = base.cmd_id(); - if let Err(e) = isolate.check_env() { + if let Err(e) = cli.check_env() { return odd_future(e); } @@ -528,21 +526,21 @@ fn op_env( } fn op_permissions( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let cmd_id = base.cmd_id(); let builder = &mut FlatBufferBuilder::new(); let inner = msg::PermissionsRes::create( builder, &msg::PermissionsResArgs { - run: isolate.permissions.allows_run(), - read: isolate.permissions.allows_read(), - write: isolate.permissions.allows_write(), - net: isolate.permissions.allows_net(), - env: isolate.permissions.allows_env(), + run: cli.permissions.allows_run(), + read: cli.permissions.allows_read(), + write: cli.permissions.allows_write(), + net: cli.permissions.allows_net(), + env: cli.permissions.allows_env(), }, ); ok_future(serialize_response( @@ -557,19 +555,19 @@ fn op_permissions( } fn op_revoke_permission( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_permission_revoke().unwrap(); let permission = inner.permission().unwrap(); let result = match permission { - "run" => isolate.permissions.revoke_run(), - "read" => isolate.permissions.revoke_read(), - "write" => isolate.permissions.revoke_write(), - "net" => isolate.permissions.revoke_net(), - "env" => isolate.permissions.revoke_env(), + "run" => cli.permissions.revoke_run(), + "read" => cli.permissions.revoke_read(), + "write" => cli.permissions.revoke_write(), + "net" => cli.permissions.revoke_net(), + "env" => cli.permissions.revoke_env(), _ => Ok(()), }; if let Err(e) = result { @@ -579,10 +577,10 @@ fn op_revoke_permission( } fn op_fetch( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { let inner = base.inner_as_fetch().unwrap(); let cmd_id = base.cmd_id(); @@ -602,7 +600,7 @@ fn op_fetch( } let req = maybe_req.unwrap(); - if let Err(e) = isolate.check_net(url) { + if let Err(e) = cli.check_net(url) { return odd_future(e); } @@ -650,11 +648,11 @@ where Ok(Ready(Ok(v))) => Ok(v.into()), Ok(Ready(Err(err))) => Err(err), Ok(NotReady) => Ok(NotReady), - Err(_err) => panic!("blocking error"), + Err(err) => panic!("blocking error {}", err), } } -fn blocking<F>(is_sync: bool, f: F) -> Box<Op> +fn blocking<F>(is_sync: bool, f: F) -> Box<OpWithError> where F: 'static + Send + FnOnce() -> DenoResult<Buf>, { @@ -666,17 +664,17 @@ where } fn op_make_temp_dir( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let base = Box::new(*base); let inner = base.inner_as_make_temp_dir().unwrap(); let cmd_id = base.cmd_id(); // FIXME - if let Err(e) = isolate.check_write("make_temp") { + if let Err(e) = cli.check_write("make_temp") { return odd_future(e); } @@ -715,17 +713,17 @@ fn op_make_temp_dir( } fn op_mkdir( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_mkdir().unwrap(); let path = String::from(inner.path().unwrap()); let recursive = inner.recursive(); let mode = inner.mode(); - if let Err(e) = isolate.check_write(&path) { + if let Err(e) = cli.check_write(&path) { return odd_future(e); } @@ -737,16 +735,16 @@ fn op_mkdir( } fn op_chmod( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_chmod().unwrap(); let _mode = inner.mode(); let path = String::from(inner.path().unwrap()); - if let Err(e) = isolate.check_write(&path) { + if let Err(e) = cli.check_write(&path) { return odd_future(e); } @@ -776,10 +774,10 @@ fn op_chmod( } fn op_open( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let cmd_id = base.cmd_id(); let inner = base.inner_as_open().unwrap(); @@ -825,20 +823,20 @@ fn op_open( match mode { "r" => { - if let Err(e) = isolate.check_read(&filename_str) { + if let Err(e) = cli.check_read(&filename_str) { return odd_future(e); } } "w" | "a" | "x" => { - if let Err(e) = isolate.check_write(&filename_str) { + if let Err(e) = cli.check_write(&filename_str) { return odd_future(e); } } &_ => { - if let Err(e) = isolate.check_read(&filename_str) { + if let Err(e) = cli.check_read(&filename_str) { return odd_future(e); } - if let Err(e) = isolate.check_write(&filename_str) { + if let Err(e) = cli.check_write(&filename_str) { return odd_future(e); } } @@ -866,10 +864,10 @@ fn op_open( } fn op_close( - _isolate: &Isolate, + _cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_close().unwrap(); let rid = inner.rid(); @@ -883,10 +881,10 @@ fn op_close( } fn op_shutdown( - _isolate: &Isolate, + _cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_shutdown().unwrap(); let rid = inner.rid(); @@ -909,10 +907,10 @@ fn op_shutdown( } fn op_read( - _isolate: &Isolate, + _cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { let cmd_id = base.cmd_id(); let inner = base.inner_as_read().unwrap(); let rid = inner.rid(); @@ -947,10 +945,10 @@ fn op_read( } fn op_write( - _isolate: &Isolate, + _cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { let cmd_id = base.cmd_id(); let inner = base.inner_as_write().unwrap(); let rid = inner.rid(); @@ -984,10 +982,10 @@ fn op_write( } fn op_seek( - _isolate: &Isolate, + _cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let _cmd_id = base.cmd_id(); let inner = base.inner_as_seek().unwrap(); @@ -1006,17 +1004,17 @@ fn op_seek( } fn op_remove( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_remove().unwrap(); let path_ = inner.path().unwrap(); let path = PathBuf::from(path_); let recursive = inner.recursive(); - if let Err(e) = isolate.check_write(path.to_str().unwrap()) { + if let Err(e) = cli.check_write(path.to_str().unwrap()) { return odd_future(e); } @@ -1036,17 +1034,17 @@ fn op_remove( // Prototype https://github.com/denoland/deno/blob/golang/os.go#L171-L184 fn op_read_file( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_read_file().unwrap(); let cmd_id = base.cmd_id(); let filename_ = inner.filename().unwrap(); let filename = PathBuf::from(filename_); debug!("op_read_file {}", filename.display()); - if let Err(e) = isolate.check_read(&filename_) { + if let Err(e) = cli.check_read(&filename_) { return odd_future(e); } blocking(base.sync(), move || { @@ -1074,10 +1072,10 @@ fn op_read_file( } fn op_copy_file( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_copy_file().unwrap(); let from_ = inner.from().unwrap(); @@ -1085,10 +1083,10 @@ fn op_copy_file( let to_ = inner.to().unwrap(); let to = PathBuf::from(to_); - if let Err(e) = isolate.check_read(&from_) { + if let Err(e) = cli.check_read(&from_) { return odd_future(e); } - if let Err(e) = isolate.check_write(&to_) { + if let Err(e) = cli.check_write(&to_) { return odd_future(e); } @@ -1130,10 +1128,10 @@ fn get_mode(_perm: &fs::Permissions) -> u32 { } fn op_cwd( - _isolate: &Isolate, + _cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let cmd_id = base.cmd_id(); Box::new(futures::future::result(|| -> OpResult { @@ -1156,10 +1154,10 @@ fn op_cwd( } fn op_stat( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_stat().unwrap(); let cmd_id = base.cmd_id(); @@ -1167,7 +1165,7 @@ fn op_stat( let filename = PathBuf::from(filename_); let lstat = inner.lstat(); - if let Err(e) = isolate.check_read(&filename_) { + if let Err(e) = cli.check_read(&filename_) { return odd_future(e); } @@ -1208,16 +1206,16 @@ fn op_stat( } fn op_read_dir( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_read_dir().unwrap(); let cmd_id = base.cmd_id(); let path = String::from(inner.path().unwrap()); - if let Err(e) = isolate.check_read(&path) { + if let Err(e) = cli.check_read(&path) { return odd_future(e); } @@ -1269,10 +1267,10 @@ fn op_read_dir( } fn op_write_file( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { let inner = base.inner_as_write_file().unwrap(); let filename = String::from(inner.filename().unwrap()); let update_perm = inner.update_perm(); @@ -1280,7 +1278,7 @@ fn op_write_file( let is_create = inner.is_create(); let is_append = inner.is_append(); - if let Err(e) = isolate.check_write(&filename) { + if let Err(e) = cli.check_write(&filename) { return odd_future(e); } @@ -1299,16 +1297,16 @@ fn op_write_file( } fn op_rename( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_rename().unwrap(); let oldpath = PathBuf::from(inner.oldpath().unwrap()); let newpath_ = inner.newpath().unwrap(); let newpath = PathBuf::from(newpath_); - if let Err(e) = isolate.check_write(&newpath_) { + if let Err(e) = cli.check_write(&newpath_) { return odd_future(e); } blocking(base.sync(), move || -> OpResult { @@ -1319,17 +1317,17 @@ fn op_rename( } fn op_symlink( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_symlink().unwrap(); let oldname = PathBuf::from(inner.oldname().unwrap()); let newname_ = inner.newname().unwrap(); let newname = PathBuf::from(newname_); - if let Err(e) = isolate.check_write(&newname_) { + if let Err(e) = cli.check_write(&newname_) { return odd_future(e); } // TODO Use type for Windows. @@ -1348,17 +1346,17 @@ fn op_symlink( } fn op_read_link( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_readlink().unwrap(); let cmd_id = base.cmd_id(); let name_ = inner.name().unwrap(); let name = PathBuf::from(name_); - if let Err(e) = isolate.check_read(&name_) { + if let Err(e) = cli.check_read(&name_) { return odd_future(e); } @@ -1386,17 +1384,17 @@ fn op_read_link( } fn op_repl_start( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_repl_start().unwrap(); let cmd_id = base.cmd_id(); let history_file = String::from(inner.history_file().unwrap()); debug!("op_repl_start {}", history_file); - let history_path = repl::history_path(&isolate.state.dir, &history_file); + let history_path = repl::history_path(&cli.state.dir, &history_file); let repl = repl::Repl::new(history_path); let resource = resources::add_repl(repl); @@ -1417,10 +1415,10 @@ fn op_repl_start( } fn op_repl_readline( - _isolate: &Isolate, + _cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_repl_readline().unwrap(); let cmd_id = base.cmd_id(); @@ -1453,17 +1451,17 @@ fn op_repl_readline( } fn op_truncate( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let inner = base.inner_as_truncate().unwrap(); let filename = String::from(inner.name().unwrap()); let len = inner.len(); - if let Err(e) = isolate.check_write(&filename) { + if let Err(e) = cli.check_write(&filename) { return odd_future(e); } @@ -1476,12 +1474,12 @@ fn op_truncate( } fn op_listen( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); - if let Err(e) = isolate.check_net("listen") { + if let Err(e) = cli.check_net("listen") { return odd_future(e); } @@ -1538,12 +1536,12 @@ fn new_conn(cmd_id: u32, tcp_stream: TcpStream) -> OpResult { } fn op_accept( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); - if let Err(e) = isolate.check_net("accept") { + if let Err(e) = cli.check_net("accept") { return odd_future(e); } let cmd_id = base.cmd_id(); @@ -1564,12 +1562,12 @@ fn op_accept( } fn op_dial( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); - if let Err(e) = isolate.check_net("dial") { + if let Err(e) = cli.check_net("dial") { return odd_future(e); } let cmd_id = base.cmd_id(); @@ -1590,17 +1588,17 @@ fn op_dial( } fn op_metrics( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let cmd_id = base.cmd_id(); let builder = &mut FlatBufferBuilder::new(); let inner = msg::MetricsRes::create( builder, - &msg::MetricsResArgs::from(&isolate.state.metrics), + &msg::MetricsResArgs::from(&cli.state.metrics), ); ok_future(serialize_response( cmd_id, @@ -1614,10 +1612,10 @@ fn op_metrics( } fn op_resources( - _isolate: &Isolate, + _cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let cmd_id = base.cmd_id(); @@ -1665,15 +1663,11 @@ fn subprocess_stdio_map(v: msg::ProcessStdio) -> std::process::Stdio { } } -fn op_run( - isolate: &Isolate, - base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { +fn op_run(cli: &Cli, base: &msg::Base<'_>, data: deno_buf) -> Box<OpWithError> { assert!(base.sync()); let cmd_id = base.cmd_id(); - if let Err(e) = isolate.check_run() { + if let Err(e) = cli.check_run() { return odd_future(e); } @@ -1739,16 +1733,16 @@ fn op_run( } fn op_run_status( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let cmd_id = base.cmd_id(); let inner = base.inner_as_run_status().unwrap(); let rid = inner.rid(); - if let Err(e) = isolate.check_run() { + if let Err(e) = cli.check_run() { return odd_future(e); } @@ -1815,15 +1809,15 @@ impl Future for GetMessageFuture { } fn op_worker_get_message( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { assert_eq!(data.len(), 0); let cmd_id = base.cmd_id(); let op = GetMessageFuture { - state: isolate.state.clone(), + state: cli.state.clone(), }; let op = op.map_err(move |_| -> DenoError { unimplemented!() }); let op = op.and_then(move |maybe_buf| -> DenoResult<Buf> { @@ -1849,16 +1843,16 @@ fn op_worker_get_message( } fn op_worker_post_message( - isolate: &Isolate, + cli: &Cli, base: &msg::Base<'_>, - data: libdeno::deno_buf, -) -> Box<Op> { + data: deno_buf, +) -> Box<OpWithError> { let cmd_id = base.cmd_id(); let d = Vec::from(data.as_ref()).into_boxed_slice(); - assert!(isolate.state.worker_channels.is_some()); - let tx = match isolate.state.worker_channels { + assert!(cli.state.worker_channels.is_some()); + let tx = match cli.state.worker_channels { None => panic!("expected worker_channels"), Some(ref wc) => { let wc = wc.lock().unwrap(); @@ -1884,13 +1878,13 @@ fn op_worker_post_message( #[cfg(test)] mod tests { use super::*; - use crate::isolate::{Isolate, IsolateState}; + use crate::cli::Cli; use crate::isolate_init::IsolateInit; use crate::permissions::{DenoPermissions, PermissionAccessor}; #[test] fn fetch_module_meta_fails_without_read() { - let state = IsolateState::mock(); + let state = Arc::new(IsolateState::mock()); let permissions = DenoPermissions { allow_write: PermissionAccessor::from(true), allow_env: PermissionAccessor::from(true), @@ -1898,13 +1892,12 @@ mod tests { allow_run: PermissionAccessor::from(true), ..Default::default() }; - let isolate = Isolate::new( + let cli = Cli::new( IsolateInit { snapshot: None, init_script: None, }, state, - dispatch, permissions, ); let builder = &mut FlatBufferBuilder::new(); @@ -1922,11 +1915,8 @@ mod tests { msg::finish_base_buffer(builder, base); let data = builder.finished_data(); let final_msg = msg::get_root_as_base(&data); - let fetch_result = op_fetch_module_meta_data( - &isolate, - &final_msg, - libdeno::deno_buf::empty(), - ).wait(); + let fetch_result = + op_fetch_module_meta_data(&cli, &final_msg, deno_buf::empty()).wait(); match fetch_result { Ok(_) => assert!(true), Err(e) => assert_eq!(e.to_string(), permission_denied().to_string()), @@ -1935,7 +1925,7 @@ mod tests { #[test] fn fetch_module_meta_fails_without_write() { - let state = IsolateState::mock(); + let state = Arc::new(IsolateState::mock()); let permissions = DenoPermissions { allow_read: PermissionAccessor::from(true), allow_env: PermissionAccessor::from(true), @@ -1943,13 +1933,12 @@ mod tests { allow_run: PermissionAccessor::from(true), ..Default::default() }; - let isolate = Isolate::new( + let cli = Cli::new( IsolateInit { snapshot: None, init_script: None, }, state, - dispatch, permissions, ); let builder = &mut FlatBufferBuilder::new(); @@ -1967,11 +1956,8 @@ mod tests { msg::finish_base_buffer(builder, base); let data = builder.finished_data(); let final_msg = msg::get_root_as_base(&data); - let fetch_result = op_fetch_module_meta_data( - &isolate, - &final_msg, - libdeno::deno_buf::empty(), - ).wait(); + let fetch_result = + op_fetch_module_meta_data(&cli, &final_msg, deno_buf::empty()).wait(); match fetch_result { Ok(_) => assert!(true), Err(e) => assert_eq!(e.to_string(), permission_denied().to_string()), @@ -1980,7 +1966,7 @@ mod tests { #[test] fn fetch_module_meta_fails_without_net() { - let state = IsolateState::mock(); + let state = Arc::new(IsolateState::mock()); let permissions = DenoPermissions { allow_read: PermissionAccessor::from(true), allow_write: PermissionAccessor::from(true), @@ -1988,13 +1974,12 @@ mod tests { allow_run: PermissionAccessor::from(true), ..Default::default() }; - let isolate = Isolate::new( + let cli = Cli::new( IsolateInit { snapshot: None, init_script: None, }, state, - dispatch, permissions, ); let builder = &mut FlatBufferBuilder::new(); @@ -2012,11 +1997,8 @@ mod tests { msg::finish_base_buffer(builder, base); let data = builder.finished_data(); let final_msg = msg::get_root_as_base(&data); - let fetch_result = op_fetch_module_meta_data( - &isolate, - &final_msg, - libdeno::deno_buf::empty(), - ).wait(); + let fetch_result = + op_fetch_module_meta_data(&cli, &final_msg, deno_buf::empty()).wait(); match fetch_result { Ok(_) => assert!(true), Err(e) => assert_eq!(e.to_string(), permission_denied().to_string()), @@ -2025,20 +2007,19 @@ mod tests { #[test] fn fetch_module_meta_not_permission_denied_with_permissions() { - let state = IsolateState::mock(); + let state = Arc::new(IsolateState::mock()); let permissions = DenoPermissions { allow_read: PermissionAccessor::from(true), allow_write: PermissionAccessor::from(true), allow_net: PermissionAccessor::from(true), ..Default::default() }; - let isolate = Isolate::new( + let cli = Cli::new( IsolateInit { snapshot: None, init_script: None, }, state, - dispatch, permissions, ); let builder = &mut FlatBufferBuilder::new(); @@ -2056,11 +2037,8 @@ mod tests { msg::finish_base_buffer(builder, base); let data = builder.finished_data(); let final_msg = msg::get_root_as_base(&data); - let fetch_result = op_fetch_module_meta_data( - &isolate, - &final_msg, - libdeno::deno_buf::empty(), - ).wait(); + let fetch_result = + op_fetch_module_meta_data(&cli, &final_msg, deno_buf::empty()).wait(); match fetch_result { Ok(_) => assert!(true), Err(e) => assert!(e.to_string() != permission_denied().to_string()), diff --git a/src/resources.rs b/src/resources.rs index 2d617265e..e962bce8e 100644 --- a/src/resources.rs +++ b/src/resources.rs @@ -8,6 +8,7 @@ // descriptors". This module implements a global resource table. Ops (AKA // handlers) look up resources by their integer id here. +use crate::cli::Buf; #[cfg(unix)] use crate::eager_unix as eager; use crate::errors; @@ -15,8 +16,7 @@ use crate::errors::bad_resource; use crate::errors::DenoError; use crate::errors::DenoResult; use crate::http_body::HttpBody; -use crate::isolate::Buf; -use crate::isolate::WorkerChannels; +use crate::isolate_state::WorkerChannels; use crate::repl::Repl; use crate::tokio_util; use crate::tokio_write; @@ -175,50 +175,12 @@ impl Resource { } } - /// Track the current task (for TcpListener resource). - /// Throws an error if another task is already tracked. - pub fn track_task(&mut self) -> Result<(), std::io::Error> { - let mut table = RESOURCE_TABLE.lock().unwrap(); - // Only track if is TcpListener. - if let Some(Repr::TcpListener(_, t)) = table.get_mut(&self.rid) { - // Currently, we only allow tracking a single accept task for a listener. - // This might be changed in the future with multiple workers. - // Caveat: TcpListener by itself also only tracks an accept task at a time. - // See https://github.com/tokio-rs/tokio/issues/846#issuecomment-454208883 - if t.is_some() { - return Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Another accept task is ongoing", - )); - } - t.replace(futures::task::current()); - } - Ok(()) - } - - /// Stop tracking a task (for TcpListener resource). - /// Happens when the task is done and thus no further tracking is needed. - pub fn untrack_task(&mut self) { - let mut table = RESOURCE_TABLE.lock().unwrap(); - // Only untrack if is TcpListener. - if let Some(Repr::TcpListener(_, t)) = table.get_mut(&self.rid) { - // DO NOT assert is_some here. - // See reasoning in Accept::poll(). - t.take(); - } - } - // close(2) is done by dropping the value. Therefore we just need to remove // the resource from the RESOURCE_TABLE. pub fn close(&self) { let mut table = RESOURCE_TABLE.lock().unwrap(); let r = table.remove(&self.rid); assert!(r.is_some()); - // If TcpListener, we must kill all pending accepts! - if let Repr::TcpListener(_, Some(t)) = r.unwrap() { - // Call notify on the tracked task, so that they would error out. - t.notify(); - } } pub fn shutdown(&mut self, how: Shutdown) -> Result<(), DenoError> { diff --git a/src/tokio_util.rs b/src/tokio_util.rs index ef66f4610..810b826b4 100644 --- a/src/tokio_util.rs +++ b/src/tokio_util.rs @@ -1,6 +1,5 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. use crate::resources::Resource; - use futures; use futures::Future; use futures::Poll; @@ -9,7 +8,14 @@ use std::mem; use std::net::SocketAddr; use tokio; use tokio::net::TcpStream; -use tokio_executor; + +pub fn run<F>(future: F) +where + F: Future<Item = (), Error = ()> + Send + 'static, +{ + // tokio::runtime::current_thread::run(future) + tokio::run(future) +} pub fn block_on<F, R, E>(future: F) -> Result<R, E> where @@ -25,10 +31,12 @@ where // Set the default executor so we can use tokio::spawn(). It's difficult to // pass around mut references to the runtime, so using with_default is // preferable. Ideally Tokio would provide this function. +#[cfg(test)] pub fn init<F>(f: F) where F: FnOnce(), { + use tokio_executor; let rt = tokio::runtime::Runtime::new().unwrap(); let mut executor = rt.executor(); let mut enter = tokio_executor::enter().expect("Multiple executors at once"); @@ -63,29 +71,7 @@ impl Future for Accept { fn poll(&mut self) -> Poll<Self::Item, Self::Error> { let (stream, addr) = match self.state { - // Similar to try_ready!, but also track/untrack accept task - // in TcpListener resource. - // In this way, when the listener is closed, the task can be - // notified to error out (instead of stuck forever). - AcceptState::Pending(ref mut r) => match r.poll_accept() { - Ok(futures::prelude::Async::Ready(t)) => { - // Notice: it is possible to be Ready on the first poll. - // When eager accept fails due to WouldBlock, - // a next poll() might still be immediately Ready. - // See https://github.com/denoland/deno/issues/1756. - r.untrack_task(); - t - } - Ok(futures::prelude::Async::NotReady) => { - // Would error out if another accept task is being tracked. - r.track_task()?; - return Ok(futures::prelude::Async::NotReady); - } - Err(e) => { - r.untrack_task(); - return Err(e); - } - }, + AcceptState::Pending(ref mut r) => try_ready!(r.poll_accept()), AcceptState::Empty => panic!("poll Accept after it's done"), }; diff --git a/src/workers.rs b/src/workers.rs index 3a3b690b2..8393de222 100644 --- a/src/workers.rs +++ b/src/workers.rs @@ -1,19 +1,21 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -use crate::isolate::Buf; +use crate::cli::Buf; +use crate::cli::Cli; +use crate::flags::DenoFlags; use crate::isolate::Isolate; -use crate::isolate::IsolateState; -use crate::isolate::WorkerChannels; use crate::isolate_init::IsolateInit; +use crate::isolate_state::IsolateState; +use crate::isolate_state::WorkerChannels; use crate::js_errors::JSErrorColor; -use crate::ops; use crate::permissions::DenoPermissions; use crate::resources; use crate::tokio_util; use deno_core::JSError; - +use futures::future::lazy; use futures::sync::mpsc; use futures::sync::oneshot; use futures::Future; +use futures::Poll; use std::sync::Arc; use std::thread; @@ -25,7 +27,8 @@ pub struct Worker { impl Worker { pub fn new( init: IsolateInit, - parent_state: &Arc<IsolateState>, + flags: DenoFlags, + argv: Vec<String>, permissions: DenoPermissions, ) -> (Self, WorkerChannels) { let (worker_in_tx, worker_in_rx) = mpsc::channel::<Buf>(1); @@ -34,30 +37,33 @@ impl Worker { let internal_channels = (worker_out_tx, worker_in_rx); let external_channels = (worker_in_tx, worker_out_rx); - let state = Arc::new(IsolateState::new( - parent_state.flags.clone(), - parent_state.argv.clone(), - Some(internal_channels), - )); + let state = + Arc::new(IsolateState::new(flags, argv, Some(internal_channels))); - let isolate = Isolate::new(init, state, ops::dispatch, permissions); + let cli = Cli::new(init, state, permissions); + let isolate = Isolate::new(cli); let worker = Worker { isolate }; (worker, external_channels) } - pub fn execute(&self, js_source: &str) -> Result<(), JSError> { + pub fn execute(&mut self, js_source: &str) -> Result<(), JSError> { self.isolate.execute(js_source) } +} - pub fn event_loop(&self) -> Result<(), JSError> { - self.isolate.event_loop() +impl Future for Worker { + type Item = (); + type Error = JSError; + + fn poll(&mut self) -> Poll<(), JSError> { + self.isolate.poll() } } pub fn spawn( init: IsolateInit, - state: Arc<IsolateState>, + state: &IsolateState, js_source: String, permissions: DenoPermissions, ) -> resources::Resource { @@ -67,27 +73,38 @@ pub fn spawn( // let (js_error_tx, js_error_rx) = oneshot::channel::<JSError>(); let (p, c) = oneshot::channel::<resources::Resource>(); let builder = thread::Builder::new().name("worker".to_string()); - let _tid = builder - .spawn(move || { - let (worker, external_channels) = Worker::new(init, &state, permissions); - let resource = resources::add_worker(external_channels); - p.send(resource.clone()).unwrap(); + let flags = state.flags.clone(); + let argv = state.argv.clone(); - tokio_util::init(|| { - (|| -> Result<(), JSError> { - worker.execute("denoMain()")?; - worker.execute("workerMain()")?; - worker.execute(&js_source)?; - worker.event_loop()?; + let _tid = builder + .spawn(move || { + tokio_util::run(lazy(move || { + let (mut worker, external_channels) = + Worker::new(init, flags, argv, permissions); + let resource = resources::add_worker(external_channels); + p.send(resource.clone()).unwrap(); + + worker + .execute("denoMain()") + .expect("worker denoMain failed"); + worker + .execute("workerMain()") + .expect("worker workerMain failed"); + worker.execute(&js_source).expect("worker js_source failed"); + + worker.then(move |r| -> Result<(), ()> { + resource.close(); + debug!("workers.rs after resource close"); + if let Err(err) = r { + eprintln!("{}", JSErrorColor(&err).to_string()); + std::process::exit(1); + } Ok(()) - })().or_else(|err: JSError| -> Result<(), JSError> { - eprintln!("{}", JSErrorColor(&err).to_string()); - std::process::exit(1) - }).unwrap(); - }); + }) + })); - resource.close(); + debug!("workers.rs after spawn"); }).unwrap(); c.wait().unwrap() @@ -103,7 +120,7 @@ mod tests { let isolate_init = isolate_init::compiler_isolate_init(); let resource = spawn( isolate_init, - IsolateState::mock(), + &IsolateState::mock(), r#" onmessage = function(e) { let s = new TextDecoder().decode(e.data);; @@ -140,7 +157,7 @@ mod tests { let isolate_init = isolate_init::compiler_isolate_init(); let resource = spawn( isolate_init, - IsolateState::mock(), + &IsolateState::mock(), "onmessage = () => close();".into(), DenoPermissions::default(), ); |