Skip to content

HaroldLee/Rome2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 

Repository files navigation

/**

@mainpage 15-410 Project 2

@author Kaili Li (kailili)
@author Qi Liu (qiliu)

Implementation:
Part1 Thread library
1. Hash table
    We use a hash table to contain the threads information. As the thread 
    tid generated by the kernal will increase and not repeat. There will be
    less collision in the table. As a result, we expect to find one thread
    item with constant time.
2. How to seperate thread stack.
    We put a blank virtual memory page between every two threads' stack. The
    blank page will not be allocated to any thread. 
    When a thread go across its boundry, it may step in the thread stack 
    below and will corrupt other thread's data. If there is a blank page,
    it will cause a page fault. And the exception handler would find the 
    cross-border behavior and terminate the thread.
 
    Another aspect is that we never put thread information(such as tid) on 
    its stack. Relying on the stack to store the information may spread error
 	from one thread to another thread. I will explain this in the 'How to 
    get tid section'.
 
 3. Exception stack
    Each thread will be allocated with one exception stack(4K Byte) in the 
    front of its stack. Thus, the handler of different threads will execute
    on different stack.
 
 4. Resource recycle
    When a thread exit, we will not release its stack immediately. We will
    put it into a free list. When new thread is created, we will find from 
    the free list first. 
 
 5. How to get tid
    It is true that there are some quick way to get current thread's tid. 
    For example, put the tid on its stack. However, we will not use the 
    method. We do want the stack corruption error to spread to other thread.
 
    Let me explain it with an example, suppose thread 7's stack is corrupted,
    and cause a fault. If the handler, use the tid from the stack, it will
    get some wrong answers, 12 maybe. As a result, the handler may try to
    terminate thread 12.
 
    We want thr_gettid() always return with a right value.
 

 

Part 2: Autostack
The following is the stack architecture in our implementation:
            +++++++++++++++++++
            +                 +
            +    root stack   +
            +                 +
            +++++++++++++++++++
            +                 +
            +    thread1      +
            +  security space +
            +     (4k)        +
            +                 +
            +++++++++++++++++++
            +                 +
            +    thread1      +
            +  handler stack  +
            +      (4k)       +
            +                 +
            +++++++++++++++++++
            +                 +
            +    thread1      +
            +   user stack    +
            +                 +
            +++++++++++++++++++
            +                 +
            +    thread2      +
            +  security space +
            +     (4k)        +
            +                 +
            +++++++++++++++++++
            +                 +
            +    thread2      +
            + handler stack   +
            +      (4k)       +
            +                 +
            +++++++++++++++++++
            +                 +
            +    thread2      +
            +   user stack    +
            +                 +
            +++++++++++++++++++
            +                 +
            +    ......       +
            +                 +
            +++++++++++++++++++
            +                 +
            +    ......       +
            +                 +
            +++++++++++++++++++
            +                 +
            +     root        +
            +  handler stack  +
            +                 +
            +++++++++++++++++++
 At the bottom (up) of the stack, is the user stack for the root thread, this
 is not allocated by us, what we do is just to  record the base and top of 
 this space, and use for further stack growth. if the "thr_init" is not 
 called, there will not be a limit of the stack size. So we do not stop the
 stack grow to a very large size ("ROOT_HDLR_STACK" in autostack.c). Below 
 the "ROOT_HDLR_STACK" is the handler stack for root thread, this is for the
 root thread's excption handler function.
            
 After the thr_init has been called, we will set a max value for the user stack
 space, then we will record it. and the stack size of any thread will be 
 limited by this maxvalue. However, we do not give user the maximum space at
 once, instead, we give one page (4k) to user. When it encounters page fault,
 we give out one page more. In this way, we give page by page until the stack
 size grows to the max size set by "thr_init". The reason we do new_page all
 space user apply is that it may really need that much space, so we can save
 physical memory (not save logical space) in this way.

 Every thread has its own user stack and handler stack. Our consideration is
 that exception handler may be alseo interrupted by aother thread, and that
 thread may also encounters page fault...so we can not only have a "public 
 space" for all handlers. Above the handler stack, is a "security space" 
 for a thread. We have this space is based on following consideration. 
 Suppose we do not have "security space", and we want to create 3 threads,
 1, 2, 3. Suppose 2 is created first, 1 later. Then when stack of thread 1 
 grow to the space of thread 2, it will not encounter a page fault because 
 this space has been paged out when 2 created. Then 2' stack will be accessed
 by 1 without any warning to user. 
 
 Part3: Mutex and condition variables
 
 We do not implement the mutex to satisify bounded waiting. The code section
 between mutex_lock and mutex_unlock is expected to be short. Some method to
 implement bouned-waiting tend to make the mutex_lock complex(more code). 
 
 Our implementation: When a thread try to get a lock and fail, it will yield
 to the thread who is currently hold the lock. So, the thread do not need to
 just wait and do nothing.
 
 Conditon varialbe:

 We have simple link list for the condition queue. Thread will be but in this 
 queue and deschedule it self; on the other hand, another thread will first 
 dequeue a thread if there is, and then record its thread id, then make it 
 runnable in a loop until the make runnable returns SUCCESS. This is a safe 
 implementation because when dequeue has not been finished, the "make run" 
 thread will wait until it finish and then awake it.

 */

Releases

No releases published

Packages

No packages published