Multi-Threading

I’ve been learning ” Operating Systems and Systems Programming ” Online for a while. I use University of California, Berkley’s Online Webcast lectures and Operating Systems Design and Implementation by Andrew S.Tanenbaum as reading material.

I’m blogging here something which is a simple concept though, performs complex working.

Multithreading is a concept, which makes an illusion of  one or more threads running in parallel. To put up in a simple way, only one thread runs at a time, after a specific threshold time the 1st thread stops and 2nd thread continues running, again after the threshold time 2nd thread stops and 1st resumes running thereby creating a illusion of two threads running at same time.

I’m diving straight into the topic, as the basic concepts are out of scope to this article.

Here is an extract from Prof. John kubiatowicz slide

Consider two threads S and T. Consider S is running. A and B are the routines in each thread. After a specific threshold time or  some boundary value or why not, sometimes even after receiving a interrupt signal the running thread (Thread S) makes a yield call. The yield returns the control of execution to the kernel. The kernel checks for waiting threads i.e the threads in runnable state [sometimes based on priority] and makes a call to switch routine, The sweetest of all.

Switch routine accepts two inputs [current thread pointer and new thread pointer]. The basic functionality of switch looks like this.

Seems simple enough, Registers of current thread [Thread S] is saved to TCB[tCur].regs.rx and the values of new thread’s registers TCB[tNew].regs.rx is over written to the CPU registers CPU.rx. The overwritten registers include stack pointer and return address. After the switch performs its process the control is shifted back to the kernel and the kernel hands over the control to the routine whose address is stored in newly overwritten Instruction pointer. In our case thread T starts running. As instructed by Prof.john kubiatowicz, i had a look at the nachos source code for switch.

Switch.S is written in assembly. It has 4 subroutines [MIPS,SPARC,HP RISC,INTEL], each subroutine is called in specific to the CPU architecture. I’ll discuss here the INTEL’s subroutine alone.

/* void SWITCH( thread *t1, thread *t2 )
**
** on entry, stack looks like this:
**      8(esp)  ->              thread *t2
**      4(esp)  ->              thread *t1
**       (esp)  ->              return address
**
** we push the current eax on the stack so that we can use it as
** a pointer to t1, this decrements esp by 4, so when we use it
** to reference stuff on the stack, we add 4 to the offset.
*/
        .comm   _eax_save,4
        .globl  _SWITCH
_SWITCH:
        movl    %eax,_eax_save          # save the value of eax
        movl    4(%esp),%eax            # move pointer to t1 into eax
        movl    %ebx,_EBX(%eax)         # save registers
        movl    %ecx,_ECX(%eax)
        movl    %edx,_EDX(%eax)
        movl    %esi,_ESI(%eax)
        movl    %edi,_EDI(%eax)
        movl    %ebp,_EBP(%eax)
        movl    %esp,_ESP(%eax)         # save stack pointer
        movl    _eax_save,%ebx          # get the saved value of eax
        movl    %ebx,_EAX(%eax)         # store it
        movl    0(%esp),%ebx            # get return address from stack into ebx
        movl    %ebx,_PC(%eax)          # save it into the pc storage
        movl    8(%esp),%eax            # move pointer to t2 into eax
        movl    _EAX(%eax),%ebx         # get new value for eax into ebx
        movl    %ebx,_eax_save          # save it
        movl    _EBX(%eax),%ebx         # retore old registers
        movl    _ECX(%eax),%ecx
        movl    _EDX(%eax),%edx
        movl    _ESI(%eax),%esi
        movl    _EDI(%eax),%edi
        movl    _EBP(%eax),%ebp
        movl    _ESP(%eax),%esp         # restore stack pointer
        movl    _PC(%eax),%eax          # restore return address into eax
        movl    %eax,4(%esp)            # copy over the ret address on the stack
        movl    _eax_save,%eax
        ret

4(esp) points to thread S and 8(esp) points to thread T, thread S’s address is pulled to eax and all the registers viz ebx,ecx,edx etc are stored with respect to eax.   ex: register ecx gets stored to _ECX(%eax) . Then 8(esp) is loaded to eax, and all registers of thread T are loaded to cpu register. ex: register _ECX(%eax) is loaded to %ecx. The return address of each threads are saved and exchanged respectively.

ps: The diagrams were taken from Prof. John kubiatowicz‘s slides.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s