====== Cvičení 12 : Podpora více vláken v OS NOVA ======
Cílem tohoto cvičení je implementovat do OS NOVA systémové volání
''thread_create'' a ''thread_yield'' a dosáhnout tím podpory
jednoduchých vícevláknových aplikací.
===== Domácí příprava =====
Pro toto cvičení budete potřebovat znalosti o:
* přečíst (ideálně i umět vysvětlit) funkce v OS NOVA:
* bootstrap, make_current, ret_user_sysexit, konstruktor k Ec
* fungování plánovačů v operačním systému (schedulers)
* {{:courses:b4b35osy:lekce03.pdf|Přednaška}}
* instrukce [[https://c9x.me/x86/html/file_module_x86_id_313.html|sysenter]]
* základní syntaxi inline assembleru (tak jako v minulých cvičeních)
* https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html (pochopit příklad z remarks)
* spojové seznamy
* https://en.wikipedia.org/wiki/Linked_list
* programování v C++
===== Zadání úlohy =====
Implementujte systémová volání s následujícími prototypy:
int thread_create(void *(*start_routine)(void *), void *stack_top);
void thread_yield(void);
=== Požadavky ===
**ABI:**
* thread_create eax = 4, esi = start_routine, edi = stack_top
* thread_yield eax = 5
**očekávané chování:**
* //thread_create// vytvoří vlákno a přidá ho do kruhové fronty vytvořených vláken.
* //start_routine// je ukazatel na adresu, od které se zahájí vykonávání nového vlákna.
* //stack_top// je adresa vrcholu zásobníku nového vlákna.
* //thread_create// vrací 0 pokud proběhl bez chyby. V opačném případě vrací libovolné nenulové číslo chyby.
* //thread_yield// přepne vykonávání z aktuálního vlákna na následující vlákno ve frontě.
* Žádné ze systémových volání nesmí končit pádem systému.
* Postupné volání thread_yield přepíná mezi všemi vlákny ve frontě (žádné vlákno se nesmí vynechat).
* Běh vlákna se dá přerušit pouze voláním //thread_yield//.
* Pokud je zavoláno thread_yield po vytvoření nového vlákna, přepne thread_yield na naposledy vytvořené vlákno. Při dalším volání thread_yield se spustí vlákno, které by bylo spuštěno, pokud by se nové vlákno nevytvořilo.
* Za správné umístění a alokaci zásobníku pro nové vlákno je zodpovědný uživatelský program, který volá thread_create.
**Co se odevzdává**:
* Změněný soubor ''kern/src/ec_syscall.cc'' implementující dvě nová systémová volání (implementace volání brk z 10. cvičení tam být nemusí). Archiv můžete vytvořit například pravidlem hw10 v kořenovém souboru Makefile ve zdrojových kódech OS NOVA.
===== Materiály =====
* {{:courses:b4b35osy:cviceni:osy-12threads.pdf|}}
* Ukázkový testovací program:
#include
static inline unsigned syscall1 (unsigned w0)
{
asm volatile (
" mov %%esp, %%ecx ;"
" mov $1f, %%edx ;"
" sysenter ;"
"1: ;"
: "+a" (w0) : : "ecx", "edx", "memory");
return w0;
}
static inline unsigned syscall3 (unsigned w0, unsigned w1, unsigned w2)
{
asm volatile (
" mov %%esp, %%ecx ;"
" mov $1f, %%edx ;"
" sysenter ;"
"1: ;"
: "+a" (w0) : "S" (w1), "D" (w2): "ecx", "edx", "memory");
return w0;
}
int create_thread(void (*start_routine)(void), void * stack)
{
return syscall3(4, (unsigned long)start_routine, (unsigned long)stack);
}
void thread_yield(void)
{
syscall1(5);
}
char stack[0x1000] __attribute__((aligned(16)));
void thread1()
{
while (1) {
printf("%s running\n", __func__);
thread_yield();
}
}
int main()
{
printf("Main thread running\n");
create_thread(thread1, stack + sizeof(stack));
while (1) {
thread_yield();
printf("I'm back in the main thread\n");
}
}