Page 1 of 1
Microkernel User I/O Handling (gets, putc, fgets)
Posted: Sun Aug 24, 2014 1:43 pm
by SoLDMG
Hello everyone,
I am quite puzzled at the idea of user input/output in microkernels. In the "Porting newlib" article here:
http://wiki.osdev.org/Porting_Newlib, it is stated that one needs a couple of system calls such as read() and putc() for a working C library, but these calls aren't implemented in a typical microkernel (userspace FS and such). So how does one "redirect", per say, these userspace servers to what the C library uses (for example: read(), but more puzzling to me, functions like putc() as mentioned in the article)?
I do have one theory, which is to do IPC and tell the server process in question to do something, but I'd rather hear from someone who does know how this works.
Thanks in advance.
Re: Microkernel User I/O Handling (gets, putc, fgets)
Posted: Sun Aug 24, 2014 2:08 pm
by Owen
SoLDMG wrote:I do have one theory, which is to do IPC and tell the server process in question to do something, but I'd rather hear from someone who does know how this works.
That.
Newlib is designed amusing your system is a decent facsimile of a Unix, which is probably bad for a microkernel (it ends up with you needing a "unix server" in order to keep everything in order, which tends to be a big monolithic mess, so you might want to keep that in mind. (On the other hand, if you decide to be less strict about your POSIX compatibility, you can probably get away with it). I'd somewhat biasedly
suggest PDCLib - link in my signature - because it implements just the C standard, not POSIX, and therefore avoids many of the issues of newlib (also, newlib doesn't get you much towards POSIX support anyway because that stuff tends to be very OS dependent), and also because I've looked at the newlib code and it made me scream.
Also, you might find the implementation of the Win32 port of PDCLib interesting, because Windows factors out all of the whole system call/platform layer thing better than most Unixes, which just stuff everything into one big "libc". I'd start
here.
Re: Microkernel User I/O Handling (gets, putc, fgets)
Posted: Sun Aug 24, 2014 3:32 pm
by SoLDMG
It does look very interesting. The goal of my project is to have everything free of any code not written by the devs (which means me), but that means YEARS upon YEARS of coding while in the meantime you still need to put all the pieces together. So my plan is to just get a reliable system running, getting a toolchain written and ported, porting programs and then gradually replacing those programs with self-written ones. I'll seriously consider using your public domain C library until a replacement is written. I have however stumbled across it before, when I was looking for a C library to study, but I couldn't really find any who's documentation fitted my stupidity aside from yours, dietlibc and the bloated and horrible nightmare glibc.
Re: Microkernel User I/O Handling (gets, putc, fgets)
Posted: Sun Aug 24, 2014 6:01 pm
by Brendan
Hi,
SoLDMG wrote:I do have one theory, which is to do IPC and tell the server process in question to do something, but I'd rather hear from someone who does know how this works.
Note that (in general, regardless of kernel type) the POSIX library acts as a kind of emulation layer. It emulates the POSIX API for processes using the library, and internally the POSIX library uses the OS's native API/s (which may or may not be radically different to the API the POSIX library provides). For badly designed monolithic systems (where the designer failed to think of any way of doing anything better or provide any additional features) the kernel API may closely match the POSIX API and therefore the "emulation layer" (POSIX library) may be relatively minimal; and for radically different systems the "emulation layer" (POSIX library) may involve a lot more. For an example; consider an exo-kernel - in this case, the "emulation layer" (POSIX library) could include the OS's file system code, device drivers, scheduler, etc.
For a micro-kernel; I'd be tempted to assume that (for the native APIs, etc):
- there's some sort of communication system (e.g. messaging, where the kernel provides some functions to get and send messages)
- file IO is done using that communication system (e.g. by sending messages to the VFS and receiving messages from the VFS)
- the GUI (or teminal emulator or whatever) is also used via. that communication system (e.g. by sending messages to the GUI and receiving messages from the GUI)
This would imply that (for the "emulation layer"/POSIX library):
- inside the POSIX library, various functions (e.g. printf(), puts(), fwrite(), gets(), fread(), etc) could all end up relying on tiny set of lower level functions (e.g. open(), read(), write() and close())
- those lower level functions would be implemented in the POSIX library using the OS's communication system, such that the file descriptor determines where the data is sent and how. For e.g. if the file descriptor for the "write()" is for a normal file then it may end up being messages sent to the VFS, if the file descriptor is stdout then it might end up being messages sent to GUI (or terminal emulator or something), etc.
Cheers,
Brendan
Re: Microkernel User I/O Handling (gets, putc, fgets)
Posted: Thu Aug 28, 2014 5:16 am
by max
Hey,
I can tell you how it's done in
my microkernel. I don't do anything POSIX/UNIX-related, so its not specific for gets/putc/fgets, but it should give you an idea of how it can be done.
First of all, the communcation between processes is controlled via messages. There are two basic libraries that applications can use, the Ghost API that contains wrappers for system calls (and a C-library-bridge), and the Ghost Library that is a high-level library, where you can for example do things like this and all necessary steps happen in the background:
Code: Select all
File test("path/to/file.txt");
if(test.open()) {
size_t bufSize = 1024;
uint8_t buf[bufSize];
int bytesRead = test.read(0, buf, bufSize); // first parameter is the offset
// do something with the bytes
}
Now this is for example what happens if you read from a file:
- A process wants to read the file with node id 25 (this id is acquired in the "open" method) and calls the File's read method
- File.read method allocates some shared memory & shares it with the VFS process
- File.read method calls the ghostapi::SystemCalls::sendMessage function to send a message to the VFS (containing the file id, the target buffer and the maximum number of bytes to read)
- ghostapi::SystemCalls::sendMessage function fills a SystemCall-struct and does a software interrupt, the kernel handles this call and dispatches the message
- In the VFS process, the ghostapi::SystemCalls::receiveMessage function is called
- ghostapi::SystemCalls::receiveMessage function again calls the kernel to receive the message
- Now the VFS has a request to handle and creates a new thread for handling
- This VFS thread does a lookup for the file, and does whatever is necessary to read the bytes into the buffer (this could now involve sending a message to a driver process to request it to read the bytes)
- Once the reading is done, the VFS sends a message to the requesting process with the number of bytes that were actually read
- The process now has the requested bytes in it's buffer
Something similar would apply to stdout/stdin, except that the communcation could for example happen with the window server.
Greets,
Max