#Zinnia
1 messages · Page 16 of 1

niiiiice
will we get womenix or a menix rewrite #3 that goes back to rust first 
i fixed the scheduler issues somewhat
its still in rust
working on real hw again
still gotta fix tsc overflow
funky
for some reason the fb on this device is SOOO slow
even limine is struggling
it's less than 1fps for an entire scroll
poor uacpi
most of these errors are
sure the errors are
i need to get to that first

i think i got stuck on the scheduler memes
What is reached stage
wdym
what does it mean and how does it work
it's an initgraph
Why
managarm larp
no cuz it's cool
why do you need this
to init the kernel
Can't you just print init... Ok like unironically
huh
Is there an actual advantage of having this is my question I guess
well this is cleaner in some way
well it lets you dynamically add init functions
ah so it's not just prints
without having a central main() where you call everything by hand
oh that's what you mean
no it's a tree of init functions
Yea I was asking what it was doing
its an init graph
you declare dependencies and a display name
then it runs those in a way so everything gets initialized in the correct order
like, adding /dev/null requires devtmpfs to be mounted
Ah that's cool
you can also visualize it
it's from an older tree
it requires a few hacks in rust, so @hoary cave made it into a proc macro
Ah maybe I'll look into this
whats a proc macro
Macro with custom syntax
pretty much
normal macros can also do that but with proc macros you get way more depth into the AST
for most things regular macros are fine, like per_cpu!()
with proc macros you get the token stream instead of composing the input from predefined rust syntax constructs
so you can parse it however you need to
thats some crazy shit
this is one of the things where rust really shines imo
it's pretty cool if you want to do some fancy stuff like we did
Wait till you see lisp macros
or elixir macros
not really
syn makes parsing really nice
you just input.parse()?

tt munching.... 😋
gotta love rust's compile time const computation, I managed to train my neural network purely during comptime even though it took over 5 times as just training it during runtime 🤪
miri moment
tbh compile time computation is one of the things that I dislike most in Rust
C++'s constexpr is one or two decades ahead compared to Rust's const
and it gets even worse when you look at const generics
which are basically impossible to use w/o nightly features
(for all interesting applications at least)
@vast lotus dumb question, how exactly does proxima do fork
i don't see where the fpu state is copied
i can see that you create a new thread on a clone, but never copy the fpu state?
A new xsave context is initialized by doing xsave
The xsave context for the new thread is created by the caller of fork and thus contains the fpu state of the caller of fork
then i'm doing something really wrong
what about user fs/gsbase?
nvm i see where it is set
In general the extended state of a new thread is initialized to that of its caller
Rust toolchain love equality i must say ☠️
fwiw that's not necessary on x86 as fpu state is caller saved
except for some control bits
the syscall abi preserves it though right
my fork is finally working
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
int main() {
write(1, "Hello, world!\n", 14);
int forked = fork();
if (forked) {
printf("I am the parent, child is %i\n", forked);
} else {
printf("I am the child\n");
printf("I like being a child\n");
}
printf("And this is shared!\n");
while(1) {
asm volatile("pause");
}
return 0;
}
this is the code being ran
i have to optimize the mapping logic because atm for private mappings it creates one memory object per page
Unless beaten by nyaux of course
I see
Wait you didn't have fork all along?
no
my scheduler was broken for too long
and the page cache bullshit was blocking me as well
fixed the fd allocation again
yoooo
also wont openrc krill itself without pipe
i would know this
it does on nyaux
guess what
lets go
c is a perfect language
and other lies you can tell yourself
lol
if c is perfect, why was c++ invented?
@lofty copper i heard you like to shill microkernels
what implications does having a microkernel have vs a monolith
HOW much different is it actually
my major concern is if there's any aids things i should know about
Idk I've never written a monolith
It's a lot more work I guess?
like protocol stuff for example
hm
how do you do stuff like fork() in a microkernel?
and how do you access phys mem
It depends
Wdym
for drivers
like, do you just say that drivers have to have a certain cap to be able to access phmem
I guess you can do the same in Linux by mapping /dev/mem
You could do that
I've been thinking about representing devices as memory objects or something
Basically capabilities system
But idk how much it matters with devices that do DMA and stuff
(unless you have iommu)
iommu drivers are easy enough i guess
Like at the moment my kernel just lets userspace map any physical memory it wants
And I have a syscall for getting phys address from pointers for DMA
I think managarm had something like that as well
so you do scheduling and process management in kernel?
or threads in kernel and processes are a user structure?
Yes
This
But idk if it makes a lot of sense
depends on how you manage address spaces
My memory management is in kernel
So I guess threads sharing the same address space can kinda represent a process
But then I have a separate server which keeps track of POSIX processes and stuff
So idk
yea if i were to go witha µ design i would probably have all the posix stuff in its own server
uMenix
munix
To make it work I have task (thread) groups in kernel
Which I've also used to share capabilities between threads
So capabilities seems like a nice abstraction for everything
that's essentially processes
minus the addrspace
but does that make sense?
Idk
in my head a thread only ever belongs to one process
because having two owners means something is off
My filesystem is also represented by task groups
So when I'm forking a process, I clone the filesystem by creating a new group, cloning the file descriptors, and giving it to the new thread/process
So at that time the thread that calls fork has two file tables
Idr what's the right name for it
fd tables
Yeah
designing a microkernel sounds kinda fun
because everything is just opaque objects passed around
So like if the userspace decides to, you can have multiple threads in the same process have different fd tables or something
Yeah, it's one of the ways to do it
btw i saw you are polling for messages in some of the servers
my idea would've been to have an infinite loop and do something akin to sigaction
where you can register handlers for certain syscall numbers
like
My receive syscall blocks on empty message queues
So my plan for handling signals was also to have a thread which polls for messages and changes other threads from userspace
So the kernel doesn't have to touch the userspace's registers
menix_handler_ret_t my_beef_handler(menix_source_t src, menix_msg_t msg);
int main() {
menix_register_handler(0xDEADBEEF, my_beef_handler);
menix_hiber();
}
something like this
I have a new API for this
hiber is noreturn
DEFINE_SYSCALL(sys_beef)
sys_beef should be like some debugging syscall or something
this reads very much like setting up some kind of event loop and then being fully event driven.
That's what I do at least
Idk I need to get back to working on my OS
I haven't touched it for almost 2 months now
are your servers also freestanding?
Yes, but that's because I haven't bothered implementing dynamic linking
I should port mlibc
yes you should
please do actually
it'd be the only other source for a microkernel sysdep
My libc is not that good
Only the stuff that's needed for dynamic linking would need to be statically linked
Idk
I think managarm had dynamic linking in the kernel or something?
My init server acts as a filesystem so I can probably do dynamic linking in there
Do you need to open files?
yes thats how dynamic linking works
It's just mmap
My files are represented by memory objects in kernel
Idk then
I haven't thought about it
like, a dynamic executable will name a path to a ld.so which loads the shared libraries
which all assume a file path
Then I guess the init server + filesystem server or whatever will need to be statically linked
i would solve this by compiling posix as freestanding
I don't like the idea of not having libc
well, posix is essentially the backing part of libc
My libc talks to other servers lazily
So if you don't use open() then there is no issue with it
i mean that's what happens in mlibc kind of
But I guess it could be freestanding now that I think of it
you can implement mlibc::sys_open however you want
But my POSIX server is written in C++ and I use libc++ in it and it requires libc
you could do like if (this.id == POSIX_ID) { ...
would be really nice if pmos was in mlibc
I've been thinking about weak symbols or something
for what?
For this
I've been thinking about using vdso for syscalls
But this sounds like a nice idea
Just have a special libmenix
For POSIX server or whatever
well my idea is to have libmenix implemented as a vdso actually
But like since it's a POSIX server, you can just not use POSIX functions inside it, and talk to servers directly
However you want it
Like that's what I've been trying to say with this
Managarm has a small subset of posix in the kernel that the servers can use for their needs. All userspace apps have to deal with the userspace posix subsystem tho
Like what?
I’m not entirely sure how it works ngl. @marble salmon knows more
if you havent made a monolithic before you should tho
a microkernel is typically much more complex
what does "making" entail
well i got to the bash prompt
Basically you should have an idea of what a kernel entails before making a microkernel
Idk if that makes sense
i'd like to believe that i do
‼️
i dunno man
@lofty copper what kinds of things should i consider when designing a microkernel system?
just categories
IPC probably
Also you kinda need to decide what you want to have in the kernel vs userspace
I guess
do you have uacpi in user space
He does
Wdym?
He has a separate parser in the kernel for tables I think
makes sense
Same as nt for example
Without the acpi.sys driver it still has a table parser
For the core stuff
uACPI has a barebones mode for that
i should design the entire system layout before i start writing code i think
if i actually follow through with this
For a microkernel probably you should
Do the NT thing and write a design book
an entire book?
i guess i should touch on task management, object passing, data passing, privilege management and initialization
also abi
Anyone who attempts nt stuff is based
nt is cool except for the coding style
The only thing that sucks about it is the typenames
Yep
KiReleaseTwoSpinlocks
or would it be Ke
I can never tell that all the prefixes mean
Ki means its internal
there's also p for private
do they have Ui and Ue functions for userspace
o
Ps
Nt
NtReadFile
NtCreateSection
Old Technology Read File
they're just naming it random letters 🙏🙏🙏
Introducing the Sybau subsystem
it features synchronization primitives like SybauWaitForSingleObject, as well as memory management functions like SybauAllocatePool
Idk the reasoning for Zw
But the prefix makes sense
Po is power
Se is security
Scheduler Yield Based Asynchronous Utilities
wait this is actually a fire name I think I'll call my subsystem that when I implement more async stuff
maybe make the Y stand for something else
Zbikowski Mark. 😁
Isn't that for the MZ header in executable files?
Yes. I remember reading somewhere, that Zw prefix also was a reference to him.
Interesting
I've read that it means Zero Wait as well
Since it skips all the parameter validation that's done
Yes, this is the explanation found most often. It might be both. 
I'm pretty sure it just means nothing and those letters were chosen because there would probably never be an Actual Real component called Zw
Fair point
Also I'm not sure how they do this, but in the source code (as far as I've been able to hear from others), the functions are defined with the Nt prefix
How come they're exported as Zw
im just gonna prefix everything with marvin_
they were randomly selected as like the two least common letters
W in Windows like: am I joke to you?
marv_some_function_in
yeah
Marvins Evil NIX
I've been meaning to find a backronym for menix
originally it stood for modular expandable unix
but that sounds a bit weird
cant you just call those functions directly in kernel mode??
without going through any system call dispatching code
‼️
incredible website btw
https://menix-os.org/
check out maestro's website 
https://maestro-os.org/
|| i've only ordered the domain name, nothing else ||
balling
i should think of a cool name for the kernel
womenix 😃
no
voted
menix-kernel
menix btw somehow associates with menopause.
bruh
@near tartan why Menix btw?
originally stood for minmal expandable unix
my kernel and OS are both called Maestro
but i feel like that acronym kinda sounds like shit
nah it's fine
freanix
marvin's evil unix
Marvelix.
maestro stands for maestro
astral stands for Astral aStral asTral astrRal astrAl astraL
i think it stands for something idk
works like a charm
works like a os
breaking news github now renders markdown in commit message headers? idk maybe this is an old thing
havent seen this before with the codeblock markdown
only with emojis
i don't know if i like the concept of mbus
i think i might put named objects/properties in the kernel
named objects
that's called a filesystem.
not really something structured
just named data that can be passed around
stuff like "acpi.rsdp"
that's called SCM_RIGHTS and the name is a file descriptor.
this, idk.
also this thing needs to work without a vfs running
i am going to follow the object capability model for most things
so i could just use objects for properties
small diff
mek? Then you can claim the M and E stand for the same thing as in menix
true
apparently its a solvent
it dissolves your sanity and free time
ok sad news
I can't do vdso for libmenix because i want the system to be buildable with a freestanding compiler
so no ld.so
what's stopping you from using ld.so and having the system buildable using a freestanding compiler
wdym
why are these two features mutually exclusive
i could have libmenix be an entry point which loads the vdso and calls main()
mlibc ld.so depends on some hosted functions that I don't think i have access to at that point
@lofty copper how does your ipc work on a theoretical level?
you create a port and send a message, right?
i'm assuming it's
port_create();
port_name("myport");
...
auto p = port_open("myport");
msg_t msg = malloc(sizeof(msg_t));
while(1) {
port_read(p, &msg);
switch (msg.num) { ... }
}
how would you pass e.g. a memory object between processes?
are object handles globally unique for every process?
Yes
I create a port, which has 1 owner thread that can receive messages, and everyone else can send messages to it
(At the moment it's everyone who knows the port id, but I've added rights/handles to it, which can be used as a permission system)
how about this
Though I think it makes sense to also make memory objects rights as well now that I have that system
It's kinda expired by Mach I guess
im looking a lot at fuchsia and zircon
I haven't looked into them
and they basically move object handles through channels
Yeah
The sender looses the right and the reciever gets it when recieving the message
Getting a new id in the scope of its namespace
?
like
how do you do shared memory
if i create a memory object in pid1 and move it to pid2
through memory objects
yeah, you send it to the second pid I guess
Idr
I don't really use shared memory
can pid1 still access the object or has it lost the right to it?
oh
I think it had reference counting
It's a separate system from message rights at the moment
And it's a bit messed up
i guess you need shared memory at least for posix MAP_SHARED
Yeah, but I haven't used it
And I think I had a capability to create shared mappings through fork?
I mean no
I do use shared memory for process creation and stuff
And CoW
I'm gonna disappear for an hour or so
Probably just ignore it for now 
lol
i wonder if its possible to do mostly shared memory IPC
i assume it could work for synchronous calls, but as soon as you need a queue the thing kind of falls apart
the idea i have atm is this
status_t link_create(link_t* out0, link_t* out1, size_t max_msg_size);
status_t link_connect(link_t link, const void** out_receiver, void** out_sender, uint8_t* out_doorbell);
status_t link_await(link_t);
link_createreturns two endpoints- one endpoint gets transferred to the child process
link_connectmaps a RO memory region for receiving and a RW region for sending, as well as a doorbell that can be rung to notify the receiver of a new messagelink_awaitblocks until the sender has rung a doorbell
i'm not too sure about the doorbell thing, i haven't thought too much about how that would actually work without going through the kernel
link_await might just be a userspace function, waiting for something like msg_head.finished
damn this might explode without any form of synchronization primitive
There was some microkernel here that was using memory sharing and mutexes for IPC or something like that
I think
(maybe)
It would probably have to go through kernel
Because you have to think about scheduling
And servers and stuff
yeah, i would probably have to have some form of notifying when you can read/write the queues
or i could say there's no such concept as a queue and make the user processes figure it out themselves
You could I guess
I'd rather have speed over reliability, as weird as it sounds
My queues are in kernel
So to send a message it is copied to a kernel buffer, pushed to the message queue, and then copied into the receiving thread
The interface is more straightforward I guess and it's probably ok for small data
yes that sounds fine
I don't even need doorbells or mutexes lol
i can just read the recv buffer on the sender side and wait for a reply
My mutexes are currently implemented with IPC
Yeah
The issue is with priorities in the scheduler and stuff
And also that mutex_unblock may fail if there is not enough memory to send a message
that's where shared memory might be nicer since the queue is already allocated
i do have to think about how to do this stuff asynchronously
You don't have to
I think there are kernels which only do synchronous IPC
that would make a lot of things easier
i mean technically speaking shared memory ipc is inherently async
i don't have to wait for a reply if I don't want to
i only need to manage queues somehow
@lofty copper do you have a max message size?
i could say something like "every message is 128 bytes big"
But I've kinda stuck with it
then queues would be very easy
Because fixing the size and preallocating the buffer makes things easier
At the moment I just kmalloc the buffer to the size that's requested by userspace
And like I've been thinking about it, but the only "problem" for now is performance
(which isn't really an issue at the moment)
But yeah, if you're sending large amounts of data, just use shared memory
actually, yeah I don't even need queues
Minix has a queue of 1 element I think, and it blocks otherwise
You can probably do some notification thing?
maybe
okay technically i don't need any notification mechanism
this can be handled by the user
Idk I think you need some mechanism for blocking if there's nothing to do
And at the same time you want something to wake up servers and potentially scheduling then immediately
Like sched_yield is not it
I guess it can be something simple and you can have nice userspace abstractions...
So like semaphores + shared memory can work as a primary IPC mechanism I think
yeah i think so
that would really cut down on time spent moving memory around i think
and is simple to implement in the kernel
because all it has to do is map memory
i guess on the kernel side i need a futex api
The thing is it's much faster to copy small chunks of data between two processes than making a shared page
if you move through registers
sure, but you make the shared page once and then you can basically write a stream to it
Also fuchsia/zircon is basically mach reinvented
So its IPC is pretty similar to mach
most times you don't need a whole page of data
Most IPC is simple RPCs
hm
tho shared memory is very useful
yea ofc
I wouldn't use it for small messages
but is it really faster to do a supercall vs just writing it to memory?
since you have two context switches
This is what we decided for the project but we haven't measured anything
what project?
The kernel Ethan and I were working on
ah
idk
the idea was kind of to leave most of the actual ipc management up to the servers
I guess you could setup a shared page per client on the server
the kernel only establishes the link
that was the idea
And if the client does multiple calls you just reuse the page
you create a link pair with send/recv buffers
l4 does a lot of shmem ipc i've read
their fastpath is through registers afaik
You need context switches in any case
(probably)
oh no i just realized i have to care about port permissions too now
if you're using names instead of capabilities, you're probably doing something wrong™
what is this in response to?
this?
just a general remark about how to design ipc systems
ah
and permissions
my plan was something like the posix api, where you get a pair of descriptors that a child can inherit
and handles having capabilities that control what you can do with them
korona you're probably the most qualified person to ask that i know
, but how dumb is doing only shared memory IPC
seL4 is in many aspects driven by what's easy to verify and not necessarily by what's great design :^)
if you want an L4 style IPC mechanism I'd look at NOVA
although NOVA can't transfer capabilities through IPC
but it'd be possible to add that on top
My OS does name resolution in a userspace server
But the interface is the same?
doesn't that mean that arbitrary clients can open connections to your server
If the server wants to, yes
But it's not really connections
You get a right to a port to talk to a server from the bootstrap server
You then talk to that server giving it a reply right
Like so it can reply to your IPC messages, send more capabilities and so on
what exactly are capabilities and why does one send them around?
i thought capabilities are related to an object(handle)
A right to send messages to ports
Or handles to objects I guess
Like handles to ports?
So you can't just start sending random stuff to random processes
yeah
yeah true
handles ARE capabilities
well, capabilities are handles plus permissions
there are also handles without permissions
for example, pidfd on linux is not a capability
because to send a signal to a process, you still need ambient authorization (= same uid/gid or root or CAP_SYS_ADMIN or similar)
but e.g., a unix socket fd is more like a real capability because if you have access to the fd, you can also send/receive
well, it's not really about kernel vs. user
the issue with names is that you need an extra permission system on top
what are some usual capabilities? RWX, movable, clonable?
file, network, software services (zip ...)
But it's probably easier to do in userspace?
They really mucked that up
FreeBSD procdescs are true capabilities
how does a microkernel normally handle cpu exceptions? managarm does something with observations, but i don't really understand it yet
Wdym
like, how do i get from an exception to e.g. a posix signal
I'd just send a message to POSIX along with the thread handle or something with the exception
directly from the kernel?
dunno
You need kernel<->userspace communication for things like swapping anyways
bootstrap server
how would that look? e.g. if i want to open an ipc connection to posix, could i do
object_t posix;
supercall(0, BOOTSTRAP_FIND, "posix", &posix);
object_t posix_link;
supercall(posix, POSIX_ESTABLISH_LINK, &posix_link);
link_connect(posix_link, ...);
i like this kind of interface
but not sure if this is "correct"
I meant from academia
is it that bad 💀
Managarm? No, but you should study actual research kernels vs hobby stuff
no i'm talking about my example
like this is the most straightforward thing i can think of, you make an rpc call to another server to request further operations
In practice you have an IDL
in this case creating a channel or whatever
That does it for you
i kind of wanted to go in blind, because this is a hobby project, but i don't see that many differences tbh
i guess minix is a bad example
they don't use an IDL
and i don't like that either really
wdym go in blind
without much research
but i guess there's no way around it
usually stuff that i could find are just random slides without any context
What you want is papers
what topics should i look for? just ipc?
because i guess ipc is the thing that makes or breaks a µkernel
Whatever you want to learn about?
My right 0 is a handle to bootstrap server's port
I think Mach does something like this as well
yeah see the snippet right below
i hope i'm on the right path, because i don't really want to just copy another kernel's logic
sure i can """"inspire"""" myself, but coming up with things myself feels infinitely more rewarding
w/e
then you have a reply port i see
But like you can pass the handle to another process and stuff
(in theory)
(so idk if I like having an explicit reply port)
my idea with links is that there's exactly one pair for every connection
so you can't pass handles to other processes directly, you'd have to go through syscalls first to transfer them
So basically pipes
Passing goes through syscall anyway
well yes in your case, but not mine
see this pseudocode
you ask the target server to allow a connection, if it accepts, it gives you the other end of the link
which you can then connect to
Why wouldn't it accept
oom? just theoretically
no like, for example if you request a shared memory region with a bogus value
the kernel will return an error to posix, which in turn makes the call return an error
or just return an error in the program directly
In the client???
If it tries to do a shitty syscall it's the kernels job to stop it not the server
When you request a region the request is to the kernel
Not the server
So the kernel returns the error
The server never has knowledge of it if there's an error
i know that, but it's just propagating it back to the client. when you create a shared memory region you get two endpoints. you want one handle on the posix side, and one on the client side. you ask posix for a new connection, which makes posix do the syscall and return back a handle to one of the endpoints.
if the syscall in posix fails, it returns that error from the rpc call
maybe I'm thinking about it wrong, but i don't see why this is so terrible
How do you ask POSIX if you haven't established a connection yet!? This doesn't make sense and incurs unneeded overhead for the simple error from the client of passing invalid parameters to a syscall to establish an IPC connection
maybe I'm missing something
Yes
how am i supposed to move handles between processes if I'm not allowed to arbitrarily request things from a server
because somehow both the server and client need to know about the shared memory region
Explain this
This doesn't make sense
like if you ask for a region of size -1
Why would the client doing establish_link(POSIX, whatever, crap) cause an error in POSIX?
i believe i see the issue. i said that the client asks posix to create the link (where the syscall may fail), and then returns back one handle, but the client can also create the link by itself and just send one handle to posix?
does that explain what I'm trying to do?
Why doesn't the client just get a handle to POSIX then sends messages along with a reply handle or something
that's just message passing then. the example i was trying to show was for setting up shared memory ipc buffers
Shared memory is a form of message passing
okay so
whats the name of non shared memory message passing
the one that goes through the kernel
because i will likely need both forms
No?
There's shared memory and there's message passing
i don't think there's a name for that
also there isn't a single way to implement that either
ah no you're right
true
anyway I still dont understand what you mean
client:
handle posix_handle = get_posix_handle();
setup_link(posix_handle);
// Why do you need this and why would this ever fail!?
posix_set_up_connection(posix_handle);
Like shared memory doesn't give you the synchronization I think
you can synchronize on shared memory
But I think those were 2 fundamental ways to do IPC
message passing just typically means its copied
setup_link should return two handles though, like a pipe
and to actually get a writable address, you "connect" to a link
okay I'm going to revise this example
handle posix = get_posix_handle();
handle link1, link2;
if (link_create(0x1000, &link1, &link2)) {
panic();
}
// How do i best move one of the link endpoints over?
send_msg(posix, POSIX_FOO_MSG, link1);
yeah that is fine
this i dont understand tho
how can you send a message to posix if you dont have a handle to it/the link isnt set up
you can't
probably brainfart cuz it's late, but the above example would've looked like this (very roughly)
handle posix = get_posix_handle();
handle link;
// posix server runs the syscall to create the shared memory
send_msg(posix, POSIX_ESTABLISH_CON, link);
recv_msg(&link);
but that's just more effort than the one above
that's where i wanted to use supercalls before (like signal handlers that a server would register beforehand)
though wait, how would this work then
the problem i have is literally just "how do i move the link handle to the other process, if i need the link to send messages"
but how is this possible? if you have no way of talking to another process, how can you bootstrap anything 
something similar to fork() could work, where the children of the bootstrap server inherit the handles
but then I couldn't arbitrarily connect to a server
yes
this is literally how it works
you have a permanent handle to bootstrap
and ask it to get an handle to posix
which posix registered beforehand
okay so there is always a link to the bootstrap server at least
yeah I'm a brainlet confirmed
i'll look at this again later today. can send_msg even work with only shared memory ipc? you can send_msg via the kernel because that allows messages from multiple clients, but a link is a 1:1 relationship
or is shared memory also allowed to have multiple writers? that sounds weird
so even with a posix handle, you can't tell posix about the new link, because you need another link to send it 
if you have a way to get the posix handle why not just set up a link?
where do you get the posix handle from
bootstrap server
okay
instead of returning a handle to posix you can just make it set up a link for you
oh
and how is posix going to receive if it doesnt have the other end?
bootstrap should give you one end of the link and posix the other end with some sort of message maybe
idk
idk how your "links" are supposed to work but yeah
is it just a pipe for messages?
meaning what you put() on one end can be get() on the other?
links are just shared memory kernel objects that you can map
wtf
why wtf
what would you call it
fair
idk how it's supposed to work so i can't tell
my idea was that you create it and you have two endpoints. one you keep, the other gets moved. you can "connect" to a link, which gives you a pointer to RW memory for sending and a pointer to RO memory for receiving.
so you have some sort of bidirectional communication via shared memory
maybe it's braindead, I can't tell
i like what managarm does with hel queues but i'm not sure if or how that works across processes
it's kinda similar to what you're saying but not exactly, you can helCreateQueue with some parameters that describe the in-memory layout of it and then you get a handle which you can use to map the queue in memory and from here you use futex to communicate with the kernel when you put something on the queue
i think that's a nice way to handle async ipc
each element on the queue carries some data, and if the data isn't too much you can embed it directly in the queue element
yea for synchronization i was going to use futexes too
there's some ref counting done on each element to make sure it isn't reused by the kernel before you are done reading from it etc
so each queue element is fixed size?
no
you can have smaller elements if they don't need much data
like a simple result that says "ok or error"
you can transfer data inline in a queue element too if you want
or just pass a pointer if it's a lot of data and it'd be better for the kernel to copy it instead
i'm 90% sure that queues are used for message passing and lanes actually let you talk to difference servers
you basically put a message on the queue with a lane handle and the kernel fulfills a request on the other side of the lane
so if one server puts a "receive" on the queue and you "send" then that completes the request
so wait the queue itself lives in userspace but the kernel accesses it?
then does it work like
auto q = create_queue();
map_queue(q, &whatever);
*whatever = message_t {123};
queue_submit(q);
far from that but sure
okay sorry, i kinda trolled
the actual message submission is done using a syscall
there's a few helSubmit* syscalls
i saw that you can submit an array
the one used for actual message passing is helSubmitAsync
that's the one you probably saw
because it takes a bunch of actions
the queue is used for notifying user space of completions
the kernel will put a completion on the queue and then futex_wake you
here's an example of submitting something
what that does is it creates an async operation on the kernel side, it waits until the time reaches provided timestamp and it submits a completion to the provided queue, the context is an arbitrary pointer sized value
i'm not sure how exactly it works on the kernel side so i can't say much
but still, that's a neat way to do async ipc
nah i don't really care
like, i could write a message to the send buffer, move on and until i want to send another message i can do whatever without waiting for a response
that's technically asynchronous, although limited
most use cases dont require async
so fully async isnt needed
async is cool though,,,
you get more brownie points for async IPC
i recommend this one: https://dl.gi.de/server/api/core/bitstreams/dabcf748-5ee0-4cbe-a2b5-cb2576fa8113/content
:^)
a supercall in Managarm is a syscall that traps into a userspace handler
re shared memory: one issue with shared memory only is that you have to be really careful when using shared memory with untrusted clients
as they may corrupt the shared memory data structures
well, I think for async IPC Managarm is indeed state-of-the-art
but it's interface is quite centered around async IPC so if you want to do sync IPC, there's certainly stuff that you'd want to do differently
Lol what is a mutex spinlocks in the corner

fair enough
i don't think i can do anything to prevent that from happening, so i just need to
more
well, the solution is to not assume that the shared memory data structure is in a sane state
does it make sense to combine the bootstrap server and the posix server? one issue i could think of is if something crashes posix, it takes bootstrap with it, stalling the entire system
though if posix crashes the system might as well be stalled
it depends on what your goal is
i'm just experimenting. if many calls end up going through bootstrap just to go to posix and back, it would probably be faster if they're one server.
if the only thing i have to do is creating a link, then it's fine
any kind of proxy like that would probably be a result of a bad design
I plan to ensure correct shared memory ring buffer control datastructures by having two sets of of them per client-server pair (not per connection) and one is mapped as readonly for the other
These pages contain all data for all connections/channels between the specific client-server pair
And a third one that's ro for both that specifies the ringbuffer size and stuff
Also the sender view for the ringbuffer is mapped as WT on x86
One connection consists of two Uni directional ring buffers
wdym not per connection? isn't a client-server pair a connection?
I don't think that this helps a lot
i don't get how it protects anything
It doesn't help a lot because the only thing that it ensures is that the write side can be sure what changes it made to the buffer
but it doesn't allow you to remove any checks from the read side
and the write side is usually not a problem anyway because it doesn't need to store state inside the buffer
What would that achieve?
WT doesn't have any advantages over WB for normal RAM
Yes but permissions are per page which would waste a lot, so all control datastructurrs of connections of a client server pair get aggregated
The other side can't manipulate things like the read/write pointer in the datastructure
WT updates the cacheline if present but doesn't allocate new ones and does write combining
So no cache pollution for the writer while still allowing a cache to cache path for the data
It's possible and likely to have multiple connections to a server
x86 caches are physically tagged so this also means that the data are not in the cache when the reader wants to read them
The reader will issue L1 and L2 prefetches before reading
L2 prefetch for further away cache lines and L1 prefetch for the next few lines
This is 100% going to be slower than WB
Have you actually tried it out?
It's only ever going to be faster if the reader doesn't run immediately after the writer
So it's only fast on the path where you don't care so much about latency
Prefetching sequential accesses has not helped on x86 for the past 10 years or so
since the cpu prefetcher does that already
In the best case you gain a few % on the code path where latency is not important, in the worst case you're slowing down the communication by 10%+ due to the increased bus traffic from the WT
Oh that's cool
Besides, you can achieve the same thing without messing with WT if you use non temporal stores or movdir64b
Unless it is and I'm missing it
Afaik non temporal stores don't update present cachelines, at least for wc memory
that is true
But in the case where the line is already cached, WT is useless anyway
Or rather, simply inferior to WB
since WT generates extra bus traffic for no gain in that case
the only reason to use WT is if you want to read from memory that has write side effects
iretq said calling shmem ipc a "link" is misleading, what would be a better name for it?
I haven't heard it called anything other than shared memory IPC or some contraction of it.
i need a name that's not totally annoying to type out
menix_shmem_create();?
oh right another issue, how do you transfer object handles with only shmem ipc
sure you can send the handle value, but that doesn't send the actual object reference i think
Depends what type of object you mean
If you mean a kernel-managed object like FDs for example I'm not sure you can even share those over IPC?
it is indeed misleading
yes i mean that
in zircon, there's an extra ipc mechanism just for sending handles
maybe i need an extra syscall for that
Also the way Linux does shared memory is to do mmap on some file with MAP_SHARED. IIRC there's even a specific file type so you don't have to allocate actual disk space.
Because you said this
for ipc between servers
Wait are you gonna microkernel?
trying my hardest to...
I see what you're trying to do now
But yes, you'd need a discrete IPC type for sharing/sending handles like this
And use shared memory for faster transfers of bulk data ofc
You can't
so could i have a dedicated handle transport
or a supercall that allows the transfer of x handles together with a message
wait a minute that's just exactly what zircon channels are
Actually now that I think of it, you could if you used a sufficiently large completely random ID.
Then knowing the ID is the authorization to use it.
Not saying this is a good idea necessarily
then you'd have a global list of handles 
Yes
That's possible, true
And also hope you like having a receiving process suddenly lose the handle when the sender closes 
CHERI 
cant you just predetermine an area in shared memory where handles transfer could occur
or something
hardcode it 
actually yes
i could do something like io_uring?
where you prepare a buffer of operations and submit them
i'm trying to think
i guess i could handle this with page faults
no this is stupid
like a doorbell, where writing to the region triggers an operation
dont do it
woe

