It's much less a library than an API that can be implemented in a C library or kernel that has implementations written for it. Similar idea to CDI/UDI, but substitute driver with allocator.
Creature wrote:I also suggest there'd be some sort of "initialize" function (or somehow do this through brk()) that allows you to tell the memory allocator where it is located or the first block should start. This way you can take care of mapping that part of virtual memory in. The rest of 'heap expansion' would then go through brk() or a similar function.
I recently had an idea about this, and the whole issue of low level memory management. You would give some sort of an initializer function the initial virtual memory region, then the allocator could request additional virtual memory from the OS. However, the actual state of these regions would be undefined: the allocator would call an "activate" function on a region to make sure there are frames with certain permissions in it, and a "deactivate" function to release that region from the need to have frames. The system could decide whether to have all regions preallocated (or not use paging) and ignore these calls, or to respond to these calls.
Creature wrote:Finally, maybe it would be feasible to have multiple types of memory allocators inside the API, such as a standard allocator, a slab allocator, and so on for specific purposes. I only see one problem however: will different architectures be supported? For starters, x86-32 seems feasible, but x86-64 OS' may want to take advantage of larger address spaces or 8-byte integers. Similarly, other architectures like ARM may require other implementations. You could also of course limit yourself to the x86 or a couple of architectures.
I think it makes most sense to make allocators instantiated (as structure-objects), so you can have any number of duplicate or different allocators on a system. The kernel/library writer would be responsible for plugging specific instances into things like malloc(), free(), etc. Allocators can easily be written to be portable across architectures and 16/32/64 bit, by using appropriate types like uintptr_t. A C allocator is as portable as C itself. Similarly, for assembly-written allocators, it will be architecture specific.
I think we can assume a flat (probably paged) address space, and that will work. By probably paged, I mean the allocators could be designed for paged systems, but if the system is not paged, all it will suffer is a loss in memory efficiency. You could easily have allocators written specifically to assume a non-paged system, but even these would work on a paged system too.
rdos wrote:I think you missed some of my point. A page-aligned allocator needs to be aware of paging, and page-tables. It cannot stand alone. A byte-aligned allocator might be more stand-alone, but it still requires some kind of integration into the paging system in order to operate properly (mostly because unallocated space should page-fault when referenced, and for allocating physical memory in page-tables).
I also don't think a C/C++ implementation of a memory allocator could possibly be used in an assembler-only OS, as it might require some C-library support.
A page aligned allocator does have to be aware of the page size, but nothing else. The paging system, even in the kernel, can be invoked in an OS-agnostic way just like in the C library.
It would work to have a small set of the C library string functions (memcpy, memset should be enough); this is as much of the C library as would be needed, and not much trouble to implement in assembly. The major issue for assembly programmers is that every interface function would require using the same calling convention as the C compiler's calling convention (usually cdecl). Without guaranteeing this, it would be impossible to have a real cross-platform API.