[OSy] Fwd: Re: UPDATE: Immo Hellwig Ex.Ass.4
Petr Tůma
petr.tuma at d3s.mff.cuni.cz
Wed Dec 12 11:16:24 CET 2018
Forwarding in case it helps other people ... PT
-------- Forwarded Message --------
Subject: Re: UPDATE: Immo Hellwig Ex.Ass.4
Date: Wed, 12 Dec 2018 10:02:16 +0100
From: Petr Tůma <petr.tuma at d3s.mff.cuni.cz>
To: Immo <immo.hellwig at stud.uni-goettingen.de>
Hi Immo,
> My last last mail nearly got obsolete, so here an update:
OK :) By the way, would you mind if I forwarded our conversation to the course mailing list ? I'm sure some of
the points would help some other students too ...
> 1. What function can I use to "make sure the rest of the function is executing on a single cpu"? Also my
> solution for stdio,kernel-syscall and kbd is really laggy. Is it reasonable to see this as the reason?
Usually, the comment you refer to is a hint that you should disable interrupts at that point in your code. For
example, in the getc function in the kernel keyboard driver, you access the shared variables of the keyboard
ring buffer (kbd_buffer). If multiple threads were to call this function at the same time, you might see a race
condition, and disabling interrupts is a fairly simple way to solve the issue on a single CPU machine.
About the lag. Looking at your keyboard driver code, I see some things I would perhaps do differently. Some of
them might contribute to the overall behavior:
- The kbd_handle function is an interrupt handler, called by the interrupt handling function in
kernel/exc/int.c whenever a key is pressed. You should not need to call the function from other places, in
particular it is strange that you would call it from getc.
- Still about the kbd_handle function. When it is used correctly (that is, only called when a key is pressed),
you do not need to have a while loop in there waiting for kbd_getchar to return a non zero value. In fact, any
kind of potentially unbounded loop in an interrupt handler is wrong, you need to be able to guarantee that the
handler will return fairly quickly.
- Taken together, the two points above might explain some of the lag. Imagine your userspace program calls
getc, which eventually lands in the keyboard driver getc. If no key is pressed, the calling thread goes to
sleep. After key press, the kbd_handler function is called in response to the interrupt generated by the
keyboard hardware. It will read the key, put it into the buffer, and wake the thread waiting for the key. In
your implementation, this thread immediately calls the kbd_handler function again, but the keyboard hardware
has already informed your code about that one key press, so it will report no key pressed, and the kbd_handler
function will keep waiting for another key in the while loop. After that key is pressed, the function will
return to getc, which will report the first key of the pair, creating an impression of a lag.
> 2. In the sys_exit function we are demanded to terminate the main, which can be found in the process-structure
> as "process->main_uthread", id use thread_destroy, but that only works for thread_t not for uthread. On top of
> that uthread is never really defined. In thread.h it is defined using forward declaration. Can I assume based
> on this, that I can just cast it?
I think the assignment text is poorly worded on this point, sorry about this. For exit to make sense, it should
terminate all threads of the calling process. If you look into the sys_thread_create function, you will see
that it maintains a list of userspace threads in the process structure (uthread_list). Exit should therefore
traverse this list and destroy the listed threads.
To destroy a userspace thread when you have an uthread reference, you should access its thread field to get the
thread reference for thread_destroy, and then remove the uthread from the list and free the memory. See
kernel/proc/sys_thread.h for the definition of the uthread structure, and, for example, the end of the
process_create function in kernel/proc/process.c for code that releases allocated uthread (in the branch that
reacts to main thread creation failure).
> 3. At the moment i'm just vma_map in sys_vma_map, same for vma_map and sys_vma_map. Do I have to check and
> return if there is any memory left?
I think your code already does the check - vma_map will return an error code (ENOMEM) if it cannot allocate the
requested block, and your sys_vma_map returns that to the userspace application, which is I think fine (there
is little else you could do in that situation anyway, it is the userspace application that has to handle the
error).
Strictly speaking, you should test the pointer passed to vma_map to make sure it is valid, otherwise your
userspace application can overwrite kernel memory by calling vma_map and passing it a pointer to that memory as
argument. Check out the vma_check_user function in kernel/mm/vmm.c.
> 4. At the moment I copied quite a lot from kernel-side malloc.c into user-malloc.c (attachment). i don't feel
> really confident with that solution an it also doesnt seem right, because for some reason i cant call
> malloc_heap(size), within the malloc function. Also I'm worried, that within the malloc_heap I manipulate
> physical memory, what doesnt seem right in userspace. I assumed that in userspace the equivalent of the
> frame_allocator are the vma_syscalls. Is that correct?
Let me start from the end of your question. Yes, your userspace implementation will need to replace the
frame_allocator calls by calls to vma_map and vma_unmap. Since these already return virtual addresses, you do
not have to care about that ADDR_IN_KSEG0 (phys) stuff, you can simply use the addresses returned by the vma
syscalls directly.
Do not worry about copying the kernel malloc code into userspace, in fact this is an acceptable solution.
Briefly browsing through the kernel malloc, I think these are the things that might need handling:
- Frame size, just define it as 4096 (that is, FRAME_WIDTH as 12, and so on) to avoid pulling the frame
allocator header file into userspace.
- Same goes for some other macros, such as ALIGN_UP from kernel/include/c.h, just copy those as needed.
- Calls to frame_alloc and frame_free should be replaced by vma_map and vma_unmap, this removes the need for
using ADDR_FROM_KSEG0 and ADDR_IN_KSEG0.
- The lists are in a header that can probably be copied without modifications.
And I do not see much else.
> 5. I implemented printf on my own, even tho i could have used the predefined solution by passing the arguments
> to the kernel, because I didnt see that exists. Do have to change that?
Doing printf on your own is actually better I think (passing the pointers to the kernel needs a bit of extra
work anyway, see the note on pointer checking above, so even in kernel you would need to have a separate printf
implementation for calls from userspace).
Regards, Petr
More information about the NSWI004
mailing list