Skip to content

Commit

Permalink
Refactor starter to use load_image.
Browse files Browse the repository at this point in the history
Note that the progress indicator won't show the correct total number
of files anymore.  This should be fixed in the future by loading files
in parallel and counting progress against the overall total number of
bytes rather than the number of bytes in the current file.
  • Loading branch information
JoeOsborn committed Aug 23, 2023
1 parent 7cb24e6 commit 7bdfc93
Showing 1 changed file with 73 additions and 174 deletions.
247 changes: 73 additions & 174 deletions src/browser/starter.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,122 +369,71 @@ V86Starter.prototype.continue_init = async function(emulator, options)
}
}

var files_to_load = [];

const add_file = (name, file) =>
if(options["state"])
{
if(!file)
{
return;
}

if(file.get && file.set && file.load)
{
files_to_load.push({
name: name,
loadable: file,
});
return;
}

if(name === "bios" || name === "vga_bios" ||
name === "initial_state" || name === "multiboot" ||
name === "bzimage" || name === "initrd")
{
// Ignore async for these because they must be available before boot.
// This should make result.buffer available after the object is loaded
file.async = false;
}
console.warn("Warning: Unknown option 'state'. Did you mean 'initial_state'?");
}

if(file.buffer instanceof ArrayBuffer)
{
var buffer = new v86util.SyncBuffer(file.buffer);
files_to_load.push({
name: name,
loadable: buffer,
});
}
else if(typeof File !== "undefined" && file.buffer instanceof File)
{
// SyncFileBuffer:
// - loads the whole disk image into memory, impossible for large files (more than 1GB)
// - can later serve get/set operations fast and synchronously
// - takes some time for first load, neglectable for small files (up to 100Mb)
//
// AsyncFileBuffer:
// - loads slices of the file asynchronously as requested
// - slower get/set

// Heuristics: If file is larger than or equal to 256M, use AsyncFileBuffer
if(file.async === undefined)
{
file.async = file.buffer.size >= 256 * 1024 * 1024;
}
var image_names = [
"bios", "vga_bios",
"cdrom", "hda", "hdb", "fda", "fdb",
"initial_state", "multiboot",
"bzimage", "initrd",
];

if(file.async)
{
var buffer = new v86util.AsyncFileBuffer(file.buffer);
}
else
{
var buffer = new v86util.SyncFileBuffer(file.buffer);
}
var total = 0;
var current_file_index = 0;
var current_file_size = 0;
var current_file_name = null;

files_to_load.push({
name: name,
loadable: buffer,
});
}
else if(file.url)
function mk_progress(starter, index, size, url)
{
return function progress(e)
{
if(file.async)
if(e.target.status === 200)
{
let buffer;

if(file.use_parts)
{
buffer = new v86util.AsyncXHRPartfileBuffer(file.url, file.size, file.fixed_chunk_size, false, this.zstd_decompress_worker.bind(this));
}
else
{
buffer = new v86util.AsyncXHRBuffer(file.url, file.size, file.fixed_chunk_size);
}

files_to_load.push({
name: name,
loadable: buffer,
starter.emulator_bus.send("download-progress", {
file_index: index,
file_count: total,
file_name: url,

lengthComputable: e.lengthComputable,
total: e.total || size,
loaded: e.loaded,
});
}
else
{
files_to_load.push({
name: name,
url: file.url,
size: file.size,
starter.emulator_bus.send("download-error", {
file_index: index,
file_count: total,
file_name: url,
request: e.target,
});
}
}
else
{
dbg_log("Ignored file: url=" + file.url + " buffer=" + file.buffer);
}
};

if(options["state"])
{
console.warn("Warning: Unknown option 'state'. Did you mean 'initial_state'?");
};
}

var image_names = [
"bios", "vga_bios",
"cdrom", "hda", "hdb", "fda", "fdb",
"initial_state", "multiboot",
"bzimage", "initrd",
];

for(var i = 0; i < image_names.length; i++)
{
add_file(image_names[i], options[image_names[i]]);
let name = image_names[i];
let file = options[image_names[i]];
if(!file) { continue; }
if(name === "bios" || name === "vga_bios" ||
name === "initial_state" || name === "multiboot" ||
name === "bzimage" || name === "initrd")
{
// Ignore async for these because they must be available before boot.
// This should make result.buffer available after the object is loaded
file.async = false;
}
total += 1;
let img = await this.load_image(file, mk_progress(this, total-1, file.size, file.url || name));
if(img)
{
put_on_settings.call(this, name, img.buffer);
}
}

if(options["filesystem"])
Expand Down Expand Up @@ -512,81 +461,18 @@ V86Starter.prototype.continue_init = async function(emulator, options)
fs_url = fs_url.url;
}
dbg_assert(typeof fs_url === "string");

files_to_load.push({
total += 1;
let img = await this.load_image({
name: "fs9p_json",
url: fs_url,
size: size,
as_json: true,
});
}, mk_progress(this, total-1, size, fs_url));
put_on_settings.call(this, "fs9p_json", img.buffer);
}
}

var starter = this;
var total = files_to_load.length;

var cont = function(index)
{
if(index === total)
{
setTimeout(done.bind(this), 0);
return;
}

var f = files_to_load[index];

if(f.loadable)
{
f.loadable.onload = function(e)
{
put_on_settings.call(this, f.name, f.loadable);
cont(index + 1);
}.bind(this);
f.loadable.load();
}
else
{
v86util.load_file(f.url, {
done: function(result)
{
if(f.url.endsWith(".zst") && f.name !== "initial_state")
{
dbg_assert(f.size, "A size must be provided for compressed images");
result = this.zstd_decompress(f.size, new Uint8Array(result));
}

put_on_settings.call(this, f.name, f.as_json ? result : new v86util.SyncBuffer(result));
cont(index + 1);
}.bind(this),
progress: function progress(e)
{
if(e.target.status === 200)
{
starter.emulator_bus.send("download-progress", {
file_index: index,
file_count: total,
file_name: f.url,

lengthComputable: e.lengthComputable,
total: e.total || f.size,
loaded: e.loaded,
});
}
else
{
starter.emulator_bus.send("download-error", {
file_index: index,
file_count: total,
file_name: f.url,
request: e.target,
});
}
},
as_json: f.as_json,
});
}
}.bind(this);
cont(0);
setTimeout(done.bind(this), 0);

async function done()
{
Expand Down Expand Up @@ -1431,11 +1317,12 @@ V86Starter.prototype.write_memory = function(blob, offset)
* explicitly given buffer.
*
* @param {Object} file
* @param {function(*) | undefined} on_progress
* @return {Promise<Object>}
* @export
*/

V86Starter.prototype.load_image = async function(file)
V86Starter.prototype.load_image = async function(file, on_progress)
{
if(file.buffer && file.buffer.get && file.buffer.set && file.buffer.load)
{
Expand All @@ -1450,8 +1337,8 @@ V86Starter.prototype.load_image = async function(file)

if(file.buffer instanceof ArrayBuffer)
{
var buffer = new v86util.SyncBuffer(file.buffer);
image.buffer = await new Promise((resolve, reject) => {
image.buffer = new v86util.SyncBuffer(file.buffer);
await new Promise((resolve, reject) => {
image.buffer.onload = (e) => resolve(buffer);
image.buffer.load();
});
Expand Down Expand Up @@ -1483,7 +1370,8 @@ V86Starter.prototype.load_image = async function(file)
var buffer = new v86util.SyncFileBuffer(file.buffer);
}

image.buffer = await new Promise((resolve, reject) => {
image.buffer = buffer;
await new Promise((resolve, reject) => {
image.buffer.onload = (e) => resolve(buffer);
image.buffer.load();
});
Expand All @@ -1503,7 +1391,8 @@ V86Starter.prototype.load_image = async function(file)
{
buffer = new v86util.AsyncXHRBuffer(file.url, file.size, file.fixed_chunk_size);
}
image.buffer = await new Promise((resolve, reject) => {
image.buffer = buffer;
await new Promise((resolve, reject) => {
image.buffer.onload = (e) => resolve(buffer);
image.buffer.load();
});
Expand All @@ -1513,8 +1402,18 @@ V86Starter.prototype.load_image = async function(file)
{
image.buffer = await new Promise((resolve, reject) => {
v86util.load_file(file.url, {
done: (result) => resolve(new v86util.SyncBuffer(result))
})
done: function(result)
{
if(file.url.endsWith(".zst") && file.name !== "initial_state")
{
dbg_assert(file.size, "A size must be provided for compressed images");
result = this.zstd_decompress(file.size, new Uint8Array(result));
}
resolve(file.as_json ? result : new v86util.SyncBuffer(result));
}.bind(this),
progress: on_progress,
as_json: file.as_json,
});
});
return image;
}
Expand Down

0 comments on commit 7bdfc93

Please sign in to comment.