Commit 1849e5a6 authored by Sundar Pandian's avatar Sundar Pandian
Browse files

finished, debugged, commented

No related merge requests found
Pipeline #17832 canceled with stage
Showing with 297 additions and 17 deletions
+297 -17
......@@ -9,18 +9,27 @@ CFLAGS = -Wall -g -std=c99 -pedantic
ASFLAGS = -g
all: test
all: test test_arg test_ret
# The simple test program
test: sthread.o queue.o glue.o test.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
# The simple test_arg program
test_arg: sthread.o queue.o glue.o test_arg.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
# The simple test_ret program
test_ret: sthread.o queue.o glue.o test_ret.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
# pseudo-target to clean up
clean:
$(RM) -f *.o core* *~ test
$(RM) -f *.o core* *~ test_arg
$(RM) -f *.o core* *~ test_ret
.PHONY: all clean
......@@ -29,4 +38,6 @@ clean:
sthread.c: sthread.h queue.h
queue.c: queue.h sthread.h
test.c: sthread.h
test_arg.c: sthread.h
test_ret.c: sthread.h
......@@ -27,8 +27,26 @@ scheduler_context: .quad 0
.globl __sthread_switch
__sthread_switch:
# save general registers
# Save the process state onto its stack
# TODO
pushq %rax
pushq %rbx
pushq %rcx
pushq %rdx
pushq %rbp
pushq %rsi
pushq %rdi
pushq %r8
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r14
pushq %r15
# save flag register
pushf
# Call the high-level scheduler with the current context as an argument
movq %rsp, %rdi
......@@ -38,9 +56,29 @@ __sthread_switch:
# The scheduler will return a context to start.
# Restore the context to resume the thread.
__sthread_restore:
# TODO
# restore returned context to stack pointer
movq %rax, %rsp
# restore the process stack
popf
popq %r15
popq %r14
popq %r13
popq %r12
popq %r11
popq %r10
popq %r9
popq %r8
popq %rdi
popq %rsi
popq %rbp
popq %rdx
popq %rcx
popq %rbx
popq %rax
# execute thread function
ret
......@@ -62,11 +100,56 @@ __sthread_restore:
.globl __sthread_initialize_context
__sthread_initialize_context:
# TODO
# Initial Thread Stack
# __sthread_finish
# f
# rax
# rbx
# rcx
# and so on for all general registers
# since all values on thread stack are 64 bit values,
# decrease by 0x08 for each new value
# save rax before using it to push __sthread_finish value
movq %rax, -0x18(%rdi)
# save return address for after thread is finished
leaq __sthread_finish(%rip), %rax
movq %rax, -0x08(%rdi)
# TODO - Make sure you completely document every part of your
# thread context; what it is, and why you set each value
# to what you choose.
# save arg variable
movq %rdx, -0x48(%rdi)
# save function pointer
movq %rsi, -0x10(%rdi)
# save general registers
# Save the process state onto its stack
movq %rbx, -0x20(%rdi)
movq %rcx, -0x28(%rdi)
movq %rdx, -0x30(%rdi)
movq %rbp, -0x38(%rdi)
movq %rsi, -0x40(%rdi)
# movq %rdi, -0x48(%rdi) # pass in arg to be used with function
movq %r8, -0x50(%rdi)
movq %r9, -0x58(%rdi)
movq %r10, -0x60(%rdi)
movq %r11, -0x68(%rdi)
movq %r12, -0x70(%rdi)
movq %r13, -0x78(%rdi)
movq %r14, -0x80(%rdi)
movq %r15, -0x88(%rdi)
# transfer flag register to stack to save
pushf
pop %rax
# save flag register
movq %rax, -0x90(%rdi)
# point context to proper location and return
movq %rdi, %rax
subq $0x90, %rax
ret
......
......@@ -129,8 +129,47 @@ static void enqueue_thread(Thread *threadp) {
*/
ThreadContext *__sthread_scheduler(ThreadContext *context) {
/* TODO: Replace these lines with your implementation */
/* TODO */ assert(0); /* TODO */
// if context is NULL, scheduler has was just started so no need to
// modify current thread since there is none
// else, properly handle the current running thread
if (context != NULL) {
// update current thread's context
current->context = context;
// manipulate thread based on current state
switch(current->state) {
case ThreadRunning: // if thread was running
current->state = ThreadReady; // next thread state is Ready
case ThreadBlocked: // if thread was blocked
enqueue_thread(current); // current's state is properly
break; // set. it is ready to be enqueued
case ThreadFinished: // if thread was finished
__sthread_delete(current); // allow thread memory to be freed
break;
default: // should never get here
fprintf(stderr, "Thread state has been corrupted: %d\n",
current->state);
exit(1);
}
}
// select the next thread from the ready queue for execution, if possible
if (queue_empty(&ready_queue) != 1) {
current = queue_take(&ready_queue);
assert(current != NULL); // ready queue should not be empty so
// current should not be NULL
// update thread state to running
current->state = ThreadRunning;
} else { // else no ready threads
if (queue_empty(&blocked_queue)) { // if no blocked threads
fprintf(stderr, "All threads have completed.\n");// exit
exit(0);
} else { // if there are blocked threads
fprintf(stderr, "Program is deadlocked.\n"); // exit with error
exit(1);
}
}
/* Return the next thread to resume executing. */
return current->context;
......@@ -156,9 +195,27 @@ void sthread_start(void)
* structure, and it adds the thread to the Ready queue.
*/
Thread * sthread_create(void (*f)(void *arg), void *arg) {
/* TODO: Replace this function's body with your implementation */
/* TODO */ assert(0); /* TODO */
return NULL;
// heap allocate a stack for the new thread
void *thread_mem = malloc(DEFAULT_STACKSIZE);
assert(thread_mem != NULL);
// heap allocate a new thread structure
Thread *thread = malloc(sizeof(Thread));
assert(thread != NULL);
// initialize thread memory
thread->memory = thread_mem;
// initialise thread state
thread->state = ThreadReady;
enqueue_thread(thread);
// initialize thread context
thread->context = __sthread_initialize_context(
(void *)((unsigned long)(thread_mem)+(DEFAULT_STACKSIZE)), f, arg);
return thread;
}
......@@ -183,8 +240,8 @@ void __sthread_finish(void) {
* context, as well as the memory for the Thread struct.
*/
void __sthread_delete(Thread *threadp) {
/* TODO: Replace this function's body with your implementation */
/* TODO */ assert(0); /* TODO */
free(threadp->memory); // free thread stack memory
free(threadp); // free thread struct memory
}
......
/*!
* A simple test program for exercising the threads API.
* Tests the functionality of passing in arguments
*
*/
#include <stdio.h>
#include "sthread.h"
/*
* In this version of the code,
* thread scheduling is explicit.
*/
/*! This thread-function outputs the inputted argument */
static void arg1(void *arg) {
fprintf(stderr, "This number better be 1: %ld.\n", (long int) (arg));
sthread_yield();
}
/*! This thread-function outputs the inputted argument */
static void arg2(void *arg) {
fprintf(stderr, "This number better be 2: %ld.\n", (long int) (arg));
sthread_yield();
}
/*
* The main function starts the two functions in separate threads,
* the start the thread scheduler.
*/
int main(int argc, char **argv) {
sthread_create(arg1, (void *)(1));
sthread_create(arg2, (void *)(2));
sthread_start();
return 0;
}
/*!
* A simple test program for exercising the threads API.
* Tests the functionality of multiple threads of diff lifetimes
*
*/
#include <stdio.h>
#include "sthread.h"
/*
* In this version of the code,
* thread scheduling is explicit.
*/
/*! This thread-function loops quad-ice */
static void loop_4(void *arg) {
for(int i = 0; i < 4; i++) {
fprintf(stderr, "Loop 4 Current iteration: %d.\n", i);
sthread_yield();
}
}
/*! This thread-function loops thrice */
static void loop_3(void *arg) {
for(int i = 0; i < 3; i++) {
fprintf(stderr, "Loop 3 Current iteration: %d.\n", i);
sthread_yield();
}
}
/*! This thread-function loops twice */
static void loop_2(void *arg) {
for(int i = 0; i < 2; i++) {
fprintf(stderr, "Loop 2 Current iteration: %d.\n", i);
sthread_yield();
}
}
/*! This thread-function loops once */
static void loop_1(void *arg) {
for(int i = 0; i < 1; i++) {
fprintf(stderr, "Loop 1 Current iteration: %d.\n", i);
sthread_yield();
}
}
/*
* The main function starts the four loops in separate threads,
* the start the thread scheduler.
*/
int main(int argc, char **argv) {
sthread_create(loop_4, NULL);
sthread_create(loop_3, NULL);
sthread_create(loop_2, NULL);
sthread_create(loop_1, NULL);
sthread_start();
return 0;
}
File added
#============================================================================
# __sthread_switch is the main entry point for the thread scheduler.
# It has three parts:
#
# 1. Save the context of the current thread on the stack.
# The context includes all of the integer registers and RFLAGS.
#
# 2. Call __sthread_scheduler (the C scheduler function), passing the
# context as an argument. The scheduler stack *must* be restored by
# setting %rsp to the scheduler_context before __sthread_scheduler is
# called.
#
# 3. __sthread_scheduler will return the context of a new thread.
# Restore the context, and return to the thread.
#
.text
.align 8
.globl output
output:
# Save the process state onto its stack
movq %rsi, %rdx
movq %rdi, %rsi
movq $1 , %rdi
movq $1 , %rax
syscall
# movq $60 , %rax
# syscall
ret
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment