User Level Threads


User level threads is created for light weight threads. It needs to be controlled, context switched and swapped by the process. To the Operating System it is only one process without any threads. Here is one implementation of it:

q.h


#include "TCB.h"

TCB_t *initQ () {
TCB_t *Q = NULL;
return Q;
}

void AddQ(TCB_t *tcb,TCB_t **Q) {

TCB_t *first,*last;
if(*Q == NULL ) {
tcb -> prev = tcb;
tcb -> next = tcb;
*Q = tcb;
return;
}
else {
first = *Q; // 1st node from the head
last = first -> prev; // last node as its prev of 1st

// completeing the Circular Queue
tcb -> next = first;
tcb -> prev = last;

first -> prev = tcb;
last -> next = tcb;
}
}

TCB_t *DelQ(TCB_t **Q) {
if(*Q == NULL) {
printf("Queue Emptyn");
return NULL;
}
TCB_t *curr,*last,*first;
curr = *Q ;
first = curr; // the element to be removed
last = curr -> prev; // last element
curr = curr-> next; // 2nd element whihc will be 1st
last -> next = curr; // remove last's link from 1st to 2nd
curr -> prev = last; // remove 2nd's link from first to last
first -> next = first -> prev = NULL; // remove all links of 1st to remove dangling pointer
if(first == last)
*Q = NULL; // removing last element so Q empty
else
*Q = curr; //Change starting point of the Q to 2nd value from 1st
return first;
}

TCB_t *RotateQ(TCB_t **Q) {
TCB_t *curr = *Q;
curr = curr -> next;
*Q = curr;
return curr;
}

void printQ(TCB_t *Q) {
printf("Queue Contains the Functions:");
TCB_t *curr;
int i = 1;
curr = Q;
if(curr == NULL) {
printf("Queue Emptyn");
return;
}
do{
printf("%d ",curr -> i);
curr = curr -> next;
}while(curr != Q);
printf("n");
}

tcb.h


#include <ucontext.h>
#include <string.h>

struct TCB {
ucontext_t context;
int i;
struct TCB *next, *prev;
};
typedef struct TCB TCB_t;

void init_TCB (TCB_t *tcb, void *function, void *stackP, int stack_size)
// arguments to init_TCB are
//   1. pointer to the function, to be executed
//   2. pointer to the thread stack
//   3. size of the stack
{
memset(tcb, '\0', sizeof(TCB_t));       // wash, rinse
getcontext(&tcb->context);              // have to get parent context, else snow forms on hell
tcb->context.uc_stack.ss_sp = stackP;
tcb->context.uc_stack.ss_size = (size_t) stack_size;
makecontext(&tcb->context, function, 0);// context is now cooked
}

threads.h


#include "q.h"
TCB_t *Q;
int count_threads = 0;
void start_thread(void (*function)(void))
{ // begin pseudo code
//allocate a stack (via malloc) of a certain size (choose 8192)
void *stackP = malloc(8192);
//allocate a TCB (via malloc)
TCB_t *tcb = (TCB_t *) malloc(sizeof(TCB_t));
//call init_TCB with appropriate arguments
init_TCB (tcb,function, stackP, 8192);
tcb -> i = ++count_threads;
//call addQ to add this TCB into the “RunQ” which is a global header pointer
AddQ(tcb,&Q);
printQ(Q);
printf("Thread %d Initialisedn",count_threads);
//end pseudo code
}

void run()
{
ucontext_t parent;     // get a place to store the main context, for faking
getcontext(&parent);   // magic sauce
swapcontext(&parent, &(Q->context));  // start the first thread
}

void yield() // similar to run
{
printQ(Q);
//rotate the run Q;
TCB_t *curr = Q;
TCB_t *RunQ = RotateQ(&Q);
//swap the context, from previous thread to the thread pointed to by runQ
printf("Switching from Thread %d to Thread %dn",curr->i,RunQ->i);
swapcontext(&(curr -> context), &(RunQ->context));
}

void exitFunction() {
//rotate the run Q;
TCB_t *curr = Q;
DelQ(&Q);
if(Q == NULL) return;
printQ(Q);
TCB_t *RunQ = Q;
//swap the context, from previous thread to the thread pointed to by runQ
printf("Exiting Thread %d to Thread %dn",curr->i,RunQ->i);
printQ(Q);
swapcontext(&(curr -> context), &(RunQ->context));
}

 

thread_test.c


#include<stdlib.h>
#include <stdio.h>

#include "threads.h"
#define SLEEP_TIME 1

int global = 0;
int ID = 1;

void function() {
printf("Function Started 1st Timen");
fflush(stdout);
int local = 0;
int lID = ID++;
while(1)
{
printf("Function %d Runningn",lID);
sleep(SLEEP_TIME);
yield();
printf("Function %d Incrementing Local=%d,Global=%dn",lID,local++,global++);
sleep(SLEEP_TIME);
printf("Function %d Yieldsn",lID);
yield();
}
printf("Function %d Exitsn",lID);
exitFunction(&Q);
}

void main(){
Q = initQ();
start_thread(function);
start_thread(function);
start_thread(function);
printQ(Q);
run();
}

 


, , ,

  1. No comments yet.
(will not be published)