Hi,
Otter wrote:The problem I have is: If my syscalls would call the callback it needs to change the cpl to 3 beacuse my kernel would never allow a user mode process to run on ring 0 . But if the cpl is 3, how could the callback function return to the syscall ? Is it necessary to create a seperate call gate to "return" to the syscall or is there a better way ?
As far as I can tell there's 3 ways...
First, you could make sure there's no reason to return to the kernel after the callback. In this case the kernel would mangle the stack and return to the callback address, and the callback code would return to the CPL=3 code that was running before the kernel was called.
The next method would be to force a return to the kernel. An easy way would be to mangle the stack so that when the callback code completes it causes an exception, and then use the exception handler to return to the kernel code that called the callback.
The last method would be to have some CPL=3 intermediate code (e.g. a "system" shared library). In this case the kernel would mangle the stack and return to the intermediate code - the intermediate code would call the callback and then do
something to return to the kernel.
IMHO the best way of doing it is to figure out where you need callbacks and find ways to avoid them completely.
Also, don't be confused by "icing" used to hide IPC in event based systems. This is a little difficult to explain, but imagine you've got an event based system where there's a central message handler that controls program flow. Now imagine you want to hide this central message handler so that programmers don't need to worry about message handling. In this case you could write a library that hides the IPC and then uses callbacks for any messages that are unexpected.
For example, consider something like this:
Code: Select all
void main(void) {
fp = fopen("r", "some_file.txt");
if(fp < 0 ) printf("Error!\n");
}
It looks like plain linear code, but what if it's linked to a system library containing this:
Code: Select all
void message_handler(void) {
get_message(&message);
switch(message.type) {
case 'SIGNAL":
do_signal_callback();
break;
case 'FILE_OPEN_STATUS":
file_open_status = (int)message.data1;
break;
}
}
FILE *fopen(char *type, char *file_name) {
file_open_status = NOT_RECEIVED_YET;
/* send request to open the file */
for(;;) {
message_handler();
if(file_open_status != NOT_RECEIVED_YET) return file_open_status;
}
}
As you can see the message handler can be hidden within the library and the programmer just writes code like they aren't using an event based system. For things that are unexpected (like signal handling) callbacks are needed, but the callbacks are entirely in CPL=3 code - the kernel just sends a message to the message handler.
Cheers,
Brendan