The underlying data structure is a singly-linked list of Vector<T>.
We never shift any of the vector contents around, but we batch the memory
allocations into 1000-element segments.
Put together a pretty well-performing queue using a Vector and an offset.
By using the new Vector::shift_left(int) instead of Vector::take_first()
we can avoid shifting the vector contents every time and instead only
do it every so often.
Maybe this could be generalized into a separate class, I'm not sure if it's
the best algorithm though, it's just what I came up with right now. :^)
I've used a SinglyLinkedList<Point> for the flood fill queue, since Vector
was death slow. This could definitely be made faster with a better algorithm
and/or data structure. :^)
This method is used in BXVGADevice to create pages for the framebuffer;
we should neither make the PhysicalPage instances eternal, nor hand over
actual physical pages to the memory allocator.
After PhysicalPage::return_to_freelist(), an actual physical page
is returned back to the memory manager; which will create a new
PhysicalPage instance if it decides to reuse the physical page. This
means this PhysicalPage instance should be freed; otherwise it would
get leaked.
This makes no functional difference, but it makes it clear that
MemoryManager and PhysicalRegion take over the actual physical
page represented by this PhysicalPage instance.
Pages created with PhysicalPage::create_eternal() should *not* be
returnable to the freelist; and pages created with the regular
PhysicalPage::create() should be; not the other way around.
A glob has to be resolved against the directory corresponding to
the part of the path it is found in, not the current directory.
For example, in /usr/i*/AK/, the glob has to be resolved inside
/usr. Moreover, an argument can contain more than one glob, such
as /u*/*/?, in which case they have to be resolved recursively.
In case a glob matches nothing, the argument should be used as is.
Previously the check for an empty part would happen before the
check for access and for the parent being a directory, and so an
error in those would not be detected.
StringView character buffer is not guaranteed to be null-terminated;
in particular it will not be null-terminated when making a substring.
This means it is not correct to check whether we've reached the end
of a StringView by comparing the next character to null; instead, we
need to do an explicit length (or pointer) comparison.
If a symlink is not the last part of a path, the remaining part
of the path has to be further resolved against the symlink target.
With this, a path containing a symlink always resolves to the target
of the first (leftmost) symlink in it, for example any path of form
/proc/self/... resolves to the corresponding /proc/pid directory.
StringView character buffer is not guaranteed to be null-terminated;
in particular it will not be null-terminated when making a substring.
This means that the buffer can not be used with C functions that expect
a null-terminated string. Instead, StringView provides a convinient
operator == for comparing it with Strings and C stirngs, so use that.
This fixes /proc/self/... resolution failures in ProcFS, since the name
("self") passed to ProcFSInode::lookup() would not be null-terminated.
This significantly reduces the pressure on the kernel heap when
allocating a lot of pages.
Previously at about 250MB allocated, the free page list would outgrow
the kernel's heap. Given that there is no longer a page list, this does
not happen.
The next barrier will be the kernel memory used by the page records for
in-use memory. This kicks in at about 1GB.
This makes checkable buttons exclusive with other checkable buttons in the
same parent widget. Basically like radio buttons. This should probably be
used to implement GRadioButton once it's a bit more mature.