====== Gestão de Tarefas ======
:!: alterações na interface em 03/2023
{{ :so:ppos_02_tarefas.mkv |Vídeo deste projeto}}
**Objetivo**: construir as funções básicas de gestão de tarefas usando as funções de troca de contexto vistas no projeto anterior.
===== Descritor de tarefa =====
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 ;
===== Interface =====
As seguintes funções devem ser implementadas:
=== Inicializa o sistema ===
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) ;
=== Inicia uma nova tarefa ===
int task_init (task_t *task, void (*start_routine)(void *), void *arg)
* ''task'': estrutura que referencia a tarefa a ser iniciada
* ''start_routine'': função que será executada pela tarefa
* ''arg'': parâmetro a passar para a tarefa que está sendo iniciada
* retorno: o ID (>0) da nova tarefa ou um valor negativo, se houver erro
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'').
=== Transfere o processador para outra tarefa ===
int task_switch (task_t *task)
* ''task'': tarefa que irá assumir o processador
* retorno: valor negativo se houver erro, ou zero
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.
=== Termina a tarefa corrente ===
{{ :so:cutting-off-branch.jpg|Cutting off a branch}}
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''.
=== Informa o identificador da tarefa corrente ===
int task_id ()
* retorno: Identificador numérico (ID) da tarefa corrente, que deverá ser 0 para ''main'', ou um valor positivo para as demais tarefas. Esse identificador é único: não devem existir duas tarefas com o mesmo ID.
===== Observações =====
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}})
* constantes e macros globais
* definições dos tipos e estruturas de dados globais
* ''ppos.h'': interface do SO (fornecido: {{ppos.h}}, **não alterar**)
* protótipos das funções públicas
* ''ppos_core.c'': contém as definições internas do sistema:
* constantes e macros internas
* definições dos tipos e estruturas de dados internas
* funções internas
* implementações das funções públicas
Capriche na implementação, pois esse código será a base de todos os projetos posteriores. Todos os avisos de compilação gerados com o flag ''-Wall'' serão **descontados**!
===== Validação =====
Seu código deve funcionar adequadamente com os programas de teste abaixo indicados, fornecendo as saídas esperadas:
* {{pingpong-tasks1.c|programa de teste 1}} e sua {{pingpong-tasks1.txt|saída esperada}}
* {{pingpong-tasks2.c|programa de teste 2}} e sua {{pingpong-tasks2.txt|saída esperada}}
* {{pingpong-tasks3.c|programa de teste 3}} e sua {{pingpong-tasks3.txt|saída esperada}}
O primeiro programa de teste corresponde ao código {{contexts.c}} do projeto anterior, reescrito com as novas funções. Comparar os dois códigos pode ajudar a compreender o que deve ser implementado em cada função.
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
===== Depuração =====
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
===== Outras informações =====
* Duração estimada: 4 horas.
* Dependências:
* [[Trocas de contexto]]