From 1332209e318c74a7e308bd2eb7d6209c8f2245ef Mon Sep 17 00:00:00 2001 From: vThor Date: Wed, 20 May 2026 21:54:57 -0300 Subject: [PATCH 01/11] acho que o alarm clock ta pegando --- src/devices/timer.c | 9 +++--- src/threads/thread.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ src/threads/thread.h | 6 ++-- 3 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/devices/timer.c b/src/devices/timer.c index 8b92341..85a3305 100755 --- a/src/devices/timer.c +++ b/src/devices/timer.c @@ -90,10 +90,10 @@ void timer_sleep (int64_t ticks) { int64_t start = timer_ticks (); - - ASSERT (intr_get_level () == INTR_ON); - while (timer_elapsed (start) < ticks) - thread_yield (); + if (timer_elapsed (start) < ticks) + { + thread_sleep (start + ticks); + } } /* Sleeps for approximately MS milliseconds. Interrupts must be @@ -172,6 +172,7 @@ timer_interrupt (struct intr_frame *args UNUSED) { ticks++; thread_tick (); + thread_wake_up(timer_ticks()); } /* Returns true if LOOPS iterations waits for more than one timer diff --git a/src/threads/thread.c b/src/threads/thread.c index ae9ed3f..c3b2ed3 100755 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -25,6 +25,9 @@ that are ready to run but not actually running. */ static struct list ready_list; +/* Lista das Threads bloqueadas */ +static struct list sleep_list; + /* List of all processes. Processes are added to this list when they are first scheduled and removed when they exit. */ static struct list all_list; @@ -72,6 +75,68 @@ static void schedule (void); void thread_schedule_tail (struct thread *prev); static tid_t allocate_tid (void); + +bool wake_up_order(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED) +{ + struct thread *thread_a = list_entry(a, struct thread, sleep_elem); + struct thread *thread_b = list_entry(b, struct thread, sleep_elem); + + if (thread_a->wake_up_tick == thread_b->wake_up_tick) + { + // Se o tempo for igual, desempata pela maior prioridade + return thread_a->priority > thread_b->priority; + } + + // Caso contrário, quem tem o menor tempo vem na frente + return thread_a->wake_up_tick < thread_b->wake_up_tick; +} + + +/* + Coloca a Thread pra dormir pelo tempo determinado + */ +void thread_sleep (int64_t wake_up_tick) +{ + //pego o estado de interrupição atual + enum intr_level old_level; + + //disabilito interrupção + old_level = intr_disable (); + + //pego a thread atual + struct thread *t = thread_current (); + + //adiciono o tempo que a thread precisa + t->wake_up_tick = wake_up_tick; + + //adicono a thread na lista de thread bloqueadas + list_insert_ordered (&sleep_list, &t->sleep_elem, wake_up_order, NULL); + + //bloqueio a thread + thread_block(); + + //volto para a interrupção que estava anteriormente + intr_set_level (old_level); +} + + + +void thread_wake_up (int64_t ticks) +{ + while (!list_empty(&sleep_list)) + { + struct thread *t = list_entry(list_begin(&sleep_list), struct thread, sleep_elem); + if (t->wake_up_tick > ticks) + { + break; + } + list_pop_front(&sleep_list); + thread_unblock(t); + } + +} + + /* Initializes the threading system by transforming the code that's currently running into a thread. This can't work in general and it is possible in this case only because loader.S @@ -92,6 +157,7 @@ thread_init (void) lock_init (&tid_lock); list_init (&ready_list); + list_init (&sleep_list); list_init (&all_list); /* Set up a thread structure for the running thread. */ diff --git a/src/threads/thread.h b/src/threads/thread.h index 7965c06..c0e7b41 100755 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -89,7 +89,8 @@ struct thread uint8_t *stack; /* Saved stack pointer. */ int priority; /* Priority. */ struct list_elem allelem; /* List element for all threads list. */ - + struct list_elem sleep_elem; /* List element para a lista bloqueada */ + int64_t wake_up_tick; /* O tempo que a thread deve estar dormindo*/ /* Shared between thread.c and synch.c. */ struct list_elem elem; /* List element. */ @@ -106,7 +107,8 @@ struct thread If true, use multi-level feedback queue scheduler. Controlled by kernel command-line option "-o mlfqs". */ extern bool thread_mlfqs; - +void thread_sleep (int64_t wake_up_time); +void thread_wake_up (int64_t ticks); void thread_init (void); void thread_start (void); From 95048ad11efbffc544d0ab202a2255768ebdcb63 Mon Sep 17 00:00:00 2001 From: Miriam Gonzaga Date: Thu, 21 May 2026 14:09:32 -0300 Subject: [PATCH 02/11] =?UTF-8?q?Explica=C3=A7=C3=A3o=20das=20fun=C3=A7?= =?UTF-8?q?=C3=B5es=20mais=20importantes=20de=20list.c?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Comentários pra explicar as funções mais utilizadas no projeto --- src/lib/kernel/list.c | 47 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/src/lib/kernel/list.c b/src/lib/kernel/list.c index 316d9ef..f16f367 100755 --- a/src/lib/kernel/list.c +++ b/src/lib/kernel/list.c @@ -56,7 +56,13 @@ is_tail (struct list_elem *elem) return elem != NULL && elem->prev != NULL && elem->next == NULL; } -/* Initializes LIST as an empty list. */ +/* INICIALIZAR UMA LISTA VAZIA! + essa função cria a estrutura head <-> list pra cada lista + o lixo de memória vira uma lista com a estrutura necessária: + *prepara a cabeça da lista; + *prepara a cauda da lista; + *prepara os ponteiross internos. +*/ void list_init (struct list *list) { @@ -67,7 +73,10 @@ list_init (struct list *list) list->tail.next = NULL; } -/* Returns the beginning of LIST. */ +/* RETORNA O PRIMEIRO ELEMENTO DA LISTA + após o cabeçalho, retorna o primeiro elemento real da lista + +*/ struct list_elem * list_begin (struct list *list) { @@ -75,7 +84,9 @@ list_begin (struct list *list) return list->head.next; } -/* Returns the element after ELEM in its list. If ELEM is the +/* PRÓXIMO elemento da lista -> retorna o elemento seguinte + dá erro se o elemento for a cauda, já que o próximo é nulo. +Returns the element after ELEM in its list. If ELEM is the last element in its list, returns the list tail. Results are undefined if ELEM is itself a list tail. */ struct list_elem * @@ -85,7 +96,7 @@ list_next (struct list_elem *elem) return elem->next; } -/* Returns LIST's tail. +/* retorna TAIL list_end() is often used in iterating through a list from front to back. See the big comment at the top of list.h for @@ -162,16 +173,34 @@ list_tail (struct list *list) return &list->tail; } -/* Inserts ELEM just before BEFORE, which may be either an - interior element or a tail. The latter case is equivalent to - list_push_back(). */ +/* INSERE ELEM antes de before + supondo head <-> A <-> B <-> tail, para inserir X antes de B, + 4 ponteiros ajustados + before é um ponteiro para um list_elem que já está numa lista (ou o tail) + before indica a posição onde se deseja inserir o novo elemento + considerando-se que o elemento virá antes de before. + + before = B e elem = X + antes da inserção, os ponteiros são + pra A: + prev -> head + next -> B + pra B: + prev -> A + next -> tail + + como before = B, before->prev = A + assim, ao inserir X, teremos elem->prev = A (before->prev) + e elem->next igual ao B (before) + before->prev->next = A->next = x (elem) +*/ void -list_insert (struct list_elem *before, struct list_elem *elem) +list_insert (struct list_elem *before, struct list_elem *elem) //recebe um ponteiro e uma lista { ASSERT (is_interior (before) || is_tail (before)); ASSERT (elem != NULL); - elem->prev = before->prev; + elem->prev = before->prev; elem->next = before; before->prev->next = elem; before->prev = elem; From bd718a4dcb226b4e7b5f1983f6fc6c5845022b3c Mon Sep 17 00:00:00 2001 From: mgabimedeiros Date: Fri, 22 May 2026 18:00:18 -0300 Subject: [PATCH 03/11] Implementa Advanced Scheduler (MLFQS) - fixed_point, nice, recent_cpu, load_avg --- src/devices/timer.c | 14 ++++++++++- src/threads/fixed_point.h | 30 ++++++++++++++++++++++ src/threads/thread.c | 53 ++++++++++++++++++++++++++++++++------- src/threads/thread.h | 9 +++++++ 4 files changed, 96 insertions(+), 10 deletions(-) create mode 100644 src/threads/fixed_point.h diff --git a/src/devices/timer.c b/src/devices/timer.c index 85a3305..d80d340 100755 --- a/src/devices/timer.c +++ b/src/devices/timer.c @@ -166,13 +166,25 @@ timer_print_stats (void) printf ("Timer: %"PRId64" ticks\n", timer_ticks ()); } -/* Timer interrupt handler. */ +/* Timer interrupt handler. - alterada para as atualizações do advenced scheduler*/ static void timer_interrupt (struct intr_frame *args UNUSED) { ticks++; thread_tick (); thread_wake_up(timer_ticks()); + if (thread_mlfqs){ + mlfqs_increment_recent_cpu(); + if (ticks%TIMER_FREQ == 0){ + mlfqs_recalc_load_avg(); + mlfqs_recalc_all_recent_cpu(); + thread_foreach(mlfqs_recalc_priority, NULL); + } + if (ticks%4==0){ + thread_foreach(mlfqs_recalc_priority, NULL); + intr_yield_on_return(); /*fazer reordenação de threads de acordo com a prioridade atualizada*/ + } + } } /* Returns true if LOOPS iterations waits for more than one timer diff --git a/src/threads/fixed_point.h b/src/threads/fixed_point.h new file mode 100644 index 0000000..f4af88e --- /dev/null +++ b/src/threads/fixed_point.h @@ -0,0 +1,30 @@ +#ifndef THREADS_FIXED_POINT_H +#define THREADS_FIXED_POINT_H + +typedef int fixed_point; + +#define F (1<<14) /*escala 17.14 -- para realizar operações de priority do advenced scheduler*/ + +/* Converte inteiro em ponto fixo*/ +#define INT_FP(n) ((n)*F) + +/* Converte ponto fixo em inteiro*/ +#define FP_INT(x) ((x)/F) + +/* Converte ponto fixo em inteiro arredondando*/ +#define FP_INT_ROUND(x) ((x)>=0?((x)+F/2)/F:((x)-F/2)/F) + +/* Adição e subtração */ +#define FP_ADD(x, y) ((x) + (y)) //soma dois fixed_point +#define FP_SUB(x, y) ((x) - (y)) +#define FP_ADD_INT(x, n) ((x) + (n) * F) //soma um fixed_point com um inteiro +#define FP_SUB_INT(x, n) ((x) - (n) * F) + +/* Multiplicação e divisão */ +#define FP_MUL(x, y) ((fixed_point)(((int64_t)(x)) * (y) / F)) +#define FP_DIV(x, y) ((fixed_point)(((int64_t)(x)) * F / (y))) +#define FP_MUL_INT(x, n) ((x) * (n)) +#define FP_DIV_INT(x, n) ((x) / (n)) + + +#endif \ No newline at end of file diff --git a/src/threads/thread.c b/src/threads/thread.c index c3b2ed3..adcc4dd 100755 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -41,6 +41,9 @@ static struct thread *initial_thread; /* Lock used by allocate_tid(). */ static struct lock tid_lock; +/*declaração do load_avg*/ +static fixed_point load_avg; + /* Stack frame for kernel_thread(). */ struct kernel_thread_frame { @@ -165,6 +168,7 @@ thread_init (void) init_thread (initial_thread, "main", PRI_DEFAULT); initial_thread->status = THREAD_RUNNING; initial_thread->tid = allocate_tid (); + load_avg = 0; } /* Starts preemptive thread scheduling by enabling interrupts. @@ -265,6 +269,10 @@ thread_create (const char *name, int priority, sf->eip = switch_entry; sf->ebp = 0; + /*inicialização do nice e recent_cpu - ambos começam zerados*/ + t->nice = 0; + t->recent_cpu = 0; + /* Add to run queue. */ thread_unblock (t); @@ -414,35 +422,62 @@ thread_get_priority (void) /* Sets the current thread's nice value to NICE. */ void -thread_set_nice (int nice UNUSED) -{ - /* Not yet implemented. */ +thread_set_nice (int nice) +{ + thread_current()->nice = nice; /*seta a thread atual e atualiza o nice*/ + mlfqs_recalc_priority(thread_current(), NULL); } /* Returns the current thread's nice value. */ int thread_get_nice (void) { - /* Not yet implemented. */ - return 0; + return thread_current()->nice; } /* Returns 100 times the system load average. */ int thread_get_load_avg (void) { - /* Not yet implemented. */ - return 0; + return FP_INT_ROUND(FP_MUL_INT(load_avg,100)); } /* Returns 100 times the current thread's recent_cpu value. */ int thread_get_recent_cpu (void) { - /* Not yet implemented. */ - return 0; + return FP_INT_ROUND(FP_MUL_INT(thread_current()->recent_cpu,100)); } +/*criação das funções mlfqs para realização dos calculos e atualizações por clock*/ +void mlfqs_increment_recent_cpu() +{ + thread_current()->recent_cpu = FP_ADD_INT(thread_current()->recent_cpu,1); +} + +void mlfqs_recalc_priority(struct thread *t, void* aux UNUSED) +{ + t->priority = FP_INT_ROUND(FP_SUB_INT(FP_SUB_INT(INT_FP(PRI_MAX),FP_DIV_INT(t->recent_cpu,4)),((t->nice)*2))); + /*manter a prioridade no limite exigido do PintOS*/ + if (t->priority > PRI_MAX) t->priority = PRI_MAX; + if (t->priority < PRI_MIN) t->priority = PRI_MIN; +} + +void mlfqs_recalc_load_avg() +{ + int ready_threads = list_size(&ready_list) + (thread_current()!=idle_thread ? 1:0); + load_avg = FP_ADD(FP_MUL(FP_DIV_INT(INT_FP(59), 60),load_avg),FP_MUL_INT(FP_DIV_INT(INT_FP(1), 60),ready_threads)); +} + +void recalc_recent_cpu(struct thread *t, void *aux UNUSED) +{ + t->recent_cpu = FP_ADD_INT(FP_MUL(FP_DIV(FP_MUL_INT(load_avg,2),FP_ADD_INT(FP_MUL_INT(load_avg,2),1)),t->recent_cpu),t->nice); +} + +void mlfqs_recalc_all_recent_cpu() +{ + thread_foreach(recalc_recent_cpu, NULL); //thread_foreach faz um for para percorrer cada thread +} /* Idle thread. Executes when no other thread is ready to run. The idle thread is initially put on the ready list by diff --git a/src/threads/thread.h b/src/threads/thread.h index c0e7b41..41c2054 100755 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -4,6 +4,7 @@ #include #include #include +#include "threads/fixed_point.h" /* States in a thread's life cycle. */ enum thread_status @@ -88,6 +89,8 @@ struct thread char name[16]; /* Name (for debugging purposes). */ uint8_t *stack; /* Saved stack pointer. */ int priority; /* Priority. */ + int nice; /*valor de "gentileza" da thread*/ + fixed_point recent_cpu; /*tempo de CPU usado recentemente pela thread*/ struct list_elem allelem; /* List element for all threads list. */ struct list_elem sleep_elem; /* List element para a lista bloqueada */ int64_t wake_up_tick; /* O tempo que a thread deve estar dormindo*/ @@ -140,4 +143,10 @@ void thread_set_nice (int); int thread_get_recent_cpu (void); int thread_get_load_avg (void); +void mlfqs_increment_recent_cpu(void); +void mlfqs_recalc_priority(struct thread *t, void *aux UNUSED); +void mlfqs_recalc_load_avg(void); +void recalc_recent_cpu(struct thread *t, void *aux); +void mlfqs_recalc_all_recent_cpu(void); + #endif /* threads/thread.h */ From 5b85bce2e1c1cf8b70d64b06b2b4e85d99cdf99b Mon Sep 17 00:00:00 2001 From: vThor Date: Sat, 23 May 2026 01:24:28 -0300 Subject: [PATCH 04/11] testes do nice funcionando --- src/devices/timer.c | 12 ------- src/threads/thread.c | 74 +++++++++++++++++++++++++++++++++++++++++--- src/threads/thread.h | 1 + 3 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/devices/timer.c b/src/devices/timer.c index d80d340..52db8b0 100755 --- a/src/devices/timer.c +++ b/src/devices/timer.c @@ -173,18 +173,6 @@ timer_interrupt (struct intr_frame *args UNUSED) ticks++; thread_tick (); thread_wake_up(timer_ticks()); - if (thread_mlfqs){ - mlfqs_increment_recent_cpu(); - if (ticks%TIMER_FREQ == 0){ - mlfqs_recalc_load_avg(); - mlfqs_recalc_all_recent_cpu(); - thread_foreach(mlfqs_recalc_priority, NULL); - } - if (ticks%4==0){ - thread_foreach(mlfqs_recalc_priority, NULL); - intr_yield_on_return(); /*fazer reordenação de threads de acordo com a prioridade atualizada*/ - } - } } /* Returns true if LOOPS iterations waits for more than one timer diff --git a/src/threads/thread.c b/src/threads/thread.c index adcc4dd..2fc2bb0 100755 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -11,6 +11,7 @@ #include "threads/switch.h" #include "threads/synch.h" #include "threads/vaddr.h" +#include "devices/timer.h" #ifdef USERPROG #include "userprog/process.h" #endif @@ -78,6 +79,41 @@ static void schedule (void); void thread_schedule_tail (struct thread *prev); static tid_t allocate_tid (void); +/*função que compara a prioridade das threads*/ +bool thread_compare_priority (const struct list_elem *a, const struct list_elem *b, void *aux UNUSED) +{ + struct thread *thread_a = list_entry (a, struct thread, elem); + struct thread *thread_b = list_entry (b, struct thread, elem); + + return thread_a->priority > thread_b->priority; +} + +/*função que checa se é nececessário mudar a thread atual baseado na prioridade*/ +void thread_mlfqs_yield(void) +{ + enum intr_level old_level = intr_disable (); //disabilida interrupções para usar a lista + if (!list_empty(&ready_list)) + { + struct thread *highest = list_entry(list_front(&ready_list), struct thread, elem); + if (thread_current()->priority < highest->priority) + { + if (intr_context ()) + { + intr_set_level(old_level); + intr_yield_on_return (); + return; + } + else + { + intr_set_level(old_level); + thread_yield (); + return; + } + } + } + intr_set_level(old_level); +} + bool wake_up_order(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED) { @@ -205,6 +241,23 @@ thread_tick (void) else kernel_ticks++; + if (thread_mlfqs){ + + if (t != idle_thread) mlfqs_increment_recent_cpu(); + + int64_t ticks = timer_ticks (); + + if (ticks%TIMER_FREQ == 0){ + mlfqs_recalc_load_avg(); + mlfqs_recalc_all_recent_cpu(); + } + if (ticks%4==0){ + thread_foreach(mlfqs_recalc_priority, NULL); + list_sort (&ready_list, thread_compare_priority, NULL); + thread_mlfqs_yield(); /*fazer reordenação de threads de acordo com a prioridade atualizada*/ + } + } + /* Enforce preemption. */ if (++thread_ticks >= TIME_SLICE) intr_yield_on_return (); @@ -312,7 +365,7 @@ thread_unblock (struct thread *t) old_level = intr_disable (); ASSERT (t->status == THREAD_BLOCKED); - list_push_back (&ready_list, &t->elem); + list_insert_ordered (&ready_list, &t->elem, thread_compare_priority, NULL); //mudança para adicionar o elemento na lista já ordenado t->status = THREAD_READY; intr_set_level (old_level); } @@ -383,7 +436,7 @@ thread_yield (void) old_level = intr_disable (); if (cur != idle_thread) - list_push_back (&ready_list, &cur->elem); + list_insert_ordered (&ready_list, &cur->elem, thread_compare_priority, NULL); //mudança para adicionar o elemento na lista já ordenado cur->status = THREAD_READY; schedule (); intr_set_level (old_level); @@ -425,7 +478,9 @@ void thread_set_nice (int nice) { thread_current()->nice = nice; /*seta a thread atual e atualiza o nice*/ + /*refaz a ordem após atualizar o nice*/ mlfqs_recalc_priority(thread_current(), NULL); + thread_mlfqs_yield(); } /* Returns the current thread's nice value. */ @@ -457,12 +512,23 @@ void mlfqs_increment_recent_cpu() void mlfqs_recalc_priority(struct thread *t, void* aux UNUSED) { - t->priority = FP_INT_ROUND(FP_SUB_INT(FP_SUB_INT(INT_FP(PRI_MAX),FP_DIV_INT(t->recent_cpu,4)),((t->nice)*2))); - /*manter a prioridade no limite exigido do PintOS*/ + if (t == idle_thread) + return; + + // Formula: priority = PRI_MAX - (recent_cpu / 4) - (nice * 2) + fixed_point cpu_div_4 = FP_DIV_INT (t->recent_cpu, 4); + fixed_point sub1 = FP_SUB (INT_FP (PRI_MAX), cpu_div_4); + fixed_point sub2 = FP_SUB_INT (sub1, t->nice * 2); + + t->priority = FP_INT_ROUND (sub2); + + /* manter a prioridade no limite exigido do PintOS */ if (t->priority > PRI_MAX) t->priority = PRI_MAX; if (t->priority < PRI_MIN) t->priority = PRI_MIN; } + + void mlfqs_recalc_load_avg() { int ready_threads = list_size(&ready_list) + (thread_current()!=idle_thread ? 1:0); diff --git a/src/threads/thread.h b/src/threads/thread.h index 41c2054..2d2605b 100755 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -110,6 +110,7 @@ struct thread If true, use multi-level feedback queue scheduler. Controlled by kernel command-line option "-o mlfqs". */ extern bool thread_mlfqs; +void thread_mlfqs_yield(void); void thread_sleep (int64_t wake_up_time); void thread_wake_up (int64_t ticks); void thread_init (void); From c056b5ab262b7d51f319113fab88877d150ad75e Mon Sep 17 00:00:00 2001 From: mgabimedeiros Date: Sat, 23 May 2026 10:11:20 -0300 Subject: [PATCH 05/11] =?UTF-8?q?corre=C3=A7=C3=A3o=20-=20teste=20mlfqs-bl?= =?UTF-8?q?ock=20pass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/devices/timer.c | 2 ++ src/threads/thread.c | 43 ++++++++++++++++++++++++++++++++++++------- src/threads/thread.h | 1 + 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/src/devices/timer.c b/src/devices/timer.c index d80d340..5037714 100755 --- a/src/devices/timer.c +++ b/src/devices/timer.c @@ -179,9 +179,11 @@ timer_interrupt (struct intr_frame *args UNUSED) mlfqs_recalc_load_avg(); mlfqs_recalc_all_recent_cpu(); thread_foreach(mlfqs_recalc_priority, NULL); + mlfqs_sort_ready_list(); } if (ticks%4==0){ thread_foreach(mlfqs_recalc_priority, NULL); + mlfqs_sort_ready_list(); intr_yield_on_return(); /*fazer reordenação de threads de acordo com a prioridade atualizada*/ } } diff --git a/src/threads/thread.c b/src/threads/thread.c index adcc4dd..f078178 100755 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -44,6 +44,9 @@ static struct lock tid_lock; /*declaração do load_avg*/ static fixed_point load_avg; +/*Função para organizar threads por prioridade*/ +static bool insert_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED); + /* Stack frame for kernel_thread(). */ struct kernel_thread_frame { @@ -269,9 +272,9 @@ thread_create (const char *name, int priority, sf->eip = switch_entry; sf->ebp = 0; - /*inicialização do nice e recent_cpu - ambos começam zerados*/ - t->nice = 0; - t->recent_cpu = 0; + /*inicialização do nice e recent_cpu - ambos herdam valor*/ + t->nice = thread_current()->nice; +t->recent_cpu = thread_current()->recent_cpu; /* Add to run queue. */ thread_unblock (t); @@ -312,7 +315,8 @@ thread_unblock (struct thread *t) old_level = intr_disable (); ASSERT (t->status == THREAD_BLOCKED); - list_push_back (&ready_list, &t->elem); + //list_push_back (&ready_list, &t->elem); + list_insert_ordered(&ready_list, &t->elem, insert_priority, NULL); t->status = THREAD_READY; intr_set_level (old_level); } @@ -383,7 +387,8 @@ thread_yield (void) old_level = intr_disable (); if (cur != idle_thread) - list_push_back (&ready_list, &cur->elem); + //list_push_back (&ready_list, &cur->elem); + list_insert_ordered(&ready_list, &cur->elem, insert_priority, NULL); cur->status = THREAD_READY; schedule (); intr_set_level (old_level); @@ -452,12 +457,13 @@ thread_get_recent_cpu (void) /*criação das funções mlfqs para realização dos calculos e atualizações por clock*/ void mlfqs_increment_recent_cpu() { - thread_current()->recent_cpu = FP_ADD_INT(thread_current()->recent_cpu,1); + if (thread_current() != idle_thread) /*checa tem thread em execuçaõ*/ + thread_current()->recent_cpu = FP_ADD_INT(thread_current()->recent_cpu, 1); } void mlfqs_recalc_priority(struct thread *t, void* aux UNUSED) { - t->priority = FP_INT_ROUND(FP_SUB_INT(FP_SUB_INT(INT_FP(PRI_MAX),FP_DIV_INT(t->recent_cpu,4)),((t->nice)*2))); + t->priority = FP_INT(FP_SUB_INT(FP_SUB_INT(INT_FP(PRI_MAX),FP_DIV_INT(t->recent_cpu,4)),((t->nice)*2))); /*manter a prioridade no limite exigido do PintOS*/ if (t->priority > PRI_MAX) t->priority = PRI_MAX; if (t->priority < PRI_MIN) t->priority = PRI_MIN; @@ -478,6 +484,29 @@ void mlfqs_recalc_all_recent_cpu() { thread_foreach(recalc_recent_cpu, NULL); //thread_foreach faz um for para percorrer cada thread } + +void mlfqs_sort_ready_list(void) +{ + list_sort(&ready_list, insert_priority, NULL); +} + +/*função para ordenar por ordem de prioridade*/ +bool insert_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED) +{ + struct thread *thread_a = list_entry(a, struct thread, elem); + struct thread *thread_b = list_entry(b, struct thread, elem); + + if (thread_a->priority == thread_b->priority) + { + return false; //manter igual + } + + // Caso contrário, quem tem a maior prioridade vem na frente + return thread_a->priority > thread_b->priority; +} + + + /* Idle thread. Executes when no other thread is ready to run. The idle thread is initially put on the ready list by diff --git a/src/threads/thread.h b/src/threads/thread.h index 41c2054..348d51f 100755 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -148,5 +148,6 @@ void mlfqs_recalc_priority(struct thread *t, void *aux UNUSED); void mlfqs_recalc_load_avg(void); void recalc_recent_cpu(struct thread *t, void *aux); void mlfqs_recalc_all_recent_cpu(void); +void mlfqs_sort_ready_list(void); #endif /* threads/thread.h */ From 87deda0667a0f9f2ceff675f505ca5d9a1227143 Mon Sep 17 00:00:00 2001 From: vThor Date: Sat, 23 May 2026 11:18:48 -0300 Subject: [PATCH 06/11] test mlfqs funcionando --- src/threads/synch.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/threads/synch.c b/src/threads/synch.c index 317c68a..0a2da42 100755 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -233,6 +233,8 @@ lock_release (struct lock *lock) lock->holder = NULL; sema_up (&lock->semaphore); + + if (!intr_context()) thread_yield(); //cede CPU se thread de maior prioridade for desbloqueada } /* Returns true if the current thread holds LOCK, false From 7753c9d6b1f4ecf0711d9562c9d921b7a310e5f2 Mon Sep 17 00:00:00 2001 From: Miriam Gonzaga Date: Sat, 23 May 2026 11:40:35 -0300 Subject: [PATCH 07/11] modificacoes de comentarios e timer_sleep Updated comments for clarity and added checks for ticks in timer_sleep function. --- src/devices/timer.c | 60 ++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/src/devices/timer.c b/src/devices/timer.c index 52db8b0..a51db5a 100755 --- a/src/devices/timer.c +++ b/src/devices/timer.c @@ -1,3 +1,10 @@ +/* + manipular principalmente as interrupções periódicas + conta os ticks (variavel global) + chama thread_tick a cada interrupcao + funcoes de delay (sleep, msleep, etcc) +*/ + #include "devices/timer.h" #include #include @@ -8,8 +15,6 @@ #include "threads/synch.h" #include "threads/thread.h" -/* See [8254] for hardware details of the 8254 timer chip. */ - #if TIMER_FREQ < 19 #error 8254 timer requires TIMER_FREQ >= 19 #endif @@ -17,8 +22,7 @@ #error TIMER_FREQ <= 1000 recommended #endif -/* Number of timer ticks since OS booted. */ -static int64_t ticks; +static int64_t ticks; //variavel global /* Number of loops per timer tick. Initialized by timer_calibrate(). */ @@ -66,34 +70,42 @@ timer_calibrate (void) printf ("%'"PRIu64" loops/s.\n", (uint64_t) loops_per_tick * TIMER_FREQ); } -/* Returns the number of timer ticks since the OS booted. */ +/* retorna qnts ticks passarm desde o boot */ int64_t timer_ticks (void) { - enum intr_level old_level = intr_disable (); - int64_t t = ticks; - intr_set_level (old_level); + enum intr_level old_level = intr_disable (); //desliga interrupcoes + int64_t t = ticks; // lê os ticks + intr_set_level (old_level); // retorna as interrupçoes pro estado inicial return t; } -/* Returns the number of timer ticks elapsed since THEN, which - should be a value once returned by timer_ticks(). */ +/* FUNÇÃO PRA CALCULAR QUANTOS TICKS PASSARAM DESDE UM EVENTO ESPECÍFICO + then é o valor de ticks no instante que o evento estava acontecendo, + usando timer_ticks pega o valor do tick atual e retorna a diferença + ou seja, quantos ticks se passaram desde que o evento ocorreu */ int64_t timer_elapsed (int64_t then) { - return timer_ticks () - then; + return timer_ticks () - then; // calcula e retorna a diferença } -/* Sleeps for approximately TICKS timer ticks. Interrupts must - be turned on. */ +/* dorme por tantos TICKS de tempo + incialmente implementado com espera ocupada -> um loop que desperdiçava cpu + modificações na implementação: bloquear a thread até o tempo passar + checar se o tempo foi atigindo e trocar o estado da thread (blocked pra ready) + usar as interrupções pra acordar as threads que já esperaram o tempo suficiente */ void timer_sleep (int64_t ticks) { - int64_t start = timer_ticks (); - if (timer_elapsed (start) < ticks) - { - thread_sleep (start + ticks); - } + if (ticks <= 0){ //condicao de ticks >0 pra executar a funcao + return; + } + enum intr_level old_level = intr_disable(); + int64_t sleep_ticks = (timer_ticks() + ticks); //qntd de ticks que a thread vai ficar dormindo + intr_set_level(old_level); + + thread_sleep(sleep_ticks); //coloca a thread pra dormir } /* Sleeps for approximately MS milliseconds. Interrupts must be @@ -166,13 +178,17 @@ timer_print_stats (void) printf ("Timer: %"PRId64" ticks\n", timer_ticks ()); } -/* Timer interrupt handler. - alterada para as atualizações do advenced scheduler*/ +/* CPU INTERROMPE A THREAD ATUAL + entra no handler de interrupcao + verifica threads dormindo + acordar threads + thread_unblock */ static void timer_interrupt (struct intr_frame *args UNUSED) { - ticks++; - thread_tick (); - thread_wake_up(timer_ticks()); + ticks++; //incrementa a variavel global de ticks + thread_wake_up(timer_ticks()); // acorda as threads que devem acordar nesse tick + thread_tick (); // atualiza (faz yield -> schedule) "chama o schedule" } /* Returns true if LOOPS iterations waits for more than one timer From 2b00f64af5fd99fbcffd124227cd32c70ca078d5 Mon Sep 17 00:00:00 2001 From: Miriam Gonzaga Date: Sat, 23 May 2026 11:42:56 -0300 Subject: [PATCH 08/11] add comentarios sobre a biblioteca pra ponto fixo --- src/threads/fixed_point.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/threads/fixed_point.h b/src/threads/fixed_point.h index f4af88e..809eb0c 100644 --- a/src/threads/fixed_point.h +++ b/src/threads/fixed_point.h @@ -1,19 +1,25 @@ +/* biblioteca aritmetica pra ponto fixo que o mlfq precisa + pintOS não tem suporte a float dentro do kernel, então essa bib + serve pra realizar os cálculos envolvendo */ + #ifndef THREADS_FIXED_POINT_H #define THREADS_FIXED_POINT_H -typedef int fixed_point; +typedef int fixed_point; //alias +//17 bits pra parte inteira e 14 bits pra parte fracionária #define F (1<<14) /*escala 17.14 -- para realizar operações de priority do advenced scheduler*/ -/* Converte inteiro em ponto fixo*/ +//conversao de int pra ponto fixo #define INT_FP(n) ((n)*F) -/* Converte ponto fixo em inteiro*/ +//conversao de ponto fixo pra inteiro (truncado) #define FP_INT(x) ((x)/F) -/* Converte ponto fixo em inteiro arredondando*/ +//conversao de ponto fixo pra inteiro (arredondado) #define FP_INT_ROUND(x) ((x)>=0?((x)+F/2)/F:((x)-F/2)/F) +//OPERACOES ARITMETICAS /* Adição e subtração */ #define FP_ADD(x, y) ((x) + (y)) //soma dois fixed_point #define FP_SUB(x, y) ((x) - (y)) @@ -27,4 +33,4 @@ typedef int fixed_point; #define FP_DIV_INT(x, n) ((x) / (n)) -#endif \ No newline at end of file +#endif From 691c1bcfb714922e154cb873a469290f62478b14 Mon Sep 17 00:00:00 2001 From: Miriam Gonzaga Date: Sat, 23 May 2026 12:54:01 -0300 Subject: [PATCH 09/11] mais comentarios e explicacoes da estrutura Refactor thread management code to improve clarity and organization. Added comments in Portuguese for better understanding of thread states and functions. --- src/threads/thread.c | 559 +++++++++++++++++++------------------------ 1 file changed, 241 insertions(+), 318 deletions(-) diff --git a/src/threads/thread.c b/src/threads/thread.c index dcebe50..4523083 100755 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -16,39 +16,33 @@ #include "userprog/process.h" #endif -/* Random value for struct thread's `magic' member. - Used to detect stack overflow. See the big comment at the top - of thread.h for details. */ #define THREAD_MAGIC 0xcd6abf4b #define A 55 -/* List of processes in THREAD_READY state, that is, processes - that are ready to run but not actually running. */ -static struct list ready_list; +/* cada thread tem 4 estados possíveis: + * RUNNING, READY, BLOCKED, DYING -/* Lista das Threads bloqueadas */ -static struct list sleep_list; - -/* List of all processes. Processes are added to this list - when they are first scheduled and removed when they exit. */ -static struct list all_list; - -/* Idle thread. */ -static struct thread *idle_thread; - -/* Initial thread, the thread running init.c:main(). */ -static struct thread *initial_thread; - -/* Lock used by allocate_tid(). */ -static struct lock tid_lock; - -/*declaração do load_avg*/ -static fixed_point load_avg; + VARIÁVEIS GLOBAIS: + essas variáveis só ficam visíveis dentro de thread.c, + para que não possam ser manipuladas por outros arquivos, + para acessar essas variáveis, outros arquivos usam funções + + isso significa que as variáveis existem globalmente durante toda a execução, + mas apenas o código dentro de thread.c pode acessá-las pelo nome + outros arquivos são obrigados a usar as funções fornecidas por thread.c, + o que protege a consistência das estruturas internas do escalonador. + + */ +static struct list sleep_list; // lista de threads bloqueadas (dormindo) +static struct list ready_list; // lista de threads prontas +static struct list all_list; // lista de todas as threads +static struct thread *idle_thread; // thread ociosa (só roda quando a ready_list está vazia) +static struct thread *initial_thread; //thread principal (representa o código que já rodava antes do sistema de threads) -> guarda ela numa struct +static struct lock tid_lock; // garantir que os ids das threads é único +static fixed_point load_avg; //declarar load_avg -/*Função para organizar threads por prioridade*/ static bool insert_priority(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED); -/* Stack frame for kernel_thread(). */ struct kernel_thread_frame { void *eip; /* Return address. */ @@ -56,14 +50,12 @@ struct kernel_thread_frame void *aux; /* Auxiliary data for function. */ }; -/* Statistics. */ static long long idle_ticks; /* # of timer ticks spent idle. */ static long long kernel_ticks; /* # of timer ticks in kernel threads. */ static long long user_ticks; /* # of timer ticks in user programs. */ -/* Scheduling. */ -#define TIME_SLICE 4 /* # of timer ticks to give each thread. */ -static unsigned thread_ticks; /* # of timer ticks since last yield. */ +#define TIME_SLICE 4 +static unsigned thread_ticks; /* If false (default), use round-robin scheduler. If true, use multi-level feedback queue scheduler. @@ -71,7 +63,6 @@ static unsigned thread_ticks; /* # of timer ticks since last yield. */ bool thread_mlfqs; static void kernel_thread (thread_func *, void *aux); - static void idle (void *aux UNUSED); static struct thread *running_thread (void); static struct thread *next_thread_to_run (void); @@ -82,7 +73,7 @@ static void schedule (void); void thread_schedule_tail (struct thread *prev); static tid_t allocate_tid (void); -/*função que compara a prioridade das threads*/ +//funcao que compara a prioridade das threads: bool thread_compare_priority (const struct list_elem *a, const struct list_elem *b, void *aux UNUSED) { struct thread *thread_a = list_entry (a, struct thread, elem); @@ -91,7 +82,7 @@ bool thread_compare_priority (const struct list_elem *a, const struct list_elem return thread_a->priority > thread_b->priority; } -/*função que checa se é nececessário mudar a thread atual baseado na prioridade*/ +/*função que checa se é nececessário mudar a thread atual com base na prioridade*/ void thread_mlfqs_yield(void) { enum intr_level old_level = intr_disable (); //disabilida interrupções para usar a lista @@ -117,123 +108,111 @@ void thread_mlfqs_yield(void) intr_set_level(old_level); } - -bool wake_up_order(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED) -{ +//funcao auxiliar (usada no LESS de list_insert_ordered quando chamada na função) +bool wake_up_order(const struct list_elem *a, const struct list_elem *b, void *aux UNUSED){ struct thread *thread_a = list_entry(a, struct thread, sleep_elem); struct thread *thread_b = list_entry(b, struct thread, sleep_elem); - if (thread_a->wake_up_tick == thread_b->wake_up_tick) - { - // Se o tempo for igual, desempata pela maior prioridade + // se o tempo for igual, desempata pela maior prioridade + if (thread_a->wake_up_tick == thread_b->wake_up_tick){ return thread_a->priority > thread_b->priority; } - // Caso contrário, quem tem o menor tempo vem na frente + // caso contrário, quem tem o menor tempo vem na frente return thread_a->wake_up_tick < thread_b->wake_up_tick; } -/* - Coloca a Thread pra dormir pelo tempo determinado - */ -void thread_sleep (int64_t wake_up_tick) -{ - //pego o estado de interrupição atual - enum intr_level old_level; - - //disabilito interrupção - old_level = intr_disable (); - - //pego a thread atual - struct thread *t = thread_current (); - - //adiciono o tempo que a thread precisa - t->wake_up_tick = wake_up_tick; +/* coloca a Thread pra dormir pelo tempo determinado */ +void thread_sleep (int64_t wake_up_tick){ + enum intr_level old_level; //pega estado de interrupcao atual + old_level = intr_disable (); //disabilito interrupção - //adicono a thread na lista de thread bloqueadas - list_insert_ordered (&sleep_list, &t->sleep_elem, wake_up_order, NULL); + struct thread *t = thread_current (); //pego a thread atual + t->wake_up_tick = wake_up_tick; //adiciono o tempo que a thread precisa + list_insert_ordered (&sleep_list, &t->sleep_elem, wake_up_order, NULL); //adicono a thread na lista de thread bloqueadas - //bloqueio a thread - thread_block(); - - //volto para a interrupção que estava anteriormente - intr_set_level (old_level); + thread_block(); //bloqueio a thread + intr_set_level (old_level); //volto para a interrupção que estava anteriormente } +void thread_wake_up (int64_t ticks){ + enum intr_level old_level = intr_disable(); //desligar interrupcoes -void thread_wake_up (int64_t ticks) -{ - while (!list_empty(&sleep_list)) + while (!list_empty(&sleep_list)) //se a lista de threads bloqueadas NÃO estiver vazia { - struct thread *t = list_entry(list_begin(&sleep_list), struct thread, sleep_elem); - if (t->wake_up_tick > ticks) - { - break; + struct thread *t = list_entry(list_begin(&sleep_list), struct thread, sleep_elem); // pega a thread + if (t->wake_up_tick > ticks){// se ainda nao atingiu a qtd de ticks necessaria + break; // permanece dormindo } list_pop_front(&sleep_list); thread_unblock(t); } - -} - + + intr_set_level (old_level); //volto para a interrupção que estava anteriormente -/* Initializes the threading system by transforming the code - that's currently running into a thread. This can't work in - general and it is possible in this case only because loader.S - was careful to put the bottom of the stack at a page boundary. +} - Also initializes the run queue and the tid lock. - After calling this function, be sure to initialize the page - allocator before trying to create any threads with - thread_create(). +/* thread_init() e thread_start() vão inicializar o sistema de threads + quando o sistema pintos inicia, tem-se: + main -> thread_init() -> thread_start() -> scheduler comeca a funcionar + novas threads podem ser criadas - It is not safe to call thread_current() until this function - finishes. */ + quando o kernel começa a executar, já existe uma pilha (stack) sendo usada na cpu, + mas não existe struct thread, ready_list e scheduler configurados +*/ void thread_init (void) -{ +{ // primeira parte de inicialização do sistema: + //cria o sistema de threads e transforma a main numa thread ASSERT (intr_get_level () == INTR_OFF); - lock_init (&tid_lock); - list_init (&ready_list); - list_init (&sleep_list); + lock_init (&tid_lock); //inicializa estruturas globais (configurador de IDs e as listas (all e ready)) + + list_init(&sleep_list); // cria e inicializa as listas das threads + list_init (&ready_list); list_init (&all_list); - /* Set up a thread structure for the running thread. */ + /* pega a thread que já tá rodando + transforma o código que já está rodando numa thread + isto é, a main vira oficialmente initial_thread, + mas as interrupções ainda estão desligadas*/ initial_thread = running_thread (); - init_thread (initial_thread, "main", PRI_DEFAULT); + init_thread (initial_thread, "main", PRI_DEFAULT); initial_thread->status = THREAD_RUNNING; initial_thread->tid = allocate_tid (); - load_avg = 0; + + load_avg = 0; } -/* Starts preemptive thread scheduling by enabling interrupts. - Also creates the idle thread. */ +/* habilita interrupções e cria a idle_thread */ void thread_start (void) -{ - /* Create the idle thread. */ - struct semaphore idle_started; +{ // segunda parte de inicialização do sistema + struct semaphore idle_started; // cria idle_thread mas ela está bloqueada sema_init (&idle_started, 0); thread_create ("idle", PRI_MIN, idle, &idle_started); - /* Start preemptive thread scheduling. */ - intr_enable (); - - /* Wait for the idle thread to initialize idle_thread. */ - sema_down (&idle_started); + intr_enable (); // escalonamento preemptivo começa + // timer fica habilitado a gerar interrupções + sema_down (&idle_started); //espera idle_thread inicializar } -/* Called by the timer interrupt handler at each timer tick. - Thus, this function runs in an external interrupt context. */ +/* a cada tick, essa função é chamada pelo timer interrupt + essa funcao possui um mecanismo de preempcao adiada + quando faz intr_yield_on_return(), não chama schedule, + ela marca uma flag pra que, quando a interrupcao terminar, + thread_yield seja chamada e depois o escalonador + isso acontece porque NÃO queremos + realizar trocas de contexto enquanto + uma interrupcao está sendo tratada + */ void thread_tick (void) { struct thread *t = thread_current (); - /* Update statistics. */ if (t == idle_thread) idle_ticks++; @@ -243,30 +222,26 @@ thread_tick (void) #endif else kernel_ticks++; - if (thread_mlfqs){ - - if (t != idle_thread) mlfqs_increment_recent_cpu(); - - int64_t ticks = timer_ticks (); - - if (ticks%TIMER_FREQ == 0){ - mlfqs_recalc_load_avg(); - mlfqs_recalc_all_recent_cpu(); - } - if (ticks%4==0){ - thread_foreach(mlfqs_recalc_priority, NULL); - list_sort (&ready_list, thread_compare_priority, NULL); - thread_mlfqs_yield(); /*fazer reordenação de threads de acordo com a prioridade atualizada*/ - } + + if (t != idle_thread) mlfqs_increment_recent_cpu(); + int64_t ticks = timer_ticks (); + + if (ticks%TIMER_FREQ == 0){ + mlfqs_recalc_load_avg(); + mlfqs_recalc_all_recent_cpu(); + } + if (ticks%4==0){ + thread_foreach(mlfqs_recalc_priority, NULL); + list_sort (&ready_list, thread_compare_priority, NULL); + thread_mlfqs_yield(); /*fazer reordenação de threads de acordo com a prioridade atualizada*/ + } } - - /* Enforce preemption. */ - if (++thread_ticks >= TIME_SLICE) - intr_yield_on_return (); + /* impoe a preempcao*/ + if (++thread_ticks >= TIME_SLICE) // se atingir a qtd de ticks, chama intr_yield_on_return + intr_yield_on_return (); //termine a interrupcao e faca um yield da thread atual } -/* Prints thread statistics. */ void thread_print_stats (void) { @@ -274,161 +249,156 @@ thread_print_stats (void) idle_ticks, kernel_ticks, user_ticks); } -/* Creates a new kernel thread named NAME with the given initial - PRIORITY, which executes FUNCTION passing AUX as the argument, - and adds it to the ready queue. Returns the thread identifier - for the new thread, or TID_ERROR if creation fails. - - If thread_start() has been called, then the new thread may be - scheduled before thread_create() returns. It could even exit - before thread_create() returns. Contrariwise, the original - thread may run for any amount of time before the new thread is - scheduled. Use a semaphore or some other form of - synchronization if you need to ensure ordering. +/* ao criar uma thread, precisa: + * alocar memória pra nova thread (4KB) + * criar e preencher struct da thread + * montar pilha (stack) + * colocar a thread na ready_list + depois o scheduler coloca a thread pra executar - The code provided sets the new thread's `priority' member to - PRIORITY, but no actual priority scheduling is implemented. - Priority scheduling is the goal of Problem 1-3. */ + no início da página fica a struct da thread e no final a pilha (stack) + +*/ tid_t thread_create (const char *name, int priority, thread_func *function, void *aux) { struct thread *t; - struct kernel_thread_frame *kf; + struct kernel_thread_frame *kf; struct switch_entry_frame *ef; struct switch_threads_frame *sf; tid_t tid; ASSERT (function != NULL); - /* Allocate thread. */ + /* aloca página de 4KB */ t = palloc_get_page (PAL_ZERO); - if (t == NULL) - return TID_ERROR; + if (t == NULL) // se não conseguir memória, + return TID_ERROR; //a criação falha - /* Initialize thread. */ - init_thread (t, name, priority); - tid = t->tid = allocate_tid (); + init_thread (t, name, priority); // inicia estrutura básica da thread (status, prioridade, ect) + tid = t->tid = allocate_tid (); //gera o id da thread - /* Stack frame for kernel_thread(). */ - kf = alloc_frame (t, sizeof *kf); + kf = alloc_frame (t, sizeof *kf); //configura a pilha (stack), que cresce pra baixo kf->eip = NULL; kf->function = function; kf->aux = aux; - /* Stack frame for switch_entry(). */ - ef = alloc_frame (t, sizeof *ef); + /* quando uma thread é criada, ela nunca executou antes + isso quer dizer que a tread não tem contexto, ñ tem end. de retorno, nem pilha + então o pintOS fabrica contexto na pilha, para que possa ser usada posteriormente, + na troca de contexto, é procedimento de inicialização pra evitar que a cpu execute + com lixo de memória + obs: para isso servem as seguintes structs: + (kernel_thread_frame, switch_entry_frame e switch_threads_frame) + são como pedacos de pilha + + */ + + ef = alloc_frame (t, sizeof *ef); // ajusta o contexto ef->eip = (void (*) (void)) kernel_thread; - /* Stack frame for switch_threads(). */ - sf = alloc_frame (t, sizeof *sf); - sf->eip = switch_entry; + // switch_threads() é a rotina assembly responsável por trocar contexto + sf = alloc_frame (t, sizeof *sf); //frame pra switch_threads() + sf->eip = switch_entry; sf->ebp = 0; - /*inicialização do nice e recent_cpu - ambos herdam valor*/ t->nice = thread_current()->nice; -t->recent_cpu = thread_current()->recent_cpu; + t->recent_cpu = thread_current()->recent_cpu; - /* Add to run queue. */ - thread_unblock (t); + thread_unblock (t); //torna a thread pronta pra executar - return tid; + return tid; //thread criada (com sucsseo) } -/* Puts the current thread to sleep. It will not be scheduled - again until awoken by thread_unblock(). - - This function must be called with interrupts turned off. It - is usually a better idea to use one of the synchronization - primitives in synch.h. */ +/* coloca a thread pra dormir (estado vira BLOCKED) + e a thread não pode ser escalonada, até que acorde novamente + essa função precisa das interrupções desligadas pra ser chamada + */ void thread_block (void) { - ASSERT (!intr_context ()); - ASSERT (intr_get_level () == INTR_OFF); - - thread_current ()->status = THREAD_BLOCKED; - schedule (); + ASSERT (!intr_context ()); // verificar se uma rotina de interrupção NÃO tá sendo executada + ASSERT (intr_get_level () == INTR_OFF); // verifica se as interrupções estão desligadas + //define o status da thread atual como BLOCKED + thread_current ()->status = THREAD_BLOCKED; + schedule (); //chama o escalonador pra escolher outra thread da ready_list } -/* Transitions a blocked thread T to the ready-to-run state. - This is an error if T is not blocked. (Use thread_yield() to - make the running thread ready.) - - This function does not preempt the running thread. This can - be important: if the caller had disabled interrupts itself, - it may expect that it can atomically unblock a thread and - update other data. */ +/* colocar a thread bloqueada na lista de threads prontas e + mudar o estado para READY (fica APTA a executar) + */ void thread_unblock (struct thread *t) { - enum intr_level old_level; + enum intr_level old_level; //guarda uma cópia do estado anterior das interrupcoes ASSERT (is_thread (t)); - - old_level = intr_disable (); + /* garantir que a operação seja "atômica" -> integridade da lista! + interrupcoes podem estar ON ou OFF, aqui, + queremos que não haja interrupcoes, pra garantir a integridade da lista, + então vamos salvar o estado atual (ON ou OFF) das interrupções, + executar a modificação na lista e depois retornar ao estado inicial + */ + old_level = intr_disable (); // retorna o antigo estado de interrupceos e depois desabilita interrupções ASSERT (t->status == THREAD_BLOCKED); list_insert_ordered (&ready_list, &t->elem, thread_compare_priority, NULL); //mudança para adicionar o elemento na lista já ordenado - t->status = THREAD_READY; - intr_set_level (old_level); + t->status = THREAD_READY; // atualiza status da thread pra READY + intr_set_level (old_level); // restaura o estado anterior de interrupçoes (ON ou OFF) } -/* Returns the name of the running thread. */ const char * thread_name (void) { - return thread_current ()->name; + return thread_current ()->name; /* retorna o NOME da thread que tá rodando */ } -/* Returns the running thread. - This is running_thread() plus a couple of sanity checks. - See the big comment at the top of thread.h for details. */ struct thread * thread_current (void) { struct thread *t = running_thread (); - - /* Make sure T is really a thread. - If either of these assertions fire, then your thread may - have overflowed its stack. Each thread has less than 4 kB - of stack, so a few big automatic arrays or moderate - recursion can cause stack overflow. */ - ASSERT (is_thread (t)); - ASSERT (t->status == THREAD_RUNNING); - return t; + ASSERT (is_thread (t)); // confere se realmente é uma thread + ASSERT (t->status == THREAD_RUNNING); //confere se está rodando + + return t; //retorna thread que está rodando } -/* Returns the running thread's tid. */ tid_t thread_tid (void) { - return thread_current ()->tid; + return thread_current ()->tid; //retorna o id da thread que tá rodando } -/* Deschedules the current thread and destroys it. Never - returns to the caller. */ +/* FINALIZAR A THREAD: + a thread já concluiu e deve ser eliminada do sistema, + mas ela não pode liberar sua memória sozinha + o processo de destruição é feito em duas partes: + 1. a thread atualiza o status pra DYING + 2. outra thread libera a memória dela depois da troca de contexto +*/ void thread_exit (void) -{ - ASSERT (!intr_context ()); +{ + // ESSA FUNCAO NÃO PODE SER CHAMADA DENTRO DE UMA INTERRUPCAO: + ASSERT (!intr_context ()); // verifica se as interrupções estão DESLIGADAS #ifdef USERPROG - process_exit (); + process_exit (); //fecha arquivos, destroi page tables, libera recursos #endif - - /* Remove thread from all threads list, set our status to dying, - and schedule another process. That process will destroy us - when it calls thread_schedule_tail(). */ - intr_disable (); - list_remove (&thread_current()->allelem); - thread_current ()->status = THREAD_DYING; - schedule (); + intr_disable (); //desliga interrupcoes (integridade das estruturas) + list_remove (&thread_current()->allelem); //remove a thread de todas as listas + thread_current ()->status = THREAD_DYING; // atualiza o status da thread + schedule (); // escolhe outra pra executar, troca de contexto NOT_REACHED (); } -/* Yields the CPU. The current thread is not put to sleep and - may be scheduled again immediately at the scheduler's whim. */ +/* FUNCAO QUE PERMITE 'ABRIR MAO' DA CPU VOLUNTARIAMENTE + a thread em execução simplesmente "cede" a cpu por um momento, + mas pode ser solicitada novamente pelo escalonador (continua em estado READY) + se a thread for uma thread comum (não for a idle_thread), ela vai pra ready_list + NÃO COLOCA A THREAD PRA DORMIR, APENAS CEDE A CPU!! + */ void thread_yield (void) { @@ -437,12 +407,13 @@ thread_yield (void) ASSERT (!intr_context ()); - old_level = intr_disable (); - if (cur != idle_thread) - list_insert_ordered (&ready_list, &cur->elem, thread_compare_priority, NULL); //mudança para adicionar o elemento na lista já ordenado - cur->status = THREAD_READY; - schedule (); - intr_set_level (old_level); + old_level = intr_disable (); //desliga interrupcoes + //verificar se não é a idle_thread, pois idle_thread não vai pra ready_list + if (cur != idle_thread) // se não for: + list_insert_ordered (&ready_list, &cur->elem, thread_compare_priority, NULL); //mudança para adicionar o elemento na ready_list já ordenado + cur->status = THREAD_READY; //muda o estado pra READY + schedule (); //aciona o escalonador pra colocar outra thread pra rodar + intr_set_level (old_level); //volta ao estado antigo de interrupções } /* Invoke function 'func' on all threads, passing along 'aux'. @@ -478,15 +449,15 @@ thread_get_priority (void) /* Sets the current thread's nice value to NICE. */ void -thread_set_nice (int nice) -{ +thread_set_nice (int nice UNUSED) +{ thread_current()->nice = nice; /*seta a thread atual e atualiza o nice*/ /*refaz a ordem após atualizar o nice*/ mlfqs_recalc_priority(thread_current(), NULL); thread_mlfqs_yield(); } -/* Returns the current thread's nice value. */ +/* retorna o nice da thread */ int thread_get_nice (void) { @@ -506,7 +477,7 @@ thread_get_recent_cpu (void) { return FP_INT_ROUND(FP_MUL_INT(thread_current()->recent_cpu,100)); } - + /*criação das funções mlfqs para realização dos calculos e atualizações por clock*/ void mlfqs_increment_recent_cpu() { @@ -569,80 +540,54 @@ bool insert_priority(const struct list_elem *a, const struct list_elem *b, void return thread_a->priority > thread_b->priority; } - - -/* Idle thread. Executes when no other thread is ready to run. - - The idle thread is initially put on the ready list by - thread_start(). It will be scheduled once initially, at which - point it initializes idle_thread, "up"s the semaphore passed - to it to enable thread_start() to continue, and immediately - blocks. After that, the idle thread never appears in the - ready list. It is returned by next_thread_to_run() as a - special case when the ready list is empty. */ + +/* Idle thread: executa quando nenhuma outra thread está pronta + é usada em thread_start, mas depois disso nunca aparece na ready_list + quando a ready_list está VAZIA, next_thread_to_run() retorna idle_thread! + */ static void idle (void *idle_started_ UNUSED) { struct semaphore *idle_started = idle_started_; idle_thread = thread_current (); - sema_up (idle_started); + sema_up (idle_started); //avisa thread_start que inicializou for (;;) { /* Let someone else run. */ intr_disable (); thread_block (); - - /* Re-enable interrupts and wait for the next one. - - The `sti' instruction disables interrupts until the - completion of the next instruction, so these two - instructions are executed atomically. This atomicity is - important; otherwise, an interrupt could be handled - between re-enabling interrupts and waiting for the next - one to occur, wasting as much as one clock tick worth of - time. - - See [IA32-v2a] "HLT", [IA32-v2b] "STI", and [IA32-v3a] - 7.11.1 "HLT Instruction". */ asm volatile ("sti; hlt" : : : "memory"); } } -/* Function used as the basis for a kernel thread. */ +/* inicio de toda thread criada com thread_create() */ static void kernel_thread (thread_func *function, void *aux) { ASSERT (function != NULL); - - intr_enable (); /* The scheduler runs with interrupts off. */ - function (aux); /* Execute the thread function. */ - thread_exit (); /* If function() returns, kill the thread. */ + intr_enable (); /* liga interrupçoes */ + function (aux); /* executa funcao funcao do usuario*/ + thread_exit (); } -/* Returns the running thread. */ +/* função utilizada pra saber qual thread está rodando */ struct thread * running_thread (void) { uint32_t *esp; - - /* Copy the CPU's stack pointer into `esp', and then round that - down to the start of a page. Because `struct thread' is - always at the beginning of a page and the stack pointer is - somewhere in the middle, this locates the curent thread. */ asm ("mov %%esp, %0" : "=g" (esp)); return pg_round_down (esp); } -/* Returns true if T appears to point to a valid thread. */ +/* verificar se é uma thread mesmo */ static bool is_thread (struct thread *t) { return t != NULL && t->magic == THREAD_MAGIC; } -/* Does basic initialization of T as a blocked thread named - NAME. */ +/* inicia a thread (nome, prioridade, etc., toda estrutura)*/ static void init_thread (struct thread *t, const char *name, int priority) { @@ -664,94 +609,74 @@ init_thread (struct thread *t, const char *name, int priority) intr_set_level (old_level); } -/* Allocates a SIZE-byte frame at the top of thread T's stack and - returns a pointer to the frame's base. */ +/* configuração da pilha */ static void * alloc_frame (struct thread *t, size_t size) { - /* Stack data is always allocated in word-size units. */ ASSERT (is_thread (t)); ASSERT (size % sizeof (uint32_t) == 0); - t->stack -= size; return t->stack; } -/* Chooses and returns the next thread to be scheduled. Should - return a thread from the run queue, unless the run queue is - empty. (If the running thread can continue running, then it - will be in the run queue.) If the run queue is empty, return - idle_thread. */ +/* + escolhe e retorna a próxima thread a ser escalonada + a idle_thread é como se fosse um modo de suspensão + -> quando não tem nada pra fazer, a cpu 'descansa', + colocando a idle_thread pra executar, q é uma thread que não faz nada + */ static struct thread * next_thread_to_run (void) { - if (list_empty (&ready_list)) - return idle_thread; - else + if (list_empty (&ready_list)) //verifica se ready_list está vazia + return idle_thread; // thread ociosa (só roda quando a ready_list está vazia) + else // se ñ estiver vazia, retorna o primeiro elemento da ready_list (round-robin) return list_entry (list_pop_front (&ready_list), struct thread, elem); } -/* Completes a thread switch by activating the new thread's page - tables, and, if the previous thread is dying, destroying it. - - At this function's invocation, we just switched from thread - PREV, the new thread is already running, and interrupts are - still disabled. This function is normally invoked by - thread_schedule() as its final action before returning, but - the first time a thread is scheduled it is called by - switch_entry() (see switch.S). - - It's not safe to call printf() until the thread switch is - complete. In practice that means that printf()s should be - added at the end of the function. - - After this function and its caller returns, the thread switch - is complete. */ +/* função chamada DEPOIS da troca de contexto, + nova thread que está rodando entra aqui + essa função serve pra finalizar a troca de contexto + aqui também ocorre a etapa 2 do thread_exit() + -> a nova thread libera a memória da thread + que estava em estado de DYING + geralmente é chamada pelo thread_schedule() + */ void thread_schedule_tail (struct thread *prev) { struct thread *cur = running_thread (); - ASSERT (intr_get_level () == INTR_OFF); - - /* Mark us as running. */ - cur->status = THREAD_RUNNING; + ASSERT (intr_get_level () == INTR_OFF); //interrupcoes desligadas - /* Start new time slice. */ - thread_ticks = 0; + cur->status = THREAD_RUNNING; //nova thread é RUNNING + thread_ticks = 0; //reseta o time slice #ifdef USERPROG /* Activate the new address space. */ - process_activate (); + process_activate (); #endif - /* If the thread we switched from is dying, destroy its struct - thread. This must happen late so that thread_exit() doesn't - pull out the rug under itself. (We don't free - initial_thread because its memory was not obtained via - palloc().) */ + /* se a troca de contexto ocorreu de uma threda q está morrendo, + libera a memória */ if (prev != NULL && prev->status == THREAD_DYING && prev != initial_thread) { ASSERT (prev != cur); - palloc_free_page (prev); + palloc_free_page (prev); //libera a memoria } } -/* Schedules a new process. At entry, interrupts must be off and - the running process's state must have been changed from - running to some other state. This function finds another - thread to run and switches to it. - - It's not safe to call printf() until thread_schedule_tail() - has completed. */ +/* ESCALONADOR: ESCOLHE QUEM VAI EXECUTAR E TROCA CONTEXTO ENTRE AS THREADS + +*/ static void schedule (void) { - struct thread *cur = running_thread (); - struct thread *next = next_thread_to_run (); - struct thread *prev = NULL; + struct thread *cur = running_thread (); // thread que está rodando + struct thread *next = next_thread_to_run (); //proxima thread + struct thread *prev = NULL; //inicialização - ASSERT (intr_get_level () == INTR_OFF); + ASSERT (intr_get_level () == INTR_OFF); // checar se interrupções estao desligadas /* TODO: * Ver de usar o thread_block, mas para o schedule * tem de verificar se uma thread esta bloqueada, alem de implementar @@ -760,22 +685,20 @@ schedule (void) ASSERT (cur->status != THREAD_RUNNING); ASSERT (is_thread (next)); - if (cur != next) - prev = switch_threads (cur, next); - thread_schedule_tail (prev); + if (cur != next) //verifica a necessidade da troca + prev = switch_threads (cur, next); //troca contextos e salva a thread anterior + thread_schedule_tail (prev); //chama a funcao pra finalizar a troca de contexto } -/* Returns a tid to use for a new thread. */ +/* determina o tid (id) de uma thread nova*/ static tid_t allocate_tid (void) { static tid_t next_tid = 1; tid_t tid; - lock_acquire (&tid_lock); tid = next_tid++; lock_release (&tid_lock); - return tid; } From a8affd27318d1812322b6332c96df56961541813 Mon Sep 17 00:00:00 2001 From: Miriam Gonzaga Date: Sat, 23 May 2026 12:55:03 -0300 Subject: [PATCH 10/11] coments sobre os estados da thread e funcionamento das funcoes Updated comments in thread.h to Portuguese for better understanding. --- src/threads/thread.h | 57 ++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/src/threads/thread.h b/src/threads/thread.h index 136979e..cd33795 100755 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -6,7 +6,12 @@ #include #include "threads/fixed_point.h" -/* States in a thread's life cycle. */ +/* estados possíveis de uma thread + RUNNING -> thread sendo executada na cpu + READY -> pronto pra executar (a espera da cpu) + BLOCKED -> bloqueada, esperando um recurso/evento pra poder ficar PRONTA + DYING -> vai ser destruída (já foi executada) + */ enum thread_status { THREAD_RUNNING, /* Running thread. */ @@ -15,23 +20,20 @@ enum thread_status THREAD_DYING /* About to be destroyed. */ }; -/* Thread identifier type. - You can redefine this to whatever type you like. */ +/* identificador da thread */ typedef int tid_t; #define TID_ERROR ((tid_t) -1) /* Error value for tid_t. */ -/* Thread priorities. */ +/* definição de prioridades, normalmente, + o valor da prioridade de um programa determina + sua execução antes de outro */ #define PRI_MIN 0 /* Lowest priority. */ #define PRI_DEFAULT 31 /* Default priority. */ #define PRI_MAX 63 /* Highest priority. */ -/* A kernel thread or user process. - - Each thread structure is stored in its own 4 kB page. The - thread structure itself sits at the very bottom of the page - (at offset 0). The rest of the page is reserved for the - thread's kernel stack, which grows downward from the top of - the page (at offset 4 kB). Here's an illustration: +/* cada thread ocua uma página de 4 kB, + a thread se estrutura no começo da página (offset 0), + enquanto a pilha da thread fica acima e vai crescendo seu tamanho 4 kB +---------------------------------+ | kernel stack | @@ -81,23 +83,28 @@ typedef int tid_t; only because they are mutually exclusive: only a thread in the ready state is on the run queue, whereas only a thread in the blocked state is on a semaphore wait list. */ + +/* a estrutura da thread guarda todas as informações importantes de uma thread +*/ + struct thread { - /* Owned by thread.c. */ - tid_t tid; /* Thread identifier. */ - enum thread_status status; /* Thread state. */ + /* struct usada em thread.c */ + tid_t tid; /* id da thread é único dela */ + enum thread_status status; /* status da thread (RUNNING, READY, BLOCKED ou DYING) */ char name[16]; /* Name (for debugging purposes). */ - uint8_t *stack; /* Saved stack pointer. */ - int priority; /* Priority. */ - int nice; /*valor de "gentileza" da thread*/ - fixed_point recent_cpu; /*tempo de CPU usado recentemente pela thread*/ - struct list_elem allelem; /* List element for all threads list. */ - struct list_elem sleep_elem; /* List element para a lista bloqueada */ - int64_t wake_up_tick; /* O tempo que a thread deve estar dormindo*/ + uint8_t *stack; /* ponteiro pro topo da stack */ + int priority; /* prioridade de 0 a 63. */ + int nice; // valor de "gentileza" da thread + fixed_point recent_cpu; //tempo da cpu usado recentemente pela thread + struct list_elem allelem; /* elemento pra lista de todas as threads */ + struct list_elem sleep_elem; // elemento para a lista de threads dormindo (bloqueadas) + int64_t wake_up_tick; // tempo q a thread vai ficar dormindo + /* Shared between thread.c and synch.c. */ - struct list_elem elem; /* List element. */ + struct list_elem elem; /* para a ready_list ou a fila de semáforo. */ -#ifdef USERPROG +#ifdef USERPROG /* Owned by userprog/process.c. */ uint32_t *pagedir; /* Page directory. */ #endif @@ -110,9 +117,12 @@ struct thread If true, use multi-level feedback queue scheduler. Controlled by kernel command-line option "-o mlfqs". */ extern bool thread_mlfqs; + void thread_mlfqs_yield(void); + void thread_sleep (int64_t wake_up_time); void thread_wake_up (int64_t ticks); + void thread_init (void); void thread_start (void); @@ -151,4 +161,5 @@ void recalc_recent_cpu(struct thread *t, void *aux); void mlfqs_recalc_all_recent_cpu(void); void mlfqs_sort_ready_list(void); + #endif /* threads/thread.h */ From 701608d3aeb9866ecfb7a1bd824ddc316fb98c2e Mon Sep 17 00:00:00 2001 From: Miriam Gonzaga Date: Sat, 23 May 2026 12:56:14 -0300 Subject: [PATCH 11/11] mlfqs funcionando 100% --- src/threads/synch.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/threads/synch.c b/src/threads/synch.c index 0a2da42..5f333cc 100755 --- a/src/threads/synch.c +++ b/src/threads/synch.c @@ -234,7 +234,9 @@ lock_release (struct lock *lock) lock->holder = NULL; sema_up (&lock->semaphore); - if (!intr_context()) thread_yield(); //cede CPU se thread de maior prioridade for desbloqueada + if (!intr_context()) + thread_yield(); //cede CPU se thread de maior prioridade for desbloqueada + } /* Returns true if the current thread holds LOCK, false