The first blogpost since a month! And I have a lot to show (I think). First, a quick round-up of the latest modifications:
- Added views system
- Implemented kernel service model
- Heap locking
- Safety checks & documentation
- Added version numbering
Details after the break!
A "view" in ttOS roughly resembles a window or console. Developers are able to open up to 10 views and give them a title. After that, it's possible to interact with the view (e.g. writing/reading). Users can switch views using CTRL-0 to CTRL-9.
I have reserved view 0 as the "debug view". The kernel will spit out debug messages there, so it doesn't clutter the actual views, and I'm still able to read the debug stuff.
The view's title can be seen in the top-left corner, near the current date/time.
I must admit, this sounds a lot more awesome than it really is. Before this redesign, I simply had a few manager classes which could be retrieved from the kernel singleton. But, this clutters the kernel class, because every time I make a new manager for something, it must be added to the kernel as a private field and a public getter method.
So I started with a ServiceContainer class. This class simply contains a collection of Services. I can register services with it, as well as get a specific service using templates (GetService<ChronoService>()).
The next step was to refactor all manager classes to inherit from the Service base class, and simply register them when the kernel starts. All references to the manager classes had to be replaced with a GetService() call. It seems a lot nicer now, more modular.
Because of this, I can now also print a list of registered services. It doesn't really serve a particular purpose, but it looks cool 😊.
This is just a little nifty feature I added to make sure that certain allocated memory areas can NEVER be freed. For example, you don't want anyone to do "free(kernel)". Especially handy for those methods that simply return a pointer to an otherwise managed resource, like the GetVideoBuffer() method in the View class. It returns a pointer to raw data. A developer is able to free this memory area. If this happens, your entire view will be filled with garbage.
So I set out to add the heap locking feature to the heap manager. Basically, I added an 8-bit flags field to the block header. Only one flag is supported, the LOCKED (0x01) flag. Using heap_set_lock(ptr, bool) you can either enable or disable the lock. When the free() method stumbles upon a locked block, it will crash the system (which is better than undefined behavior).
Safety checks & documentation
Basically, I added a whole bunch of asserts throughout the kernel code. There's a configuration flag called "RELAXED_ASSERT". If set to 1, it just shows a debug message. If set to 0, it will crash the kernel.
I also started to add doxygen documentation to the kernel. This automatically creates some really cool diagrams:
I simply started to tag certain commits in the Git repository with a version. This version number is also shown in the default kernel view (as seen in the screenshots above).
This way, whenever I decide that it's time for a release, I can also write a blogpost about it!