Compare commits
4 Commits
34be439843
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| f575d22cb5 | |||
| 1f13f2025a | |||
| 475ef950d9 | |||
| 038d924916 |
@ -164,7 +164,7 @@ table thead tr th, table tfoot tr th, table tbody tr td, table tr td, table tfoo
|
|||||||
.clearfix:before, .clearfix:after, .float-group:before, .float-group:after { content: " "; display: table; }
|
.clearfix:before, .clearfix:after, .float-group:before, .float-group:after { content: " "; display: table; }
|
||||||
.clearfix:after, .float-group:after { clear: both; }
|
.clearfix:after, .float-group:after { clear: both; }
|
||||||
|
|
||||||
*:not(pre) > code { font-size: 0.9375em; padding: 1px 3px 0; white-space: nowrap; background-color: #f2f2f2; border: 1px solid #cccccc; -webkit-border-radius: 4px; border-radius: 4px; text-shadow: none; }
|
*:not(pre) > code { font-size: 0.9375em; padding: 1px 3px 0; white-space: nowrap; background-color: #060606; text-shadow: none; }
|
||||||
|
|
||||||
/*pre, pre > code { line-height: 1.4; color: inherit; font-family: Consolas, "Liberation Mono", Courier, monospace; font-weight: normal; }*/
|
/*pre, pre > code { line-height: 1.4; color: inherit; font-family: Consolas, "Liberation Mono", Courier, monospace; font-weight: normal; }*/
|
||||||
|
|
||||||
|
|||||||
@ -22,7 +22,7 @@ body {
|
|||||||
height: 60px;
|
height: 60px;
|
||||||
}
|
}
|
||||||
#footer {
|
#footer {
|
||||||
background-color: #f5f5f5;
|
background-color: #060606;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,4 +49,4 @@ body {
|
|||||||
|
|
||||||
/*code {
|
/*code {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
}*/
|
}*/
|
||||||
|
|||||||
16
assets/css/bootstrap.min.css
vendored
16
assets/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@ -1 +1,118 @@
|
|||||||
.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
|
/*
|
||||||
|
* Derived from einaros's Sons of Obsidian theme at
|
||||||
|
* http://studiostyl.es/schemes/son-of-obsidian by
|
||||||
|
* Alex Ford of CodeTunnel:
|
||||||
|
* http://CodeTunnel.com/blog/post/71/google-code-prettify-obsidian-theme
|
||||||
|
*/
|
||||||
|
|
||||||
|
.str
|
||||||
|
{
|
||||||
|
color: #EC7600;
|
||||||
|
}
|
||||||
|
.kwd
|
||||||
|
{
|
||||||
|
color: #93C763;
|
||||||
|
}
|
||||||
|
.com
|
||||||
|
{
|
||||||
|
color: #66747B;
|
||||||
|
}
|
||||||
|
.typ
|
||||||
|
{
|
||||||
|
color: #678CB1;
|
||||||
|
}
|
||||||
|
.lit
|
||||||
|
{
|
||||||
|
color: #FACD22;
|
||||||
|
}
|
||||||
|
.pun
|
||||||
|
{
|
||||||
|
color: #F1F2F3;
|
||||||
|
}
|
||||||
|
.pln
|
||||||
|
{
|
||||||
|
color: #F1F2F3;
|
||||||
|
}
|
||||||
|
.tag
|
||||||
|
{
|
||||||
|
color: #8AC763;
|
||||||
|
}
|
||||||
|
.atn
|
||||||
|
{
|
||||||
|
color: #E0E2E4;
|
||||||
|
}
|
||||||
|
.atv
|
||||||
|
{
|
||||||
|
color: #EC7600;
|
||||||
|
}
|
||||||
|
.dec
|
||||||
|
{
|
||||||
|
color: purple;
|
||||||
|
}
|
||||||
|
pre.prettyprint
|
||||||
|
{
|
||||||
|
border: 0px solid #888;
|
||||||
|
}
|
||||||
|
ol.linenums
|
||||||
|
{
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.prettyprint {
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
li.L0, li.L1, li.L2, li.L3, li.L4, li.L5, li.L6, li.L7, li.L8, li.L9
|
||||||
|
{
|
||||||
|
color: #555;
|
||||||
|
list-style-type: decimal;
|
||||||
|
}
|
||||||
|
li.L1, li.L3, li.L5, li.L7, li.L9 {
|
||||||
|
background: #111;
|
||||||
|
}
|
||||||
|
@media print
|
||||||
|
{
|
||||||
|
.str
|
||||||
|
{
|
||||||
|
color: #060;
|
||||||
|
}
|
||||||
|
.kwd
|
||||||
|
{
|
||||||
|
color: #006;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.com
|
||||||
|
{
|
||||||
|
color: #600;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.typ
|
||||||
|
{
|
||||||
|
color: #404;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.lit
|
||||||
|
{
|
||||||
|
color: #044;
|
||||||
|
}
|
||||||
|
.pun
|
||||||
|
{
|
||||||
|
color: #440;
|
||||||
|
}
|
||||||
|
.pln
|
||||||
|
{
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.tag
|
||||||
|
{
|
||||||
|
color: #006;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.atn
|
||||||
|
{
|
||||||
|
color: #404;
|
||||||
|
}
|
||||||
|
.atv
|
||||||
|
{
|
||||||
|
color: #060;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
BIN
assets/img/fatfs-showcase1.png
Normal file
BIN
assets/img/fatfs-showcase1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
BIN
assets/img/fatfs-showcase2.png
Normal file
BIN
assets/img/fatfs-showcase2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
BIN
assets/img/fs-design-diagram1.png
Normal file
BIN
assets/img/fs-design-diagram1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/img/mbus-diagram1.png
Normal file
BIN
assets/img/mbus-diagram1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
191
content/blog/MOP2/fatfs-integration.adoc
Normal file
191
content/blog/MOP2/fatfs-integration.adoc
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
= FAT filesystem integration into MOP2
|
||||||
|
Kamil Kowalczyk
|
||||||
|
2025-11-19
|
||||||
|
:jbake-type: post
|
||||||
|
:jbake-tags: MOP2 osdev
|
||||||
|
:jbake-status: published
|
||||||
|
|
||||||
|
Hello, World!
|
||||||
|
|
||||||
|
I would like to present to you FAT filesystem integration into the MOP2 operating system! This was
|
||||||
|
possible thanks to `fat_io_lib` library by UltraEmbedded, because there's no way I'm writing an
|
||||||
|
entire FAT driver from scratch ;).
|
||||||
|
|
||||||
|
Source for `fat_io_lib`: https://github.com/ultraembedded/fat_io_lib
|
||||||
|
|
||||||
|
== Needed changes and a "contextual" system
|
||||||
|
|
||||||
|
Integrating fat_io_lib wasn't so straightforward as I thought it would be. To understand the problem
|
||||||
|
we need to first understand the current design of MOP2's VFS.
|
||||||
|
|
||||||
|
=== MOP2's VFS explained
|
||||||
|
|
||||||
|
image::/img/fs-design-diagram1.png["FS diagram"]
|
||||||
|
|
||||||
|
The VFS (ie. Virtual File System) is a Windows/DOS-style labeled VFS. Mountpoints are identified by
|
||||||
|
a label, like for eg. `sys:/boot/mop2` or `base:/scripts/mount.tb`, which kinda looks like
|
||||||
|
`C:\Path\To\File` in Windows. I've chosen this style of VFS over the UNIX kind, because it makes more
|
||||||
|
sense to me personally. A mountpoint label can point to a physical device, a virtual device (ramsd)
|
||||||
|
or a subdevice/partition device. In the UNIX world on the other hand, we have a hierarchical VFS, so
|
||||||
|
paths look like `/`, `/proc`, `/dev`, etc. This is a little confusing to reason about, because you'd
|
||||||
|
think that if `/` is mounted let's say on a drive `sda0`, then `/home` would be a home directory
|
||||||
|
within the root of that device. This is not always the case. `/` can be placed on `sda0`, but `/home`
|
||||||
|
can be placed on `sdb0`, so now something that looks like a subdirectory, is now a pointer to an
|
||||||
|
entirely different media. Kinda confusing, eh?
|
||||||
|
|
||||||
|
=== The problem
|
||||||
|
|
||||||
|
So now that we know how MOP2's VFS works, let's get into low-level implementation details. To handle
|
||||||
|
mountpoints we use a basic hashtable. We just map the label to the proper underlying file system
|
||||||
|
driver like so:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
base -> Little FS
|
||||||
|
uhome -> Little FS
|
||||||
|
sys -> FAT16
|
||||||
|
----
|
||||||
|
|
||||||
|
Through this table, we can see that we have two mountpoints (base and uhome), which both use Little
|
||||||
|
FS, but are placed on different media entirely. Base is located on a ramsd, which is entirely virtual
|
||||||
|
and uhome is a partition on a physical drive.
|
||||||
|
|
||||||
|
To manage such setup, we need to have separate filesystem library contexts for each mountpoint.
|
||||||
|
A context here means an object, which stores info like block size, media read/write/sync hooks,
|
||||||
|
media capacity and so on. Luckly, with Little FS we could do this out of the box, because it blesses
|
||||||
|
us with `lfs_t` - an instance object. We can then create this object for each Little FS mountpoint.
|
||||||
|
|
||||||
|
.Internals of the VFS mountpoint structure
|
||||||
|
[source,c]
|
||||||
|
----
|
||||||
|
typedef struct VfsMountPoint {
|
||||||
|
int _hshtbstate;
|
||||||
|
char label[VFS_MOUNTPOINT_LABEL_MAX];
|
||||||
|
|
||||||
|
int32_t fstype;
|
||||||
|
StoreDev *backingsd;
|
||||||
|
|
||||||
|
VfsObj *(*open)(struct VfsMountPoint *vmp, const char *path, uint32_t flags);
|
||||||
|
int32_t (*cleanup)(struct VfsMountPoint *vmp);
|
||||||
|
int32_t (*stat)(struct VfsMountPoint *vmp, const char *path, FsStat *statbuf);
|
||||||
|
int32_t (*fetchdirent)(struct VfsMountPoint *vmp, const char *path, FsDirent *direntbuf, size_t idx);
|
||||||
|
int32_t (*mkdir)(struct VfsMountPoint *vmp, const char *path);
|
||||||
|
int32_t (*delete)(struct VfsMountPoint *vmp, const char *path);
|
||||||
|
|
||||||
|
// HERE: instance objects for the underlying filesystem driver library.
|
||||||
|
union {
|
||||||
|
LittleFs littlefs;
|
||||||
|
FatFs fatfs;
|
||||||
|
} fs;
|
||||||
|
SpinLock spinlock;
|
||||||
|
} VfsMountPoint;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
SpinLock spinlock;
|
||||||
|
VfsMountPoint mountpoints[VFS_MOUNTPOINTS_MAX];
|
||||||
|
} VfsTable;
|
||||||
|
|
||||||
|
// ...
|
||||||
|
----
|
||||||
|
|
||||||
|
.Little FS init code
|
||||||
|
[source,c]
|
||||||
|
----
|
||||||
|
int32_t vfs_init_littlefs(VfsMountPoint *mp, bool format) {
|
||||||
|
// Configure Little FS
|
||||||
|
struct lfs_config *cfg = dlmalloc(sizeof(*cfg));
|
||||||
|
memset(cfg, 0, sizeof(*cfg));
|
||||||
|
cfg->context = mp;
|
||||||
|
cfg->read = &portlfs_read; // Our read/write hooks
|
||||||
|
cfg->prog = &portlfs_prog;
|
||||||
|
cfg->erase = &portlfs_erase;
|
||||||
|
cfg->sync = &portlfs_sync;
|
||||||
|
cfg->block_size = LITTLEFS_BLOCK_SIZE;
|
||||||
|
cfg->block_count = mp->backingsd->capacity(mp->backingsd) / LITTLEFS_BLOCK_SIZE;
|
||||||
|
// left out...
|
||||||
|
int err = lfs_mount(&mp->fs.littlefs.instance, cfg);
|
||||||
|
if (err < 0) {
|
||||||
|
ERR("vfs", "Little FS mount failed %d\n", err);
|
||||||
|
return E_MOUNTERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// VFS hooks
|
||||||
|
mp->cleanup = &littlefs_cleanup;
|
||||||
|
mp->open = &littlefs_open;
|
||||||
|
mp->stat = &littlefs_stat;
|
||||||
|
mp->fetchdirent = &littlefs_fetchdirent;
|
||||||
|
mp->mkdir = &littlefs_mkdir;
|
||||||
|
mp->delete = &littlefs_delete;
|
||||||
|
return E_OK;
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
So where is the problem? It's in the fat_io_lib library. You see, the creators of Little FS thought
|
||||||
|
this out pretty well and designed their library in such manner that we can do cool stuff like this.
|
||||||
|
The creators of fat_io_lib on the other hand... yeah. Here are the bits of internals of fat_io_lib:
|
||||||
|
|
||||||
|
[source,c]
|
||||||
|
----
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Locals
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
static FL_FILE _files[FATFS_MAX_OPEN_FILES];
|
||||||
|
static int _filelib_init = 0;
|
||||||
|
static int _filelib_valid = 0;
|
||||||
|
static struct fatfs _fs;
|
||||||
|
static struct fat_list _open_file_list;
|
||||||
|
static struct fat_list _free_file_list;
|
||||||
|
----
|
||||||
|
|
||||||
|
There's no concept of a "context" - everything is thrown into a bunch of global variables.
|
||||||
|
To clarify: THIS IS NOT BAD! This is good if you need a FAT library for let's say a microcontroller,
|
||||||
|
or some other embedded device. Less code/stuff == less memory usage and so on.
|
||||||
|
|
||||||
|
When I was searching online for a FAT library, I wanted something like Little FS, but to my suprise
|
||||||
|
there are no libraries for FAT designed like this? Unless it's a homebrew OsDev project, of course.
|
||||||
|
I've even went on reddit to ask and got nothing, but cricket noises ;(.
|
||||||
|
|
||||||
|
I've decided to modify fat_io_lib to suit my needs. I mean, most of the code is already written for
|
||||||
|
me anyway, so I'm good.
|
||||||
|
|
||||||
|
The refactoring was quite easy to my suprise! The state of the library is global, but it's all nicely
|
||||||
|
placed in one spot, so we can then move it out into a struct:
|
||||||
|
|
||||||
|
[source,c]
|
||||||
|
----
|
||||||
|
struct fat_ctx {
|
||||||
|
FL_FILE _files[FATFS_MAX_OPEN_FILES];
|
||||||
|
int _filelib_init;
|
||||||
|
int _filelib_valid;
|
||||||
|
struct fatfs _fs;
|
||||||
|
struct fat_list _open_file_list;
|
||||||
|
struct fat_list _free_file_list;
|
||||||
|
void *extra; // we need this to store a ref to the mountpoint to access storage device hooks
|
||||||
|
};
|
||||||
|
----
|
||||||
|
|
||||||
|
[source,c]
|
||||||
|
----
|
||||||
|
// This is what our VfsMountPoint struct from earlier was referencing, BTW.
|
||||||
|
typedef struct {
|
||||||
|
struct fat_ctx instance;
|
||||||
|
} FatFs;
|
||||||
|
----
|
||||||
|
|
||||||
|
I've then gone on a compiler error hunt for about 2 hours! All I had to do is change references for
|
||||||
|
eg. from `_fs.some_field` into `ctx->_fs.some_field`. It was all pretty much brainless work - just
|
||||||
|
compile the code, read the error line number, edit the variable reference, repeat.
|
||||||
|
|
||||||
|
== Why do I even need FAT in MOP2?
|
||||||
|
|
||||||
|
I need it, because Limine (the bootloader) uses FAT16/32 (depending on what the user picks) to store
|
||||||
|
the kernel image, resource files and the bootloader binary itself. It'd be nice to be able to view
|
||||||
|
all of these files and manage them, to maybe in the future for eg. update the kernel image from the
|
||||||
|
system itself (self-hosting, hello?).
|
||||||
|
|
||||||
|
== Fruits of labour
|
||||||
|
|
||||||
|
Here are some screenshots ;).
|
||||||
|
|
||||||
|
image::/img/fatfs-showcase2.png["showcase 2"]
|
||||||
|
image::/img/fatfs-showcase1.png["showcase 1"]
|
||||||
153
content/blog/MOP2/mbus-messaging-ipc.adoc
Normal file
153
content/blog/MOP2/mbus-messaging-ipc.adoc
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
= MBus - in-kernel messaging system
|
||||||
|
Kamil Kowalczyk
|
||||||
|
2025-11-12
|
||||||
|
:jbake-type: post
|
||||||
|
:jbake-tags: MOP2 osdev
|
||||||
|
:jbake-status: published
|
||||||
|
|
||||||
|
In this article I would like to present to you `MBus` - a kernel-space messaging IPC mechanism for
|
||||||
|
the MOP2 operating system.
|
||||||
|
|
||||||
|
== One-to-many messaging
|
||||||
|
|
||||||
|
MBus is a one-to-many messaging system. This means that there's one sender/publisher and many
|
||||||
|
readers/subscribers. Think of a YouTube channel - a person posts a video and their subscribers get
|
||||||
|
a push notification that there's content to consume.
|
||||||
|
|
||||||
|
image::/img/mbus-diagram1.png["One-to-many messaging diagram"]
|
||||||
|
|
||||||
|
== User-space API
|
||||||
|
|
||||||
|
This is the user-space API for MBus. The application can create a message bus for `objmax`
|
||||||
|
messages of `objsize`. Message buses are indentified via a global string ID, for eg. the PS/2
|
||||||
|
keyboard driver uses ID "ps2kb".
|
||||||
|
|
||||||
|
`ipc_mbusattch` and `ipc_mbusdttch` are used for attaching/detattching a consumer to/from the
|
||||||
|
message bus.
|
||||||
|
|
||||||
|
[source,c]
|
||||||
|
----
|
||||||
|
int32_t ipc_mbusmake(char *name, size_t objsize, size_t objmax);
|
||||||
|
int32_t ipc_mbusdelete(char *name);
|
||||||
|
int32_t ipc_mbuspublish(char *name, const uint8_t *const buffer);
|
||||||
|
int32_t ipc_mbusconsume(char *name, uint8_t *const buffer);
|
||||||
|
int32_t ipc_mbusattch(char *name);
|
||||||
|
int32_t ipc_mbusdttch(char *name);
|
||||||
|
----
|
||||||
|
|
||||||
|
=== Usage
|
||||||
|
|
||||||
|
The usage of MBus can be found for eg. inside of TB - the MOP2's shell:
|
||||||
|
|
||||||
|
.Initalizing interactive shell mode
|
||||||
|
[source,c]
|
||||||
|
----
|
||||||
|
if (CONFIG.mode == MODE_INTERACTIVE) {
|
||||||
|
ipc_mbusattch("ps2kb");
|
||||||
|
do_mode_interactive();
|
||||||
|
// ...
|
||||||
|
----
|
||||||
|
|
||||||
|
.Reading key presses
|
||||||
|
[source,c]
|
||||||
|
----
|
||||||
|
// ...
|
||||||
|
int32_t read = ipc_mbusconsume("ps2kb", &b);
|
||||||
|
if (read > 0) {
|
||||||
|
switch (b) {
|
||||||
|
case C('C'):
|
||||||
|
case 0xE9:
|
||||||
|
uprintf("\n");
|
||||||
|
goto begin;
|
||||||
|
break;
|
||||||
|
case C('L'):
|
||||||
|
uprintf(ANSIQ_CUR_SET(0, 0));
|
||||||
|
uprintf(ANSIQ_SCR_CLR_ALL);
|
||||||
|
goto begin;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
----
|
||||||
|
|
||||||
|
Previously reading the keyboard was done in a quite ugly manner via specialized functions of the
|
||||||
|
`ps2kbdev` device object (`DEV_PS2KBDEV_ATTCHCONS` and `DEV_PS2KBDEV_READCH`). It was a one big
|
||||||
|
hack, but the MBus API has turned out quite nicely ;).
|
||||||
|
|
||||||
|
With the new MBus API, the PS/2 keyboard driver becomes way cleaner than before (you can dig
|
||||||
|
through the commit history...).
|
||||||
|
|
||||||
|
.Kernel-side code for the PS/2 keyboard driver
|
||||||
|
[source,c]
|
||||||
|
----
|
||||||
|
// ...
|
||||||
|
IpcMBus *PS2KB_MBUS;
|
||||||
|
|
||||||
|
void ps2kbdev_intr(void) {
|
||||||
|
int32_t c = ps2kb_intr();
|
||||||
|
if (c >= 0) {
|
||||||
|
uint8_t b = c;
|
||||||
|
ipc_mbuspublish("ps2kb", &b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ps2kbdev_init(void) {
|
||||||
|
intr_attchhandler(&ps2kbdev_intr, INTR_IRQBASE+1);
|
||||||
|
|
||||||
|
Dev *ps2kbdev;
|
||||||
|
HSHTB_ALLOC(DEVTABLE.devs, ident, "ps2kbdev", ps2kbdev);
|
||||||
|
spinlock_init(&ps2kbdev->spinlock);
|
||||||
|
PS2KB_MBUS = ipc_mbusmake("ps2kb", 1, 0x100);
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
The messaging logic is ~20 lines of code now.
|
||||||
|
|
||||||
|
== The tricky part
|
||||||
|
|
||||||
|
The trickiest part to figure out while implementing MBus was to implement
|
||||||
|
cleaning up dangling/dead consumers. In the current model, a message bus
|
||||||
|
doesn't really know if a consumer has died without explicitly detattching
|
||||||
|
itself from the bus. This is solved by going through each message bus and
|
||||||
|
it's corresponding consumers and deleting the ones that aren't in the list
|
||||||
|
of currently running processes. This operation is ran every cycle of the
|
||||||
|
scheduler - you could say it's a form of garbage collection. All of this
|
||||||
|
is implemented inside `ipc_mbustick`:
|
||||||
|
|
||||||
|
[source,c]
|
||||||
|
----
|
||||||
|
void ipc_mbustick(void) {
|
||||||
|
spinlock_acquire(&IPC_MBUSES.spinlock);
|
||||||
|
// Go through all message buses
|
||||||
|
for (size_t i = 0; i < LEN(IPC_MBUSES.mbuses); i++) {
|
||||||
|
IpcMBus *mbus = &IPC_MBUSES.mbuses[i];
|
||||||
|
// Skip unused slots
|
||||||
|
if (mbus->_hshtbstate != HSHTB_TAKEN) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IpcMBusCons *cons, *constmp;
|
||||||
|
spinlock_acquire(&mbus->spinlock);
|
||||||
|
// Go through every consumer of this message bus
|
||||||
|
LL_FOREACH_SAFE(mbus->consumers, cons, constmp) {
|
||||||
|
spinlock_acquire(&PROCS.spinlock);
|
||||||
|
Proc *proc = NULL;
|
||||||
|
LL_FINDPROP(PROCS.procs, proc, pid, cons->pid);
|
||||||
|
spinlock_release(&PROCS.spinlock);
|
||||||
|
|
||||||
|
// If not on the list of processes, purge!
|
||||||
|
if (proc == NULL) {
|
||||||
|
LL_REMOVE(mbus->consumers, cons);
|
||||||
|
dlfree(cons->rbuf.buffer);
|
||||||
|
dlfree(cons);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spinlock_release(&mbus->spinlock);
|
||||||
|
}
|
||||||
|
spinlock_release(&IPC_MBUSES.spinlock);
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
As you can see it's a quite heavy operation and thus not ideal - but still
|
||||||
|
way ahead of what we had before. I guess the next step would be to figure out
|
||||||
|
a way to optimize this further, although the system doesn't seem to take a
|
||||||
|
noticable hit in performance (maybe do some benchmarks in the future?).
|
||||||
Reference in New Issue
Block a user