1.2 xv6 Light Weighted Process(LWP, Thread) - KeonYeong/LKY GitHub Wiki
Thread Create :
- If Thread Create SYSCALL occurs, thread_create is started. Takes 3 arguments (thread ID, start routine and argument for func), and
create LWP.
+LWP basically copies almost of parent process' proc structure. - LWP first makes kernal stack of its own, then copies page directory of parent process.
- There is a array for checking the space available for creating stack of each threads. 3-1. Using that space, according to original proc's size (about page directory's bound) makes new variable holding the stack address for LWP.
- Allocate the page directory for LWP using allocuvm and we put the argument for func and return address into the stack allocated and put it into esp (Start routine goes into eip)
- After that follows the remaining steps of fork() function. +LWP has same pid with their parent process.
Thread Join :
- When Join SYSCALL occurs, basically we follow the steps of wait() function.
- First, return value made from thread_exit() is stored on the retval (Second argument).
- In the loop, we find the process that has the same LWP ID with the thread (First argument) from the process table.
+ Moreover, check one more condition which is checking whether process found on the process table is LWP(thread) or not.
3 - 1. Moreover, while initializing the variables in the proc structure of found process we don't free the page directory of that process but only the page directory for the LWP's own stack.
+ Also, initialize the variables related to LWP. - The process which called join function becomes sleeping state.
Thread Exit:
- After Exit SYSCALL occurs, basically follows the exit() function.
- However, we don't call initproc() function because it might initialize the main process.
- Then the return value (argument) is stored on the main process' variable created in order to send value to thread_join() function.
System Calls:
Arguments are taken using argint() function. Then the each variables are saved into certain arguments need in order using type casting.
Other System Calls: =
-
exit(): There are two supplementary functions applied in order to be compatible to threads.
1-1. When process is exit even though its child threads are survived, those child threads are automatically ended. (state becomes ZOMBIE, This is done by iterating ptable) 1-2. When thread makes exit() system call, it automatically ends all of the other threads that have same parents, and moreover it quits the parent process also. + Those threads which do not have parent process are cared as Zombie, their state turn into ZOMBIE and new flag called isZombie is turned on. Then in wait() system call in the first layer of the infinite loop, CPU will search ptable for those threads whose isZombie is 1, and deallocate all of those threads. -
fork() : When thread makes fork() system call, a process is created equally. Also since the some space of page directory would be blank because of threads, in copyuvm, when there're no data in memory, panic is substituted by continue; (when thread made fork() call). + But then when it exits, it wakes up the thread that called fork syscall not the process holding the thread.
-
exec() : In original exec syscall, old page directory was removed after the exec system call. However in the thread-calling-exec() syscall, the old page directory is conserved and only the stack page for thread is exchanged. Also, at the beginning of the exec(), there's a function that makes all the other threads' state into ZOMBIE which means other LWPs are cleaned.
-
sbrk() : When sbrk() syscall happens, the memory is increased in same order. However, since there are spaces for threads right below the main process's page, new memory is allocated under the PGSIZE * 64 (Because there are only 64 thread pages below the main memory). All the memory functions are executed on those space. + However if the process doesn't have any threads, it allocates the memory in same manner as original thread. + Moreover since sbrk function changes the variable 'sz', there could be such situations that process' size (proc->sz) changed effecting thread_create, hence there is one more variable named 'stdsz(standard sz)' in order to pointing on end of process' page directory(or start of the first thread's page directory).
-
kill() : When kill with given pid is occured in thread, all processes or threads with same pid will be ended. The process will wake up if it was sleeping, and the other threads will be on orphan state (waiting for parent process to finish them). The main process will end and so does to holding threads.
-
pipe(): pipe will be shared instead of duplicating samely to threads. All the thread will share the data and data will be synchronized.
-
sleep() : If thread calls sleep syscall, Its state will be turned into 'sleep' same as normal process.
-
stride() or set_cpu_share(): If a process calls set_cpu_share when it already has several threads, the given share will be divided into number of threads + process itself. Then all the threads and process will be holding same share and stride and execute on stride scheduler. If a process already has the share without threads and makes thread_create() syscall, newly created threads will be given a divided share according to the number of existing threads. When thread exits, in the thread_exit() the share will be re-calculated and re-allocated to each threads and main process. (Finding threads are done by finding same pid's processes when iterating ptable)
!! New variables are added to proc.h and I explained all of them with remark put on next to variables.
!! Main File changed is 'proc.c'