alterações na interface em 03/2023
Objetivo: construir as funções básicas de gestão de tarefas usando as funções de troca de contexto vistas no projeto anterior.
Cada tarefa existente no sistema deve ter uma estrutura que a representa, ou seja, um descritor de tarefa (TCB - Task Control Block). O tipo dessa estrutura deve ser definido no arquivo ppos_data.h
:
typedef struct task_t { struct task_t *prev, *next ; // para a biblioteca de filas (cast) int tid ; // task ID, identificador da tarefa int status ; // pronta, executando, terminada, ... ... // demais informações da tarefa } task_t ;
As seguintes funções devem ser implementadas:
void ppos_init ()
Esta função inicializa as estruturas internas do SO. Por enquanto, conterá apenas algumas inicializações de variáveis e a seguinte instrução, que desativa o buffer utilizado pela função printf
, para evitar condições de disputa que podem ocorrer nesse buffer ao usar as funções de troca de contexto:
/* desativa o buffer da saida padrao (stdout), usado pela função printf */ setvbuf (stdout, 0, _IONBF, 0) ;
int task_init (task_t *task, void (*start_routine)(void *), void *arg)
task
: estrutura que referencia a tarefa a ser iniciadastart_routine
: função que será executada pela tarefaarg
: parâmetro a passar para a tarefa que está sendo iniciada
Atenção: deve ser previsto um descritor de tarefa que aponte para o programa principal (que exercerá a mesma função da variável ContextMain
no programa contexts.c
).
int task_switch (task_t *task)
task
: tarefa que irá assumir o processador
Esta é a operação básica de troca de contexto, que encapsula a função swapcontext
. Ela será chamada sempre que for necessária uma troca de contexto.
void task_exit (int exit_code)
exit_code
: código de término devolvido pela tarefa corrente (ignorar este parâmetro por enquanto, pois ele somente será usado mais tarde).
Neste projeto, quando uma tarefa encerra, o controle deve retornar à tarefa main
. Isso é feito usando usando task_switch
.
int task_id ()
main
, ou um valor positivo para as demais tarefas. Esse identificador é único: não devem existir duas tarefas com o mesmo ID.A implementação completa deste projeto compreende definir os tipos e estruturas de dados necessários para gerenciar as tarefas e implementar as funções acima descritas, comentando detalhadamente o código.
A convenção de estruturação de código em C deverá ser respeitada:
ppos_data.h
: definições de dados globais (esqueleto: ppos_data.h)ppos.h
: interface do SO (fornecido: ppos.h, não alterar)ppos_core.c
: contém as definições internas do sistema:-Wall
serão descontados!
Seu código deve funcionar adequadamente com os programas de teste abaixo indicados, fornecendo as saídas esperadas:
Compile da seguinte forma:
$ cc -Wall ppos_core.c pingpong-tasks1.c
Se desejar mais detalhes da compilação, pode usar o flag -Wextra
:
$ cc -Wextra ppos_core.c pingpong-tasks1.c
Todas as funções implementadas devem gerar mensagens de depuração, que permitam acompanhar a execução das tarefas, como no exemplo a seguir:
task_init: iniciada tarefa 23 task_switch: trocando contexto 14 -> 23 task_exit: tarefa 23 sendo encerrada ...
Essas mensagens de depuração somente deverão ser geradas se a contante global DEBUG
estiver definida, usando compilação condicional:
#ifdef DEBUG printf ("task_init: iniciada tarefa %d\n", task->id) ; #endif
A constante DEBUG
pode ser definida no código-fonte:
#define DEBUG
ou na linha de comando, no momento da compilação:
$ cc -Wall -o teste -DDEBUG ppos_core.c pingpong-tasks1.c