All pastes #1005615 Raw Edit

Mine

public c v1 · immutable
#1005615 ·published 2008-05-03 02:13 UTC
rendered paste body
/* * Implementation for CS325 thread library * Copyright  2008 Anthony Martinez */#define _GNU_SOURCE#include "libthread.h"#include <assert.h>#include <sched.h>#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#include <string.h>#include <search.h>static unsigned int _libthread_maxtid   = 0;static unsigned int _libthread_curtid   = 0;static queue_head_t _runqueue  = {NULL};static queue_head_t _waitqueue = {NULL};static volatile thread_state_t _libthread_global_context;static unsigned int _libthread_save_context = 1;void _enqueue(queue_head_t *q, thread_state_t *new) {    ensure_queue(q);        if(q->head && q->tail) { /* This is not the first element */        insque(q->tail, new);        q->tail = new;    }    else { /* This is the first thing in the queue, so we have to handle head and tail. */        q->head = new;        q->tail = new;        q->head->prev = q->head->next = NULL;    }}thread_state_t *_dequeue(queue_head_t *q) {    thread_state_t *r = NULL;    ensure_queue(q);    if(q->head) {        r = q->head;        q->head = r->next;        if(q->head == NULL) q->tail = NULL;        remque(r);    }    return r;}thread_state_t *_peek(queue_head_t *q) {    ensure_queue(q);    return q->head;}unsigned int thread_create(void *function) {    unsigned int thread_id = _libthread_maxtid++;    thread_state_t *newthread = new_thread_state();    Dprintf("%s: Got function %p\n", __FUNCTION__, function);    newthread->esp = (unsigned int*)malloc(THREAD_STACK_SIZE);    Dprintf("%s: new thread stack from %#x to %#x\n", __FUNCTION__, newthread->esp, newthread->esp+THREAD_STACK_SIZE);#ifdef DEBUG    memset(newthread->esp, 0xF1, THREAD_STACK_SIZE);#endif    newthread->esp += (int)THREAD_STACK_SIZE-4;  /* sgd */    __asm__ __volatile__ ("movl 4(%%ebp), %0" : "=a" (*newthread->esp));    Dprintf("%s: returning to %#x\n", __FUNCTION__, *newthread->esp);    newthread->ebp = newthread->esp;    newthread->eip = (unsigned int*)function;    newthread->id  = thread_id;    _enqueue(&_runqueue, newthread);    return thread_id;}void begin_threads(void) {    thread_state_t *cur_thread = NULL;    Dprintf("%s called\n", __FUNCTION__);    while(1) {        cur_thread = _peek(&_runqueue);        if(cur_thread) {            _libthread_save_context = 0;            thread_switch(cur_thread->id);        }        else {            exit(0);        }    }}void thread_suspend(void) {    __asm__ __volatile__ ("movl %%eax, %0;"                          "movl %%ebx, %1;"                          "movl %%ecx, %2;"                          "movl %%edx, %3;"                          "movl %%esi, %4;"                          "movl %%edi, %5;"                          : "=m"(_libthread_global_context.eax), /* 0 */                            "=m"(_libthread_global_context.ebx), /* 1 */                            "=m"(_libthread_global_context.ecx), /* 2 */                            "=m"(_libthread_global_context.edx), /* 3 */                            "=m"(_libthread_global_context.esi), /* 4 */                            "=m"(_libthread_global_context.edi) /* 5 */                          );    thread_state_t *new_context = new_thread_state();    thread_state_t *next_thread = _peek(&_runqueue);    Dprintf("%s called\n", __FUNCTION__);    memcpy(new_context, (thread_state_t *volatile)&_libthread_global_context, sizeof(thread_state_t));        new_context->id  = _libthread_curtid;    __asm__ __volatile__ ("movl %%ebp, %0" : "=a" (new_context->esp));    new_context->esp += 2;    __asm__ __volatile__ ("movl (%%ebp), %0;"                          "movl 4(%%ebp), %1;"                          : "=a" (new_context->ebp),                            "=c" (new_context->eip));    _enqueue(&_waitqueue, new_context);    if(next_thread) {        _libthread_save_context = 0;        thread_switch(next_thread->id);    }    else {        fprintf(stderr, "%s: got null thread from run queue: H: %p, t:%p\n", __FUNCTION__, _runqueue.head, _runqueue.tail);#ifndef DEBUG        exit(-2);#endif    }    }void thread_switch(unsigned int id) {    __asm__ __volatile__ ("movl %%eax, %0;"                          "movl %%ebx, %1;"                          "movl %%ecx, %2;"                          "movl %%edx, %3;"                          "movl %%esi, %4;"                          "movl %%edi, %5;"                          : "=m"(_libthread_global_context.eax), /* 0 */                            "=m"(_libthread_global_context.ebx), /* 1 */                            "=m"(_libthread_global_context.ecx), /* 2 */                            "=m"(_libthread_global_context.edx), /* 3 */                            "=m"(_libthread_global_context.esi), /* 4 */                            "=m"(_libthread_global_context.edi) /* 5 */                          );    thread_state_t *inspection = _peek(&_runqueue);    thread_state_t *new_context = new_thread_state();    thread_state_t found;        Dprintf("%s: got tid %i, %ssaving context\n", __FUNCTION__, id, _libthread_save_context == 0 ? "not " : "");    if(_libthread_save_context == 0) goto just_switch;    memcpy(new_context, (thread_state_t *volatile)&_libthread_global_context, sizeof(thread_state_t));    __asm__ __volatile__ ("movl %%ebp, %0" : "=m" (new_context->esp));    new_context->esp += 2;    __asm__ __volatile__ ("movl (%%ebp), %0;"                          "movl 4(%%ebp), %1;"                          : "=a" (new_context->ebp),                            "=c" (new_context->eip));    _enqueue(&_runqueue, new_context); just_switch:    /* Our next switch should save context */    _libthread_save_context = 1;    while(inspection != NULL) {        if(inspection->id == id) {            _libthread_curtid = id;            memcpy(&found, inspection, sizeof(thread_state_t));            /* Dprintf("thread_switch: \neax %#8.x\necx %#8.x\nedx %#8.x\nebx %#8.x\nesp %#8.x\nebp %#8.x\nesi %#8.x\nedi %#8.x\neip %#8.x\n", found.eax, found.ecx, found.edx, found.ebx, found.esp, found.ebp, found.esi, found.edi, found.eip); */            if(inspection == _runqueue.head) {                _runqueue.head = inspection->next;            }            if(inspection == _runqueue.tail) {                _runqueue.tail = inspection->prev;            }            remque(inspection);#ifdef DEBUG            memset(inspection, 0x81, sizeof(thread_state_t));#endif            free(inspection);            found.esp--; /* Make room for RA */            *found.esp = (unsigned int) found.eip;            __asm__ __volatile__ ( "movl %0, %%eax;"                                    "movl %1, %%ebx;"                                    "movl %2, %%ecx;"                                    "movl %3, %%edx;"                                    "movl %4, %%esi;"                                    "movl %5, %%edi;"                                    "movl %6, %%esp;"                                    "movl %7, %%ebp;"                                    "ret" :                                   "=m" (found.eax),  /* 0 */                                   "=m" (found.ebx),  /* 1 */                                   "=m" (found.ecx),  /* 2 */                                   "=m" (found.edx),  /* 3 */                                   "=m" (found.esi),  /* 4 */                                   "=m" (found.edi),  /* 5 */                                   "=mV" (found.esp), /* 6 */                                   "=mV" (found.ebp)  /* 7 */                                   );        }#ifdef DEBUG        if(inspection->next && inspection->next->prev != inspection) {            fprintf(stderr, "%s: queue anomaly\n", __FUNCTION__);            abort();        }#endif        inspection = inspection->next;                }}void thread_wakeup(unsigned int id) {    thread_state_t *inspection = _peek(&_waitqueue);    int tried_runq = 0;    Dprintf("%s: got tid %i\n", __FUNCTION__, id); retry: while(inspection != NULL) {        if(inspection->id == id) {            Dprintf("%s: found in %squeue: thread %i context at %p\n", __FUNCTION__, (tried_runq ? "run" : "wait" ), id, (void*)inspection);            if(!tried_runq) {                if(inspection == _waitqueue.head) {                    _waitqueue.head = inspection->next;                }                if(inspection == _waitqueue.tail) {                    _waitqueue.tail = inspection->prev;                }                remque(inspection);                _enqueue(&_runqueue, inspection);            }            return;        }#ifdef DEBUG        if(inspection->next && inspection->next->prev != inspection) {            fprintf(stderr, "%s: queue anomaly\n", __FUNCTION__);            abort();        }#endif                inspection = inspection->next;    }    /* Didn't find our tid on waitq, try runq */    if(!tried_runq) {        inspection = _peek(&_runqueue);        tried_runq = 1;        goto retry;    }    fprintf(stderr, "%s: was asked to wakeup a nonexistent thread %i\n", __FUNCTION__, id);}