NOT WORKING!!!!

This commit is contained in:
secXsQuared 2016-06-01 19:16:20 -07:00
parent 24a458858d
commit 2475039543
2 changed files with 550 additions and 0 deletions

View File

@ -0,0 +1,101 @@
/*-------------------------------------------------------
|
| bifrost_thread.h
|
| Contains Bifrost threading APIs,
|
|--------------------------------------------------------
|
| Copyright ( C ) 2016 Microsoft Corp.
| All Rights Reserved
| Confidential and Proprietary
|
|--------------------------------------------------------
*/
#pragma once
#include "linked_list.h"
#include "bifrost_sim.h"
#include "avl_tree.h"
#define STATE_NUM (5)
typedef enum {
NEW = 0 ,
BLOCK = 1,
RUN = 4,
READY = 3,
EXIT = 2
} hw_thread_state_t;
#define PRIORITY_LEVEL_NUM (5)
typedef enum
{
HIGHEST = 0,
HIGH = 1,
MEDIUM = 2,
LOW = 3,
LOWEST = 4,
} hw_thread_priority_t;
typedef struct
{
UINT32 pc;
UINT32 sp;
UINT32 a2;
UINT32 a3;
UINT32 a4;
UINT32 a5;
UINT32 a6;
UINT32 a7;
UINT32 a8;
UINT32 a9;
UINT32 a10;
UINT32 a11;
UINT32 a12;
UINT32 a13;
UINT32 a14;
UINT32 a15;
UINT32 ps;
UINT32 epc;
} __attribute__((packed)) hw_regs_t;
typedef struct {
linked_list_node_t list_node;
avl_tree_node_t tree_node;
UINT32 thread_id;
UINT32 core_id;
hw_thread_priority_t priority;
void* stack_ptr;
UINT32 stack_size;
hw_regs_t regs;
void (*proc)(void*);
void* args;
hw_thread_state_t state;
INT32 exit_code;
HW_MAILBOX mailbox;
_Bool initialized;
} hw_tcb_t;
int hw_thread_create(void (*proc)(void*),
void* args,
hw_thread_priority_t priority,
UINT32 stack_size,
UINT32* thread_id);
int hw_thread_start(UINT32 thread_id);
int hw_thread_block(UINT32 thread_id);
int hw_thread_resume(UINT32 thread_id);
int hw_thread_destroy(UINT32 thread_id);
int hw_thread_get_exit_code(UINT32 thread_id, INT32 *exit_code);
void hw_thread_exit(INT32 exit_code);
void hw_thread_init();

449
miscellaneous/hw_thread.c Normal file
View File

@ -0,0 +1,449 @@
#include "bifrost_thread.h"
#include "avl_tree.h"
#include <stdint.h>
// global structures
static hw_tcb_t *g_core_current_thread[HW_PROC_CNT];
extern UINT32 ts_arch_context_switch_ASM(void *curTestRegs, void *targetTestRegs);
extern UINT32 ts_arch_resume_ASM(void *curTestRegs, void *targetTestRegs);
static HW_LOCK g_avl_lock;
static avl_tree_t g_global_thread_tree;
static HW_LOCK g_core_lock[HW_PROC_CNT];
static linked_list_t g_core_thread_list[HW_PROC_CNT][STATE_NUM - 1][PRIORITY_LEVEL_NUM];
static UINT32 g_thread_id_count;
static HW_LOCK g_thread_id_count_lock;
static _Bool initialized = false;
static INT32 _thread_id_compare(avl_tree_node_t *tree_node, avl_tree_node_t *my_node)
{
hw_tcb_t *tcb = OBTAIN_STRUCT_ADDR(tree_node, tree_node, hw_tcb_t);
hw_tcb_t *my_tcb = OBTAIN_STRUCT_ADDR(my_node, tree_node, hw_tcb_t);
return tcb->thread_id - my_tcb->thread_id;
}
static _Bool _thread_id_equal(linked_list_node_t *list_node, linked_list_node_t *my_node)
{
hw_tcb_t *tcb = OBTAIN_STRUCT_ADDR(list_node, list_node, hw_tcb_t);
hw_tcb_t *my_tcb = OBTAIN_STRUCT_ADDR(my_node, list_node, hw_tcb_t);
return tcb->thread_id == my_tcb->thread_id;
}
static hw_tcb_t *_get_tcb_by_id(uint32_t thread_id)
{
avl_tree_node_t *temp;
hw_tcb_t clone, *result;
clone.thread_id = thread_id;
temp = avl_tree_search(&g_global_thread_tree, &clone.tree_node);
return temp == NULL ? NULL : OBTAIN_STRUCT_ADDR(temp, tree_node, hw_tcb_t);
}
static void _adjust_queue(int core_num, hw_thread_state_t old, hw_thread_state_t new, hw_thread_state_t cond)
{
for (int priority = 0; priority < PRIORITY_LEVEL_NUM; priority++)
{
linked_list_t *list = &g_core_thread_list[core_num][old][priority];
linked_list_node_t *cur = linked_list_first(list);
uint32_t index = 0;
while (cur != NULL)
{
hw_tcb_t *tcb = OBTAIN_STRUCT_ADDR(cur, list_node, hw_tcb_t);
cur = linked_list_next(cur);
if (tcb->state == cond)
{
linked_list_remove(list, index);
linked_list_push_back(&g_core_thread_list[core_num][new][priority], &tcb->list_node);
index--;
}
index++;
}
}
}
//
// THE NULL PROC
//
static UINT32 _null_proc_id;
static void _null_proc(void* par)
{
while(1)
{
hw_printf("==NULL PROC==\n");
}
}
// Absolutely unexposed routine. Only extern
// DPC Level
static UINT64 _dummy_regs[16];
void hw_thread_schedule()
{
if(initialized)
{
const int core_num = hw_getCoreNum();
hw_tcb_t *old_tcb = g_core_current_thread[core_num];
hw_lock(&g_core_lock[core_num], false);
// move anything ready from new queue to ready queue
_adjust_queue(core_num, NEW, READY, READY);
// move anything blocked from ready queue to block queue
_adjust_queue(core_num, READY, BLOCK, BLOCK);
// move anything ready from block queue to ready queue
_adjust_queue(core_num, BLOCK, READY, READY);
// check current thread -> block to block queue, run to ready queue, exit to exit queue
if (old_tcb != NULL)
{
if (old_tcb->state == BLOCK)
{
linked_list_push_back(&g_core_thread_list[core_num][BLOCK][old_tcb->priority], &old_tcb->list_node);
}
else if (old_tcb->state == RUN)
{
old_tcb->state = READY;
linked_list_push_back(&g_core_thread_list[core_num][READY][old_tcb->priority], &old_tcb->list_node);
}
else if (old_tcb->state == EXIT)
{
linked_list_push_back(&g_core_thread_list[core_num][EXIT][old_tcb->priority], &old_tcb->list_node);
}
else
{
// CRITICAL ERROR
// DISCARD THE ERRONEOUS THREAD FOREVER
}
}
// pick a new thread and run
for (int i = 0; i < PRIORITY_LEVEL_NUM; i++)
{
linked_list_node_t *front;
front = linked_list_pop_front(&g_core_thread_list[core_num][READY][i]);
if (front != NULL)
{
g_core_current_thread[core_num] = OBTAIN_STRUCT_ADDR(front, list_node, hw_tcb_t);
g_core_current_thread[core_num]->state = RUN;
break;
}
}
hw_unlock(&g_core_lock[core_num], false);
if(g_core_current_thread[core_num] != NULL)
{
hw_printf("SELECTED: %d\n", g_core_current_thread[core_num]->thread_id);
// Spills window registers to the current test's stack
xthal_window_spill();
if (g_core_current_thread[core_num]->initialized)
{
// Transfer control with a jump to prevent doing anything with window registers
__asm volatile("mov a2, %0 \n" \
"mov a3, %1 \n" \
"j ts_arch_resume_ASM"
::"a" (old_tcb == NULL ? &_dummy_regs[0] : &old_tcb->regs), "a" (&g_core_current_thread[core_num]->regs)
: "a2", "a3");
}
else
{
g_core_current_thread[core_num]->initialized = true;
_xtos_ints_on(0x00200002);
// Transfer control with a jump to prevent doing anything with window registers
__asm volatile("mov a2, %0 \n" \
"mov a3, %1 \n" \
"j ts_arch_context_switch_ASM"
::"a" (old_tcb == NULL ? &_dummy_regs[0] : &old_tcb->regs), "a" (&g_core_current_thread[core_num]->regs)
: "a2", "a3");
}
}
}
return;
}
extern HW_RESULT hw_int_set(HW_INT_VECTOR_MASK mask);
static void _yield()
{
hw_int_set(1 << HW_INT_SW_5);
}
static void _ensure_priority(hw_tcb_t *cur, hw_tcb_t *next)
{
if (cur != NULL && next != NULL)
{
if (cur->priority > next->priority)
{
_yield();
}
}
}
void hw_thread_init()
{
if (!initialized)
{
g_thread_id_count_lock = 0;
g_thread_id_count = 0;
g_avl_lock = 0;
avl_tree_init(&g_global_thread_tree, _thread_id_compare);
for (int i = 0; i < HW_PROC_CNT; i++)
{
g_core_current_thread[i] = NULL;
g_core_lock[i] = 0;
for (int j = 0; j < STATE_NUM; j++)
{
for (int k = 0; k < PRIORITY_LEVEL_NUM; k++)
{
linked_list_init(&g_core_thread_list[i][j][k]);
}
}
}
initialized = true;
hw_thread_create(_null_proc,NULL, LOW, 0x2000, &_null_proc_id);
hw_thread_start(_null_proc_id);
}
}
int hw_thread_create(void (*proc)(void *),
void *args,
hw_thread_priority_t priority,
UINT32 stack_size,
UINT32 *thread_id)
{
if (!initialized)
return THREAD_STATUS_UNINITIALIZED;
if (proc == NULL)
return THREAD_STATUS_INVALID_ARGUMENT;
// make one allocation to save time
hw_tcb_t *tcb = (hw_tcb_t *) hw_alloc(sizeof(hw_tcb_t) + stack_size);
if (tcb == NULL)
return THREAD_STATUS_OUT_OF_MEMORY;
HW_INT_VECTOR_MASK irql;
tcb->proc = proc;
tcb->stack_ptr = (char *) tcb + sizeof(hw_tcb_t) + stack_size;
tcb->args = args;
tcb->priority = priority;
tcb->stack_size = stack_size;
tcb->state = NEW;
tcb->core_id = hw_getCoreNum();
tcb->exit_code = 0;
tcb->initialized = false;
tcb->regs.pc = proc;
tcb->regs.sp = tcb->stack_ptr;
tcb->regs.ps = PS_WOE_MASK | PS_UM_MASK | PS_EXCM_MASK | (1 << PS_CALLINC_SHIFT);
irql = hw_lock_irq_save(&g_thread_id_count_lock);
tcb->thread_id = g_thread_id_count;
g_thread_id_count++;
hw_unlock_irq_restore(&g_thread_id_count_lock, irql);
if (thread_id != NULL)
{
*thread_id = tcb->thread_id;
}
// write per core table
irql = hw_lock_irq_save(&g_core_lock[tcb->core_id]);
linked_list_push_back(&g_core_thread_list[tcb->core_id][tcb->state][tcb->priority],
&tcb->list_node);
hw_unlock_irq_restore(&g_core_lock[tcb->core_id], irql);
// write avl tree
hw_lock(&g_avl_lock, false);
avl_tree_insert(&g_global_thread_tree, &tcb->tree_node);
hw_unlock(&g_avl_lock, false);
return THREAD_STATUS_SUCCESS;
}
int hw_thread_start(UINT32 thread_id)
{
if (!initialized)
return THREAD_STATUS_UNINITIALIZED;
int result = THREAD_STATUS_SUCCESS;
hw_tcb_t *target = NULL;
hw_lock(&g_avl_lock, false);
target = _get_tcb_by_id(thread_id);
if (target == NULL)
{
result = THREAD_STATUS_INVALID_ARGUMENT;
}
else
{
if (target->state == NEW)
{
target->state = READY;
}
else
{
result = THREAD_STATUS_ACTION_NOT_APPLICABLE;
}
}
hw_unlock(&g_avl_lock, false);
_ensure_priority(g_core_current_thread[hw_getCoreNum()], target);
return result;
}
int hw_thread_destroy(UINT32 thread_id)
{
if (!initialized)
return THREAD_STATUS_UNINITIALIZED;
// make one allocation to save time
hw_tcb_t *tcb;
int result = THREAD_STATUS_SUCCESS;
HW_INT_VECTOR_MASK irql;
// detach tcb
hw_lock(&g_avl_lock, false);
tcb = _get_tcb_by_id(thread_id);
if (tcb == NULL)
{
result = THREAD_STATUS_INVALID_ARGUMENT;
}
else
{
if (tcb->state == EXIT)
{
avl_tree_delete(&g_global_thread_tree, &tcb->tree_node);
}
else
{
result = THREAD_STATUS_ACTION_NOT_APPLICABLE;
}
}
hw_unlock(&g_avl_lock, false);
if (result == THREAD_STATUS_SUCCESS)
{
irql = hw_lock_irq_save(&g_core_lock[tcb->core_id]);
linked_list_remove(&g_core_thread_list[tcb->core_id][tcb->state][tcb->priority],
linked_list_search(&g_core_thread_list[tcb->core_id][tcb->state][tcb->priority],
&tcb->list_node, _thread_id_equal));
hw_unlock_irq_restore(&g_core_lock[tcb->core_id], irql);
hw_free(tcb);
}
return result;
}
int hw_thread_get_exit_code(UINT32 thread_id, INT32 *exit_code)
{
if (!initialized)
return THREAD_STATUS_UNINITIALIZED;
if (exit_code == NULL)
return THREAD_STATUS_INVALID_ARGUMENT;
int result = THREAD_STATUS_SUCCESS;
hw_tcb_t *target = NULL;
hw_lock(&g_avl_lock, false);
target = _get_tcb_by_id(thread_id);
if (target == NULL)
{
result = THREAD_STATUS_INVALID_ARGUMENT;
}
else
{
if (target->state == EXIT)
{
*exit_code = target->exit_code;
}
else
{
result = THREAD_STATUS_ACTION_NOT_APPLICABLE;
}
}
hw_unlock(&g_avl_lock, false);
return result;
}
void hw_thread_exit(INT32 exit_code)
{
if (initialized)
{
HW_INT_VECTOR_MASK irql;
int core_num = hw_getCoreNum();
irql = hw_lock_irq_save(&g_core_lock[core_num]);
g_core_current_thread[core_num]->state = EXIT;
g_core_current_thread[core_num]->exit_code = exit_code;
hw_unlock_irq_restore(&g_core_lock[core_num], irql);
_yield();
}
}
int hw_thread_block(UINT32 thread_id)
{
if (!initialized)
return THREAD_STATUS_UNINITIALIZED;
int result = THREAD_STATUS_SUCCESS;
hw_tcb_t *target = NULL;
hw_lock(&g_avl_lock, false);
target = _get_tcb_by_id(thread_id);
if (target == NULL)
{
return THREAD_STATUS_INVALID_ARGUMENT;
}
else
{
if (target->state == RUN || target->state == READY)
{
target->state = BLOCK;
}
else
{
result = THREAD_STATUS_ACTION_NOT_APPLICABLE;
}
}
hw_unlock(&g_avl_lock, false);
hw_tcb_t *cur_tcb = g_core_current_thread[hw_getCoreNum()];
if (cur_tcb != NULL && thread_id == cur_tcb->thread_id)
{
_yield();
}
return result;
}
int hw_thread_resume(UINT32 thread_id)
{
if (!initialized)
return THREAD_STATUS_UNINITIALIZED;
int result = THREAD_STATUS_SUCCESS;
hw_tcb_t *target = NULL;
hw_lock(&g_avl_lock, false);
target = _get_tcb_by_id(thread_id);
if (target == NULL)
{
result = THREAD_STATUS_INVALID_ARGUMENT;
}
else
{
if (target->state == BLOCK)
{
target->state = READY;
}
else
{
result = THREAD_STATUS_ACTION_NOT_APPLICABLE;
}
}
hw_unlock(&g_avl_lock, false);
_ensure_priority(g_core_current_thread[hw_getCoreNum()], target);
return result;
}