377 lines
12 KiB
Rust
Raw Normal View History

2018-12-11 18:06:20 +01:00
use super::utils::{copy_cstr_into_wasm, write_to_buf};
2019-02-09 13:31:28 -08:00
use libc::{c_char, c_int};
2018-11-26 20:29:26 -08:00
use std::mem;
use std::time::SystemTime;
#[cfg(not(target_os = "windows"))]
use libc::{clockid_t, time as libc_time};
2019-02-09 13:31:28 -08:00
#[cfg(target_os = "windows")]
use libc::time_t;
#[cfg(target_os = "windows")]
2019-03-15 14:10:17 -07:00
#[allow(non_camel_case_types)]
type clockid_t = c_int;
#[cfg(target_os = "windows")]
extern "C" {
#[link_name = "time"]
pub fn libc_time(s: *const time_t) -> time_t;
}
use time;
2019-01-10 21:37:59 -08:00
use super::env;
2019-01-23 01:27:13 -06:00
use wasmer_runtime_core::vm::Ctx;
2019-01-01 16:13:35 -08:00
#[cfg(target_os = "linux")]
2018-12-31 14:56:04 -08:00
use libc::{CLOCK_MONOTONIC, CLOCK_MONOTONIC_COARSE, CLOCK_REALTIME};
2019-01-01 16:13:35 -08:00
#[cfg(target_os = "macos")]
2019-05-06 14:05:04 -07:00
use libc::CLOCK_REALTIME;
#[cfg(target_os = "macos")]
const CLOCK_MONOTONIC: clockid_t = 1;
2019-01-01 16:13:35 -08:00
#[cfg(target_os = "macos")]
const CLOCK_MONOTONIC_COARSE: clockid_t = 6;
2019-01-01 16:13:35 -08:00
2018-12-31 14:56:04 -08:00
// some assumptions about the constants when targeting windows
#[cfg(target_os = "windows")]
const CLOCK_REALTIME: clockid_t = 0;
2018-12-31 14:56:04 -08:00
#[cfg(target_os = "windows")]
const CLOCK_MONOTONIC: clockid_t = 1;
2018-12-31 14:56:04 -08:00
#[cfg(target_os = "windows")]
const CLOCK_MONOTONIC_COARSE: clockid_t = 6;
2018-12-31 14:56:04 -08:00
/// emscripten: _gettimeofday
2019-01-18 00:33:46 -06:00
#[allow(clippy::cast_ptr_alignment)]
pub fn _gettimeofday(ctx: &mut Ctx, tp: c_int, tz: c_int) -> c_int {
debug!("emscripten::_gettimeofday {} {}", tp, tz);
#[repr(C)]
struct GuestTimeVal {
tv_sec: i32,
tv_usec: i32,
}
2018-11-26 20:29:26 -08:00
assert!(
tz == 0,
"the timezone argument of `_gettimeofday` must be null"
);
unsafe {
let now = SystemTime::now();
let since_epoch = now.duration_since(SystemTime::UNIX_EPOCH).unwrap();
2019-01-24 13:04:12 -08:00
let timeval_struct_ptr = emscripten_memory_pointer!(ctx.memory(0), tp) as *mut GuestTimeVal;
(*timeval_struct_ptr).tv_sec = since_epoch.as_secs() as _;
(*timeval_struct_ptr).tv_usec = since_epoch.subsec_nanos() as _;
}
0
}
2018-11-26 15:42:47 -05:00
/// emscripten: _clock_gettime
2019-01-18 00:33:46 -06:00
#[allow(clippy::cast_ptr_alignment)]
pub fn _clock_gettime(ctx: &mut Ctx, clk_id: clockid_t, tp: c_int) -> c_int {
debug!("emscripten::_clock_gettime {} {}", clk_id, tp);
2019-01-24 13:04:12 -08:00
// debug!("Memory {:?}", ctx.memory(0)[..]);
#[repr(C)]
struct GuestTimeSpec {
tv_sec: i32,
tv_nsec: i32,
}
fix(emscripten) Various warning fixes and cleanups (#266) * fix(emscripten) Remove unused imports. This patch removes unused imports reported by `rustc` as warnings. * fix(emscripten) Allow unreachable patterns in `_clock_gettime`. The compiler thinks `CLOCK_MONOTONIC_COARSE` is unreachable, which is not always the case. Add an attribute to allow unreachable patterns to remove the warning. * fix(emscripten) Rename unused variables. This patch renames various unused variables by appending an underscore to them. * fix(emscripten) Declare `table` as immutable. The `table` variable in `EmscriptenGlobals::new` was declared as mutable, but it's never mutated. * fix(emscripten) Remove an unnecessary `unsafe` block. * fix(emscripten) Remove duplicate definition of `SO_NOSIGPIPE`. The `SO_NOSIGPIPE` constant is defined in `syscalls/mod.rs` and `syscalls/unix.rs`. It's never used in the first case. We can safely remove it in this file, and keep it in `unix.rs`. * fix(emscripten) `read_string_from_wasm` is used only on Windows. Mark `read_string_from_wasm` as possible deadcode, since it's used only on Windows. * fix(emscripten) Remove `DYNAMICTOP_PTR_DIFF`, `stacktop`, `stack_max`, `dynamic_base` and `dynamic_ptr`. Four functions and one constant are used together but never used inside or outside this file. They are deadcode. * fix(emscripten) Remove `infinity` and `nan` fields of `EmscriptenGlobalsData`. Those fields are never used. * fix(emscripten) Allow non snake case in `emscripten_target.rs`. Many functions in this file don't follow the snake case style for Rust function names. The reason is that we want the names to match the emscripten symbol names; even if a mapping is done in `lib.rs`, it's easier to get the same names. * fix(emscripten) Rename `STATIC_TOP` to `static_top`. This variable is not a constant.
2019-03-12 22:00:33 +01:00
#[allow(unreachable_patterns)]
2018-12-27 06:57:00 -08:00
let timespec = match clk_id {
2018-12-31 14:56:04 -08:00
CLOCK_REALTIME => time::get_time(),
fix(emscripten) Various warning fixes and cleanups (#266) * fix(emscripten) Remove unused imports. This patch removes unused imports reported by `rustc` as warnings. * fix(emscripten) Allow unreachable patterns in `_clock_gettime`. The compiler thinks `CLOCK_MONOTONIC_COARSE` is unreachable, which is not always the case. Add an attribute to allow unreachable patterns to remove the warning. * fix(emscripten) Rename unused variables. This patch renames various unused variables by appending an underscore to them. * fix(emscripten) Declare `table` as immutable. The `table` variable in `EmscriptenGlobals::new` was declared as mutable, but it's never mutated. * fix(emscripten) Remove an unnecessary `unsafe` block. * fix(emscripten) Remove duplicate definition of `SO_NOSIGPIPE`. The `SO_NOSIGPIPE` constant is defined in `syscalls/mod.rs` and `syscalls/unix.rs`. It's never used in the first case. We can safely remove it in this file, and keep it in `unix.rs`. * fix(emscripten) `read_string_from_wasm` is used only on Windows. Mark `read_string_from_wasm` as possible deadcode, since it's used only on Windows. * fix(emscripten) Remove `DYNAMICTOP_PTR_DIFF`, `stacktop`, `stack_max`, `dynamic_base` and `dynamic_ptr`. Four functions and one constant are used together but never used inside or outside this file. They are deadcode. * fix(emscripten) Remove `infinity` and `nan` fields of `EmscriptenGlobalsData`. Those fields are never used. * fix(emscripten) Allow non snake case in `emscripten_target.rs`. Many functions in this file don't follow the snake case style for Rust function names. The reason is that we want the names to match the emscripten symbol names; even if a mapping is done in `lib.rs`, it's easier to get the same names. * fix(emscripten) Rename `STATIC_TOP` to `static_top`. This variable is not a constant.
2019-03-12 22:00:33 +01:00
2018-12-31 14:56:04 -08:00
CLOCK_MONOTONIC | CLOCK_MONOTONIC_COARSE => {
let precise_ns = time::precise_time_ns();
time::Timespec::new(
(precise_ns / 1000000000) as i64,
(precise_ns % 1000000000) as i32,
)
}
_ => panic!("Clock with id \"{}\" is not supported.", clk_id),
2018-12-27 06:57:00 -08:00
};
unsafe {
2019-01-24 15:30:13 -08:00
let timespec_struct_ptr =
emscripten_memory_pointer!(ctx.memory(0), tp) as *mut GuestTimeSpec;
(*timespec_struct_ptr).tv_sec = timespec.sec as _;
(*timespec_struct_ptr).tv_nsec = timespec.nsec as _;
}
0
}
2018-11-26 22:15:49 +01:00
/// emscripten: ___clock_gettime
pub fn ___clock_gettime(ctx: &mut Ctx, clk_id: clockid_t, tp: c_int) -> c_int {
debug!("emscripten::___clock_gettime {} {}", clk_id, tp);
_clock_gettime(ctx, clk_id, tp)
}
/// emscripten: _clock
pub fn _clock(_ctx: &mut Ctx) -> c_int {
debug!("emscripten::_clock");
0 // TODO: unimplemented
}
/// emscripten: _difftime
pub fn _difftime(_ctx: &mut Ctx, t0: u32, t1: u32) -> f64 {
debug!("emscripten::_difftime");
(t0 - t1) as _
}
pub fn _gmtime_r(_ctx: &mut Ctx, _one: i32, _two: i32) -> i32 {
2019-01-24 23:58:54 -06:00
debug!("emscripten::_gmtime_r");
-1
}
pub fn _mktime(_ctx: &mut Ctx, _one: i32) -> i32 {
2019-01-24 23:58:54 -06:00
debug!("emscripten::_mktime");
-1
}
pub fn _gmtime(_ctx: &mut Ctx, _one: i32) -> i32 {
2019-01-27 00:33:58 -06:00
debug!("emscripten::_gmtime");
-1
}
2018-12-07 14:50:35 +01:00
#[repr(C)]
struct guest_tm {
2018-12-28 12:38:39 +01:00
pub tm_sec: c_int, // 0
pub tm_min: c_int, // 4
pub tm_hour: c_int, // 8
pub tm_mday: c_int, // 12
pub tm_mon: c_int, // 16
pub tm_year: c_int, // 20
pub tm_wday: c_int, // 24
pub tm_yday: c_int, // 28
pub tm_isdst: c_int, // 32
pub tm_gmtoff: c_int, // 36
2018-12-28 12:38:39 +01:00
pub tm_zone: c_int, // 40
2018-12-07 14:50:35 +01:00
}
/// emscripten: _tvset
pub fn _tvset(_ctx: &mut Ctx) {
debug!("emscripten::_tvset UNIMPLEMENTED");
}
2018-12-11 18:06:20 +01:00
/// formats time as a C string
2019-01-18 00:33:46 -06:00
#[allow(clippy::cast_ptr_alignment)]
unsafe fn fmt_time(ctx: &mut Ctx, time: u32) -> *const c_char {
2019-01-24 13:04:12 -08:00
let date = &*(emscripten_memory_pointer!(ctx.memory(0), time) as *mut guest_tm);
2018-12-11 18:06:20 +01:00
let days = vec!["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2018-12-15 00:46:11 -06:00
let months = vec![
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
];
2018-12-11 18:06:20 +01:00
let year = 1900 + date.tm_year;
let time_str = format!(
// NOTE: TODO: Hack! The 14 accompanying chars are needed for some reason
2018-12-11 18:06:20 +01:00
"{} {} {:2} {:02}:{:02}:{:02} {:4}\n\0\0\0\0\0\0\0\0\0\0\0\0\0",
days[date.tm_wday as usize],
months[date.tm_mon as usize],
date.tm_mday,
date.tm_hour,
date.tm_min,
date.tm_sec,
year
);
time_str[0..26].as_ptr() as _
}
2018-12-07 14:50:35 +01:00
/// emscripten: _asctime
pub fn _asctime(ctx: &mut Ctx, time: u32) -> u32 {
2018-12-07 14:50:35 +01:00
debug!("emscripten::_asctime {}", time);
unsafe {
let time_str_ptr = fmt_time(ctx, time);
2019-01-24 13:04:12 -08:00
copy_cstr_into_wasm(ctx, time_str_ptr)
2018-12-11 17:05:07 +01:00
2019-01-24 13:04:12 -08:00
// let c_str = emscripten_memory_pointer!(ctx.memory(0), res) as *mut i8;
2018-12-11 17:05:07 +01:00
// use std::ffi::CStr;
// debug!("#### cstr = {:?}", CStr::from_ptr(c_str));
}
}
/// emscripten: _asctime_r
pub fn _asctime_r(ctx: &mut Ctx, time: u32, buf: u32) -> u32 {
debug!("emscripten::_asctime_r {}, {}", time, buf);
2018-12-11 17:05:07 +01:00
unsafe {
2018-12-07 16:37:14 +01:00
// NOTE: asctime_r is specced to behave in an undefined manner if the algorithm would attempt
2018-12-07 14:50:35 +01:00
// to write out more than 26 bytes (including the null terminator).
// See http://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime.html
// Our undefined behavior is to truncate the write to at most 26 bytes, including null terminator.
let time_str_ptr = fmt_time(ctx, time);
write_to_buf(ctx, time_str_ptr, buf, 26)
2018-12-07 14:50:35 +01:00
2019-01-24 13:04:12 -08:00
// let c_str = emscripten_memory_pointer!(ctx.memory(0), res) as *mut i8;
2018-12-07 18:19:28 +01:00
// use std::ffi::CStr;
// debug!("#### cstr = {:?}", CStr::from_ptr(c_str));
2018-12-07 14:50:35 +01:00
}
}
2018-11-26 22:15:49 +01:00
/// emscripten: _localtime
2019-01-18 00:33:46 -06:00
#[allow(clippy::cast_ptr_alignment)]
pub fn _localtime(ctx: &mut Ctx, time_p: u32) -> c_int {
2018-11-26 22:15:49 +01:00
debug!("emscripten::_localtime {}", time_p);
2018-12-07 14:50:35 +01:00
// NOTE: emscripten seems to want tzset() called in this function
// https://stackoverflow.com/questions/19170721/real-time-awareness-of-timezone-change-in-localtime-vs-localtime-r
2018-11-26 22:15:49 +01:00
let timespec = unsafe {
2019-01-24 13:04:12 -08:00
let time_p_addr = emscripten_memory_pointer!(ctx.memory(0), time_p) as *mut i64;
let seconds = *time_p_addr.clone();
time::Timespec::new(seconds, 0)
};
let result_tm = time::at(timespec);
2018-12-07 14:50:35 +01:00
unsafe {
let tm_struct_offset = env::call_malloc(ctx, mem::size_of::<guest_tm>() as _);
2019-01-24 15:30:13 -08:00
let tm_struct_ptr =
emscripten_memory_pointer!(ctx.memory(0), tm_struct_offset) as *mut guest_tm;
2018-12-11 21:13:43 +01:00
// debug!(
// ">>>>>>> time = {}, {}, {}, {}, {}, {}, {}, {}",
// result_tm.tm_sec, result_tm.tm_min, result_tm.tm_hour, result_tm.tm_mday,
// result_tm.tm_mon, result_tm.tm_year, result_tm.tm_wday, result_tm.tm_yday,
// );
2018-12-11 20:42:29 +01:00
(*tm_struct_ptr).tm_sec = result_tm.tm_sec;
(*tm_struct_ptr).tm_min = result_tm.tm_min;
(*tm_struct_ptr).tm_hour = result_tm.tm_hour;
(*tm_struct_ptr).tm_mday = result_tm.tm_mday;
(*tm_struct_ptr).tm_mon = result_tm.tm_mon;
(*tm_struct_ptr).tm_year = result_tm.tm_year;
(*tm_struct_ptr).tm_wday = result_tm.tm_wday;
(*tm_struct_ptr).tm_yday = result_tm.tm_yday;
(*tm_struct_ptr).tm_isdst = result_tm.tm_isdst;
(*tm_struct_ptr).tm_gmtoff = 0;
(*tm_struct_ptr).tm_zone = 0;
2018-12-07 14:50:35 +01:00
2018-12-11 17:05:07 +01:00
tm_struct_offset as _
2018-11-26 23:27:56 +01:00
}
2018-12-07 14:50:35 +01:00
}
/// emscripten: _localtime_r
2019-01-18 00:33:46 -06:00
#[allow(clippy::cast_ptr_alignment)]
pub fn _localtime_r(ctx: &mut Ctx, time_p: u32, result: u32) -> c_int {
2018-12-07 14:50:35 +01:00
debug!("emscripten::_localtime_r {}", time_p);
// NOTE: emscripten seems to want tzset() called in this function
// https://stackoverflow.com/questions/19170721/real-time-awareness-of-timezone-change-in-localtime-vs-localtime-r
2018-11-26 23:27:56 +01:00
2018-11-26 22:15:49 +01:00
unsafe {
2019-01-24 13:04:12 -08:00
let seconds = emscripten_memory_pointer!(ctx.memory(0), time_p) as *const i32;
2019-01-06 23:31:52 -06:00
let timespec = time::Timespec::new(*seconds as _, 0);
let result_tm = time::at(timespec);
2018-12-08 01:38:51 +01:00
2018-12-11 20:42:29 +01:00
// debug!(
// ">>>>>>> time = {}, {}, {}, {}, {}, {}, {}, {}",
// result_tm.tm_sec, result_tm.tm_min, result_tm.tm_hour, result_tm.tm_mday,
// result_tm.tm_mon, result_tm.tm_year, result_tm.tm_wday, result_tm.tm_yday,
// );
2019-01-24 13:04:12 -08:00
let result_addr = emscripten_memory_pointer!(ctx.memory(0), result) as *mut guest_tm;
2018-12-11 20:42:29 +01:00
(*result_addr).tm_sec = result_tm.tm_sec;
(*result_addr).tm_min = result_tm.tm_min;
(*result_addr).tm_hour = result_tm.tm_hour;
(*result_addr).tm_mday = result_tm.tm_mday;
(*result_addr).tm_mon = result_tm.tm_mon;
(*result_addr).tm_year = result_tm.tm_year;
(*result_addr).tm_wday = result_tm.tm_wday;
(*result_addr).tm_yday = result_tm.tm_yday;
(*result_addr).tm_isdst = result_tm.tm_isdst;
(*result_addr).tm_gmtoff = 0;
(*result_addr).tm_zone = 0;
2018-12-11 20:42:29 +01:00
result as _
2018-11-26 22:15:49 +01:00
}
}
/// emscripten: _time
2019-01-18 00:33:46 -06:00
#[allow(clippy::cast_ptr_alignment)]
pub fn _time(ctx: &mut Ctx, time_p: u32) -> i32 {
2018-11-26 22:15:49 +01:00
debug!("emscripten::_time {}", time_p);
unsafe {
2019-01-24 13:04:12 -08:00
let time_p_addr = emscripten_memory_pointer!(ctx.memory(0), time_p) as *mut i64;
libc_time(time_p_addr) as i32 // TODO review i64
2018-11-26 22:15:49 +01:00
}
}
2018-11-26 14:16:51 -08:00
/// emscripten: _strftime
pub fn _strftime(
2019-04-05 13:59:33 -07:00
ctx: &mut Ctx,
s_ptr: c_int,
maxsize: u32,
format_ptr: c_int,
tm_ptr: c_int,
) -> i32 {
2018-11-26 20:29:26 -08:00
debug!(
"emscripten::_strftime {} {} {} {}",
2019-04-05 14:33:49 -07:00
s_ptr, maxsize, format_ptr, tm_ptr
2018-11-26 20:29:26 -08:00
);
2019-04-05 13:59:33 -07:00
#[allow(clippy::cast_ptr_alignment)]
let s = emscripten_memory_pointer!(ctx.memory(0), s_ptr) as *mut c_char;
#[allow(clippy::cast_ptr_alignment)]
let format = emscripten_memory_pointer!(ctx.memory(0), format_ptr) as *const c_char;
#[allow(clippy::cast_ptr_alignment)]
let tm = emscripten_memory_pointer!(ctx.memory(0), tm_ptr) as *const guest_tm;
let format_string = unsafe { std::ffi::CStr::from_ptr(format).to_str().unwrap() };
debug!("=> format_string: {:?}", format_string);
let tm = unsafe { &*tm };
let rust_tm = ::time::Tm {
tm_sec: tm.tm_sec,
tm_min: tm.tm_min,
tm_hour: tm.tm_hour,
tm_mday: tm.tm_mday,
tm_mon: tm.tm_mon,
tm_year: tm.tm_year,
tm_wday: tm.tm_wday,
tm_yday: tm.tm_yday,
tm_isdst: tm.tm_isdst,
tm_utcoff: tm.tm_gmtoff,
tm_nsec: 0,
};
let result_str = match ::time::strftime(format_string, &rust_tm) {
Ok(res_string) => res_string,
// TODO: maybe match on e in Err(e) and return different values if required
_ => return 0,
};
// pad for null?
let bytes = result_str.chars().count();
if bytes as u32 > maxsize {
2019-04-29 23:45:38 -05:00
0
2019-04-05 13:59:33 -07:00
} else {
// write output string
for (i, c) in result_str.chars().enumerate() {
unsafe { *s.add(i) = c as c_char };
}
// null terminate?
bytes as i32
}
2018-11-26 14:16:51 -08:00
}
2019-04-05 10:04:39 -07:00
/// emscripten: _strftime_l
pub fn _strftime_l(
ctx: &mut Ctx,
s_ptr: c_int,
maxsize: u32,
format_ptr: c_int,
tm_ptr: c_int,
_last: c_int,
) -> i32 {
debug!(
"emscripten::_strftime_l {} {} {} {}",
s_ptr, maxsize, format_ptr, tm_ptr
);
_strftime(ctx, s_ptr, maxsize, format_ptr, tm_ptr)
}