mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 22:25:40 +00:00
Merge pull request #42 from wasmerio/fix/localtime
Fix localtime implementation
This commit is contained in:
commit
83e1a0e75c
@ -97,11 +97,6 @@ pub extern "C" fn _getgrnam(name_ptr: c_int, instance: &mut Instance) -> c_int {
|
||||
}
|
||||
}
|
||||
|
||||
pub extern "C" fn _localtime_r() -> u32 {
|
||||
debug!("emscripten::_localtime_r");
|
||||
0
|
||||
}
|
||||
|
||||
pub extern "C" fn _getpagesize() -> u32 {
|
||||
debug!("emscripten::_getpagesize");
|
||||
16384
|
||||
|
@ -18,7 +18,7 @@ mod time;
|
||||
mod utils;
|
||||
mod varargs;
|
||||
|
||||
pub use self::storage::{align_memory, static_alloc};
|
||||
pub use self::storage::{align_memory};
|
||||
pub use self::utils::{is_emscripten_module, allocate_on_stack, allocate_cstr_on_stack};
|
||||
|
||||
// TODO: Magic number - how is this calculated?
|
||||
@ -44,12 +44,6 @@ fn dynamictop_ptr(static_bump: u32) -> u32 {
|
||||
static_bump + DYNAMICTOP_PTR_DIFF
|
||||
}
|
||||
|
||||
// fn static_alloc(size: usize, static_top: &mut size) -> usize {
|
||||
// let ret = *static_top;
|
||||
// *static_top = (*static_top + size + 15) & (-16 as usize);
|
||||
// ret
|
||||
// }
|
||||
|
||||
pub fn emscripten_set_up_memory(memory: &mut LinearMemory) {
|
||||
let dynamictop_ptr = dynamictop_ptr(STATIC_BUMP) as usize;
|
||||
let dynamictop_ptr_offset = dynamictop_ptr + mem::size_of::<u32>();
|
||||
@ -383,6 +377,16 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
|
||||
"_clock_gettime",
|
||||
ImportValue::Func(time::_clock_gettime as _),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
"_asctime",
|
||||
ImportValue::Func(time::_asctime as _),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
"_asctime_r",
|
||||
ImportValue::Func(time::_asctime_r as _),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
"_localtime",
|
||||
@ -393,7 +397,7 @@ pub fn generate_emscripten_env<'a, 'b>() -> ImportObject<&'a str, &'b str> {
|
||||
import_object.set(
|
||||
"env",
|
||||
"_localtime_r",
|
||||
ImportValue::Func(env::_localtime_r as _),
|
||||
ImportValue::Func(time::_localtime_r as _),
|
||||
);
|
||||
import_object.set(
|
||||
"env",
|
||||
|
@ -4,22 +4,15 @@ pub fn align_memory(ptr: u32) -> u32 {
|
||||
(ptr + 15) & !15
|
||||
}
|
||||
|
||||
// pub fn static_alloc(size: u32, instance: &mut Instance) -> u32 {
|
||||
// let static_top = instance.emscripten_data.static_top;
|
||||
// let total_memory = instance.memories[0].maximum.unwrap_or(LinearMemory::DEFAULT_HEAP_SIZE as u32);
|
||||
// instance.emscripten_data.static_top = (static_top + size + 15) & 4294967280;
|
||||
// assert!(static_top < total_memory, "not enough memory for static allocation - increase total_memory!");
|
||||
// static_top
|
||||
// }
|
||||
|
||||
pub fn static_alloc(size: u32, static_top: &mut u32, memory: &LinearMemory) -> u32 {
|
||||
let old_static_top = *static_top;
|
||||
let total_memory = memory.maximum_size() * LinearMemory::PAGE_SIZE;
|
||||
// NOTE: The `4294967280` is a u32 conversion of -16 as gotten from emscripten.
|
||||
*static_top = (*static_top + size + 15) & 4_294_967_280;
|
||||
assert!(
|
||||
*static_top < total_memory,
|
||||
"not enough memory for static allocation - increase total_memory!"
|
||||
);
|
||||
old_static_top
|
||||
}
|
||||
// pub fn static_alloc(size: u32, static_top: &mut u32, memory: &LinearMemory) -> u32 {
|
||||
// let old_static_top = *static_top;
|
||||
// let total_memory = memory.maximum_size() * LinearMemory::PAGE_SIZE;
|
||||
// // NOTE: The `4294967280` is a u32 conversion of -16 as gotten from emscripten.
|
||||
// *static_top = (*static_top + size + 15) & 4294967280;
|
||||
// assert!(
|
||||
// *static_top < total_memory,
|
||||
// "not enough memory for static allocation - increase total_memory!"
|
||||
// );
|
||||
// old_static_top
|
||||
// }
|
||||
|
@ -1,13 +1,15 @@
|
||||
use super::utils::copy_cstr_into_wasm;
|
||||
use super::utils::{copy_cstr_into_wasm, write_to_buf};
|
||||
use libc::{
|
||||
c_int,
|
||||
c_long,
|
||||
clock_gettime as libc_clock_gettime,
|
||||
// tm,
|
||||
localtime,
|
||||
localtime_r,
|
||||
tm,
|
||||
time,
|
||||
time_t,
|
||||
timespec,
|
||||
c_char,
|
||||
};
|
||||
use std::mem;
|
||||
use std::time::SystemTime;
|
||||
@ -64,50 +66,163 @@ pub extern "C" fn _clock_gettime(clk_id: c_int, tp: c_int, instance: &mut Instan
|
||||
0
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct guest_tm {
|
||||
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
|
||||
pub tm_zone: c_int, // 40
|
||||
}
|
||||
|
||||
/// emscripten: _tvset
|
||||
pub extern "C" fn _tvset() {
|
||||
debug!("emscripten::_tvset UNIMPLEMENTED");
|
||||
}
|
||||
|
||||
/// formats time as a C string
|
||||
unsafe extern "C" fn fmt_time(time: u32, instance: &Instance) -> *const c_char {
|
||||
let date = &*(instance.memory_offset_addr(0, time as _) as *mut guest_tm);
|
||||
|
||||
let days = vec!["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
let months = vec!["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
||||
let year = 1900 + date.tm_year;
|
||||
|
||||
let time_str = format!(
|
||||
// NOTE: TODO: Hack! The 14 accompanying chars are needed for some reason
|
||||
"{} {} {: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 _
|
||||
}
|
||||
|
||||
/// emscripten: _asctime
|
||||
pub extern "C" fn _asctime(time: u32, instance: &mut Instance) -> u32 {
|
||||
debug!("emscripten::_asctime {}", time);
|
||||
|
||||
unsafe {
|
||||
let time_str_ptr = fmt_time(time, instance);
|
||||
copy_cstr_into_wasm(instance, time_str_ptr)
|
||||
|
||||
// let c_str = instance.memory_offset_addr(0, time_str_offset as _) as *mut i8;
|
||||
// use std::ffi::CStr;
|
||||
// debug!("#### cstr = {:?}", CStr::from_ptr(c_str));
|
||||
}
|
||||
}
|
||||
|
||||
/// emscripten: _asctime_r
|
||||
pub extern "C" fn _asctime_r(time: u32, buf: u32, instance: &mut Instance) -> u32 {
|
||||
debug!("emscripten::_asctime_r {}", time);
|
||||
|
||||
unsafe {
|
||||
// NOTE: asctime_r is specced to behave in an undefined manner if the algorithm would attempt
|
||||
// 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(time, instance);
|
||||
write_to_buf(time_str_ptr, buf, 26, instance)
|
||||
|
||||
// let c_str = instance.memory_offset_addr(0, time_str_offset as _) as *mut i8;
|
||||
// use std::ffi::CStr;
|
||||
// debug!("#### cstr = {:?}", CStr::from_ptr(c_str));
|
||||
}
|
||||
}
|
||||
|
||||
/// emscripten: _localtime
|
||||
pub extern "C" fn _localtime(time_p: u32, instance: &mut Instance) -> c_int {
|
||||
debug!("emscripten::_localtime {}", time_p);
|
||||
|
||||
#[repr(C)]
|
||||
struct GuestTm {
|
||||
tm_sec: i32,
|
||||
tm_min: i32,
|
||||
tm_hour: i32,
|
||||
tm_mday: i32,
|
||||
tm_mon: i32,
|
||||
tm_year: i32,
|
||||
tm_wday: i32,
|
||||
tm_yday: i32,
|
||||
tm_isdst: i32,
|
||||
tm_gmtoff: c_long,
|
||||
tm_zone: u32,
|
||||
}
|
||||
// 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
|
||||
|
||||
unsafe {
|
||||
let time_p_addr = instance.memory_offset_addr(0, time_p as _) as *mut i64;
|
||||
let tm_struct = &*localtime(time_p_addr);
|
||||
|
||||
// Webassembly allocation
|
||||
let result_tm = &*localtime(time_p_addr);
|
||||
let tm_struct_offset = (instance.emscripten_data.as_ref().unwrap().malloc)(
|
||||
mem::size_of::<GuestTm>() as _,
|
||||
mem::size_of::<guest_tm>() as _,
|
||||
instance,
|
||||
);
|
||||
let tm_struct_ptr = instance.memory_offset_addr(0, tm_struct_offset as _) as *mut GuestTm;
|
||||
|
||||
// Initializing
|
||||
(*tm_struct_ptr).tm_sec = tm_struct.tm_sec;
|
||||
(*tm_struct_ptr).tm_min = tm_struct.tm_min;
|
||||
(*tm_struct_ptr).tm_hour = tm_struct.tm_hour;
|
||||
(*tm_struct_ptr).tm_mday = tm_struct.tm_mday;
|
||||
(*tm_struct_ptr).tm_mon = tm_struct.tm_mon;
|
||||
(*tm_struct_ptr).tm_year = tm_struct.tm_year;
|
||||
(*tm_struct_ptr).tm_wday = tm_struct.tm_wday;
|
||||
(*tm_struct_ptr).tm_yday = tm_struct.tm_yday;
|
||||
(*tm_struct_ptr).tm_isdst = tm_struct.tm_isdst;
|
||||
(*tm_struct_ptr).tm_gmtoff = tm_struct.tm_gmtoff;
|
||||
(*tm_struct_ptr).tm_zone = copy_cstr_into_wasm(instance, tm_struct.tm_zone);
|
||||
let tm_struct_ptr = instance.memory_offset_addr(0, tm_struct_offset as _) as *mut guest_tm;
|
||||
// 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,
|
||||
// );
|
||||
|
||||
tm_struct_offset as c_int
|
||||
(*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 = result_tm.tm_gmtoff as i32;
|
||||
(*tm_struct_ptr).tm_zone = copy_cstr_into_wasm(instance, result_tm.tm_zone) as i32;
|
||||
|
||||
tm_struct_offset as _
|
||||
}
|
||||
}
|
||||
/// emscripten: _localtime_r
|
||||
pub extern "C" fn _localtime_r(time_p: u32, result: u32, instance: &mut Instance) -> c_int {
|
||||
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
|
||||
|
||||
unsafe {
|
||||
let time_p_addr = instance.memory_offset_addr(0, time_p as _) as *mut i64;
|
||||
let result_addr = instance.memory_offset_addr(0, result as _) as *mut guest_tm;
|
||||
|
||||
let mut result_tm = tm {
|
||||
tm_sec: (*result_addr).tm_sec,
|
||||
tm_min: (*result_addr).tm_min,
|
||||
tm_hour: (*result_addr).tm_hour,
|
||||
tm_mday: (*result_addr).tm_mday,
|
||||
tm_mon: (*result_addr).tm_mon,
|
||||
tm_year: (*result_addr).tm_year,
|
||||
tm_wday: (*result_addr).tm_wday,
|
||||
tm_yday: (*result_addr).tm_yday,
|
||||
tm_isdst: (*result_addr).tm_isdst,
|
||||
tm_gmtoff: (*result_addr).tm_gmtoff as _,
|
||||
tm_zone: instance.memory_offset_addr(0, (*result_addr).tm_zone as _) as _,
|
||||
};
|
||||
|
||||
localtime_r(time_p_addr, &mut result_tm);
|
||||
// let tm_struct = result_tm;
|
||||
// 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,
|
||||
// );
|
||||
|
||||
(*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 = result_tm.tm_gmtoff as _;
|
||||
(*result_addr).tm_zone = copy_cstr_into_wasm(instance, result_tm.tm_zone) as _;
|
||||
|
||||
result as _
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,18 @@ pub fn is_emscripten_module(module: &Module) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub unsafe fn write_to_buf(string: *const c_char, buf: u32, max: u32, instance: &Instance) -> u32 {
|
||||
let buf_addr = instance.memory_offset_addr(0, buf as _) as *mut c_char;
|
||||
|
||||
unsafe {
|
||||
for i in 0..max {
|
||||
*buf_addr.add(i as _) = *string.add(i as _);
|
||||
}
|
||||
}
|
||||
|
||||
buf
|
||||
}
|
||||
|
||||
pub unsafe fn copy_cstr_into_wasm(instance: &mut Instance, cstr: *const c_char) -> u32 {
|
||||
let s = CStr::from_ptr(cstr).to_str().unwrap();
|
||||
let cstr_len = s.len();
|
||||
@ -28,6 +40,8 @@ pub unsafe fn copy_cstr_into_wasm(instance: &mut Instance, cstr: *const c_char)
|
||||
*loc = byte;
|
||||
}
|
||||
|
||||
// TODO: Appending null byte won't work, because there is CStr::from_ptr(cstr)
|
||||
// at the top that crashes when there is no null byte
|
||||
*raw_memory.add(cstr_len) = 0;
|
||||
|
||||
space_offset
|
||||
|
Loading…
Reference in New Issue
Block a user