CSE 451 Section Notes

CSE 451
Introduction to Operating Systems

Autumn 1998


Assignment 3 FAQ and More


Tips on Writing the Preemptive Minithreads System:

Here are some basic tips (passed on through generations of CSE 451 TAs) for writing the preemptive minithreads system:


Answers To Frequently Asked Questions:


> I realize we are building our own thread system. But do we use any of
> the UNIX thread commands anywhere in our definitions? For example, when
> we call our minithread_fork(), do we implement the UNIX command
> thread_fork() inside that function?
No, you are not allowed to use any of the thread management functions on Unix. Your program should run without the thread package. The idea is to implement functions similar to pthread_fork() yourself.


> If we are not using the UNIX thread commands, I'm not clear how we can
> switch_context to get the PC pointed at the right place and start
> execution of a different thread.
You will be using minithread_switch() which is declared in minithread_public.h for making a context switch. This function calls context_switch() which is an assembly function in sys.S

Here is something about minithread_switch() which might not be mentioned in the docs:

  void minithread_switch( stack_pointer_t *old_thread_sp,
                          stack_pointer_t *new_thread_sp );

Both parameters are pointers to stack pointers, which points to the malloced stacks. The first parameter is an ouput parameter while the second one is an input parameter.

So you call minithread_switch() as follows:

  stack_pointer_t oldsp,  /* oldsp is uninitialised                       */
                  newsp;  /* Set to the stack of the new thread to be run */

  newsp = ....
  minithread_switch( &oldsp, &newsp ); /* This saves the context into     */
                                       /* the current stack, changes the  */
                                       /* stack to newsp and restores the */
                                       /* context of that thread.         */

The function returns in the new thread (because the new thread, when it blocked, called context switch). When it returns, oldsp contains the stack pointer of the thread which called minithread_switch()

Note that there is an exception to this when the thread is scheduled for the first time. It will start executing from minithread_root which is defined in sys.S.



> I am wondering if someone is to use this minithread package, can I
> assume that the client would always call minithread_initialize(...) to
> start the program?
They will call minithread_system_initialize(...)


> Also, in the example you gave us last week (quiz 3), the p_thread
> package has this pthread_join(...) function to make sure that the main()
> thread wouldn't exit before the threads created by it finish, right? I've
> tried taking out those join statements and the result is some threads
> didn't get to print out their stuff. So in our minithread package, do we
> have to always make sure that the main thread (main()) doesn't exit until
> all the other threads are done??
When you call minithread_system_initialize(..) the thread system starts up. The function never returns. It starts up the first thread. The process exit()s when all the threads have died (because you cannot create another thread if all the threads terminated.)


> And I'm also a bit confused about the minithread.h interface. Is
> minithread_fork() basically the same as calling minithread_create() and
> then minithread_start()? Or actually, they're supposed to do different
> things?
You are right. minithread_fork() is same as minithread_create() followed by minithread_start().


> Finally, about minithread_stop(), when we stop a thread, are we
> supposed to free it? I guess what I really want to ask is what is the
> difference between minithread_yield and minithread_stop, 'cause in some
> cases, we might want to stop a thread while still want to use it later...
> like when there is a semaphore blocking?? Am I thinking this right?
minithread_stop() should only remove the thread from the ready queue. It is put back into the ready queue only when another thread calls minithread_start(). minithread_yield() removes the current thread from the processor and puts it at the end of the ready queue. So, calling yield doesn't block the thread.

A thread is deallocated when it returns from the function. You could also add a function called void minithread_exit() to minithread.h which kills off the thread.



> Since proc_t is of the type:
>
>   typedef int (*proc_t)();
>
> How do the arguments get sent into functions of type proc_t? It looks
> like the function takes no arguments, but we send in arguments when we
> initialize the stack:
>
>   minithread_initialize_stack( stacktop, initial_proc, initial_arg,
>                                body_proc, body_arg, finally_proc,
>                                finally_arg );
Actually, proc_t should be defined as:
typedef int (*proc_t)(void *);
But the compiler doesnot complain because, the functions are called from minithread_root which is written in assembly


> The interface in minithread_public.h says function final_proc shouldn't
> return. How do we write a function that doesn't return? Should we call
> minithread_swith() and give the control to scheduler?
The final_proc() function shouldn't return. You should do a minithread_switch() and make sure that the thread is not put back in the readyQ (maybe you should put it in a deleteQ to be deleted later on by some other thread, e.g. the scheduler).