WebAssembly progress

The first thing I found is about Protection::NONE

The crate supports Protection::NONE, which implies that the area cannot be read from or written to. This causes a few tests to fail when they try to drop the area when it goes out of scope. This is because we use the area_for() function to find the area_id of an area, but Haiku is designed to not return the area_id for an area that cannot be read from or written to. See around line 3789 in src/system/kernel/vm/vm.cpp.

Four approaches to this:

  • You could try to argue that the behavior of area_for() is wrong, and that it should also be able to find areas that do not have read or write access. You would need to investigate the history though. This would be a Haiku change.
  • You could avoid area_for() in the free() function, and instead just iterate through all areas and try to match the address yourself. This is not super optimal, but it will work.
  • You could refactor the Allocation struct in alloc.rs to support platform-specific handles. This would store the area_id in haiku, and store nothing in other platforms.
  • You could just ignore the broken tests. area_for() is also used in the platform specific protect() function, so that will break too if the area is initially set up for Protection::NONE.

This causes the problems in tests alloc_size_is_aligned_to_page_size() and alloc_can_allocate_unused_region ()

2 Likes

THANKS! That helps a lot! The Windows iterator just tries and finds out what is possible but the OS doesn’t supply an iterator function. I may be able to do something like that!

THANKS AGAIN!

Edit

Option 3 might be even better.

A second thing you may want to look at is the implementation of QueryIter::new(). The first test you do there is to use area_for() on the start address. This seems to be incorrect with how this method may be used, as the documentation for the query_range() function that calls this OS implementation explicitly allows to use ranges that are outside of the existing ranges.

1 Like

Actually your whole implementation of QueryIter does not make sense. You need to write something that uses get_next_area_info() to loop through all the areas. The QueryIter::new() function should only set up the iterator, it is the QueryIter::next() that should return an area id, or return None if there are no more values within that address range.

Edit: that’s enough homework for now :grinning:

1 Like

Option 3 might be even better.

I think option 3 is probably best, but option 2 will probably be easiest for now and allow you to go forward with testing the rest of the implementation.

1 Like

If this is only for deallocation, I think you can call unmap instead of delete_area(area_for(...)) and it will work just as well. (I’m pretty sure we take advantage of this ourselves in some places.)

Thanks, but I found a spot in src/lib.rs that lets me change the dereference method of the AllocatedPages structure. All I had to do was exclude Haiku from the POSIX implementation and write custom Haiku code based on the Area commands.

Update

The query may work the same way. I’m ditching their wrapper and writing my own, I think.

1 Like

Bad News

After trying to replace the area_for() function with a static hash map as would be required by option 3, it seems this was a dead end. Rust, in all of its safety, refuses to create a static handle to a hash map structure. Even if the key and value members are all safe behind mutexes, Rust can’t do it anyway. I’m not sure option 2 would be much easier because it would still require some sort of memory handle. I’m thinking making a wrapper around the std::slice datatype in Rust might be easier at this point. It would still need to be a wrapper though, because std::slice also doesn’t support Protection::NONE.

Update

Apart from the Rust compiler refusing to make a HashMap with static visibility, I’ve gotten the rest of the code in the Region crate to compile on Haiku. I can’t get the unit tests to run without that last bug solved though.

Update2

Using a third-party dependency, it is possible to do it.

https://crates.io/crates/lazy_static/1.4.0

Update3

Once in std::sync - Rust may do the same thing without adding a third-party dependency.

Why is this written the way that it is? Rust is concurrent multithreaded and it needs to be told when to execute the static initializer so that it doesn’t run in multiple threads. Using a mutex isn’t enough. Tomorrow I’ll try out these solutions and hopefully get past this roadblock.

2 Likes

Some Success!

Now that I’ve added the lazy_static crate to the dependencies (duplicating the effort with it was not worth the time in the end) and copied the in-code documentation from alloc.rs, the code builds again. There are 11 succeeding unit-tests and 16 that fail again but now it only has 2 allocation problems and those may be related to failing queries or protection tests. I’m on the right track. Thanks, @nielx for getting me on the right track!

10 Likes

Upon closer examination 11 of the 16 failed unit-tests are giving the same error message: InvalidParameter(ā€œCould not find any allocated pagesā€) which suggests there may be a race condition in accessing the mutex to the hash map. Another possibility is that the allocations are failing silently for some reason. I always check the return codes from the Haiku subroutines so the former is looking to be more likely than the latter. If that’s the case it may be something as simple as adding a ā€œfenceā€ to make sure the write to the hash map gets through the mutex before the read does.

Update

I tried locking the mutex at the start of every allocation but it made no difference. It’s possible that the create_area() function is not allocating Protection::NONE protected regions.

Problem Found

fix_protection() is incompatible with the region crate altogether. It is called by create_area() which is called by all user code.

3 Likes

How is fix_protection incompatible with Region? All it does is make sure the kernel has the same access to an area that userland does. How can this cause any problems for userland applications?

It appears to require that memory being allocated is at least readable. The unit tests of the Region crate need memory allocated with the no permission to read, write nor execute. It may just be a problem with the unit tests themselves in the long run.

WebKit does the exact same thing (allocating areas with PROT_NONE.) That’s perfectly valid and it works just fine.

The kernel will give itself read permissions, yes, but these are a totally separate permissions system from the userland ones, and userland cannot see them at all.

1 Like

Thanks! That eliminated the likeliest cause of failure. Now I have to find the actual cause.

It seems that the hash map I put in to replace the AreaFor() commands are reporting allocations as not found. It’s the only place that error could have been reported from. The allocations must have succeeded, I think.

Update

It occurred to me this morning that Wasmer was written for Region crate version 2.x so if it isn’t using the 3.0 features I’m trying to fix, it might just already work. Some Wasmer crates already do.

Now I’m working on the actual source of Wasmer proper. It’s forked and I’m working on the vm. I’m down to the point where the Wasmer VM is allocating an alternate stack for the event handling. The Unix-like operating systems need 64k while the stack supplied by Windows’ default is big enough already and the code does nothing. I’ll assume the latter of Haiku for now and see if I can get it to run.

Update2

It built! It’s just the rust crate so far but I’ve made more progress with it today than I have for a month!

15 Likes

:joy:
now is time for the moon. :rocket:

1 Like

Speaking of moon-shots, I have a second interview for a position at Wasmer on Monday. WIsh me well. (Considering all the examples I sent are incomplete snippets and Rust crates, I may need some well-wishing and divine guidance.)

16 Likes

Ooh nice! The engineer job? Looks like it is up your street and that you might even get paid a little for your Haiku work too. Good luck!

1 Like

Thanks! Yes, it’s the compiler engineer job.

2 Likes