os-workshop

same materials and sample source for RV32 OS projects
git clone http://frotz.net/git/os-workshop.git
Log | Files | Refs

ex10-threads-cooperative.c (4838B)


      1 // Copyright 2022, Brian Swetland <swetland@frotz.net>
      2 // Licensed under the Apache License, Version 2.0
      3 
      4 #include <hw/debug.h>
      5 #include <hw/riscv.h>
      6 #include <hw/context.h>
      7 #include <hw/intrinsics.h>
      8 #include <hw/platform.h>
      9 #include <hw/litex.h>
     10 #include <gfx/gfx.h>
     11 #include <string.h>
     12 
     13 // (extremely simple) memory management
     14 // ------------------------------------
     15 
     16 #define MEMORY_TOP (DRAM_BASE + DRAM_SIZE)
     17 
     18 static uint8_t* next_stack = (void*) (MEMORY_TOP - 4096);
     19 static uint8_t* next_heap = (void*) (DRAM_BASE + 1024*1024);
     20 
     21 void* alloc_stack(void) {
     22 	void* s = next_stack;
     23 	next_stack -= 8192;
     24 	memset(next_stack, 0xee, 4096);
     25 	return s;
     26 }
     27 
     28 void* alloc(unsigned sz) {
     29 	sz = (sz + 31) & (~31);
     30 	uint8_t* ptr = next_heap;
     31 	memset(ptr, 0, sz);
     32 	next_heap += sz;
     33 	return ptr;
     34 }
     35 
     36 // (cooperative) thread library
     37 // ----------------------------
     38 
     39 #define THREAD_MAGIC 0x5c95bec3
     40 
     41 typedef struct thread {
     42 	uint32_t magic;
     43 	uint32_t id;
     44 	struct thread *next;
     45 	struct thread *prev;
     46 	cframe_t ctxt;
     47 } thread_t;
     48 
     49 static uint32_t next_thread_id = 1;
     50 
     51 thread_t thread0 = {
     52 	.magic = THREAD_MAGIC,
     53 	.id = 0,
     54 	.next = &thread0,
     55 	.prev = &thread0,
     56 };
     57 
     58 void thread_init(void) {
     59 	threadptr_set(&thread0);
     60 };
     61 
     62 thread_t* thread_create(int (*fn)(void*), void* arg) {
     63 	thread_t *current = threadptr_get();
     64 
     65 	thread_t *t = alloc(sizeof(thread_t));
     66 	t->magic = THREAD_MAGIC;
     67 	t->id = next_thread_id++;
     68 	t->next = current;
     69 	t->prev = current->prev;
     70 	t->prev->next = t;
     71 	t->next->prev = t;
     72 
     73 	// setup threadptr and stackptr
     74 	t->ctxt.tp = (uintptr_t) t;
     75 	t->ctxt.sp = (uintptr_t) alloc_stack();
     76 
     77 	// setup the context_entry thunk
     78 	t->ctxt.s0 = (uintptr_t) arg;
     79 	t->ctxt.s1 = 0;
     80 	t->ctxt.s2 = (uintptr_t) fn;
     81 	t->ctxt.pc = (uintptr_t) context_entry;
     82 
     83 	xprintf("[ created thread %p id=%u sp=%08x pc=%08x ]\n",
     84 		t, t->id, t->ctxt.sp, t->ctxt.s2);
     85 
     86 	return t;
     87 }
     88 
     89 void thread_exit(int status) {
     90 	thread_t *current = threadptr_get();
     91 	thread_t *next = current->next;
     92 	thread_t *prev = current->prev;
     93 
     94 	xprintf("[ thread %p id=%u exited status=%d ]\n", current, current->id, status);
     95 
     96 	if (next == current) {
     97 		xprintf("[ all threads have exited ]\n");
     98 		for (;;) ;
     99 	}
    100 
    101 	// remove current thread from list
    102 	next->prev = prev;
    103 	prev->next = next;
    104 	current->prev = 0;
    105 	current->next = 0;
    106 
    107 	// switch to next thread
    108 	context_switch(&current->ctxt, &next->ctxt);
    109 
    110 	xprintf("[ error: zombie thread ]\n");
    111 	for (;;) ;
    112 }
    113 
    114 void yield(void) {
    115 	thread_t* current = threadptr_get();
    116 	context_switch(&current->ctxt, &current->next->ctxt);
    117 }
    118 
    119 // multithreaded mandelbrot demo
    120 // -----------------------------
    121 
    122 uint16_t colors[12] = {
    123 	0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666,
    124 	0x7777, 0x8888, 0x9999, 0xAAAA, 0xBBBB, 0xCCCC,
    125 };
    126 
    127 int render(gfx_surface_t* _gs,
    128 		uint32_t px0, uint32_t py0,
    129 		uint32_t px1, uint32_t py1) {
    130 	gfx_surface_t gs;
    131 	memcpy(&gs, _gs, sizeof(gs));
    132 
    133 	for (int py = py0; py < py1; py++) {
    134 		int y0 = 650 - (1300 * py) / gs.height;
    135 		for (int px = px0; px < px1; px++) {
    136 			int x0 = -1250 + (1750 * px) / gs.width;
    137 			int x = 0, y = 0;
    138 			for (int i = 0; i < 500; i++) {
    139 				int x2 = x * x / 1000;
    140 				int y2 = y * y / 1000;
    141 				if ((x2 + y2) > 4000) {
    142 					gs.fgcolor = colors[(i > 11) ? 11 : i];
    143 					gfx_plot(&gs, px, py);
    144 					goto done;
    145 				}
    146 				y = 2 * x * y / 1000 + y0;
    147 				x = x2 - y2 + x0;
    148 			}
    149 			gs.fgcolor = 0;
    150 			gfx_plot(&gs, px, py);
    151 		done:
    152 			;
    153 		}
    154 		yield();
    155 	}
    156 
    157 	return 2;
    158 }
    159 
    160 int t1(void* arg) {
    161 	gfx_surface_t *gs = arg;
    162 	gfx_fill(gs, 0, 0, 320, 240, gfx_color(gs, C_WHITE));
    163 	gfx_puts(gs, 0, 240-16, "Thread One");
    164 	return render(gs, 0, 0, 320, 240);
    165 }
    166 int t2(void* arg) {
    167 	gfx_surface_t *gs = arg;
    168 	gfx_fill(gs, 320, 240, 640, 480, gfx_color(gs, C_GRAY75));
    169 	gfx_puts(gs, 320, 480-16, "Thread Two");
    170 	return render(gs, 320, 240, 640, 480);
    171 }
    172 int t3(void* arg) {
    173 	gfx_surface_t *gs = arg;
    174 	gfx_fill(gs, 320, 0, 640, 240, gfx_color(gs, C_GRAY25));
    175 	gfx_puts(gs, 320, 240-16, "Thread Three");
    176 	return render(gs, 320, 0, 640, 240);
    177 }
    178 int t4(void* arg) {
    179 	gfx_surface_t *gs = arg;
    180 	gfx_fill(gs, 0, 240, 320, 480, gfx_color(gs, C_GRAY50));
    181 	gfx_puts(gs, 0, 480-16, "Thread Four");
    182 	return render(gs, 0, 240, 320, 480);
    183 }
    184 
    185 // program start
    186 // -------------
    187 
    188 void interrupt_handler(void) { }
    189 
    190 void exception_handler(eframe_t *ef) {
    191 	xprintf("\n** SUPERVISOR EXCEPTION **\n");
    192 	xprint_s_exception(ef);
    193 	xprintf("\nHALT\n");
    194 	for (;;) ;
    195 }
    196 
    197 void start(void) {
    198 	xprintf("Example 10 - Threads Cooperative\n\n");
    199 
    200 	csr_write(CSR_STVEC, (uintptr_t) trap_entry);
    201 
    202 	// setup the main thread (running now)
    203 	thread_init();
    204 
    205 	// setup graphics
    206 	gfx_surface_t *gs = alloc(sizeof(*gs));
    207 	gfx_init_display(gs);
    208 	memset((void*) gs->pixels, 0, gs->width * gs->height * 2);
    209 
    210 	// launch four worker threads
    211 	thread_create(t1, gs);
    212 	thread_create(t2, gs);
    213 	thread_create(t3, gs);
    214 	thread_create(t4, gs);
    215 
    216 	// exit the main thread
    217 	thread_exit(0);
    218 }
    219