Gestão de Tarefas

:!: alterações na interface em 03/2023

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) 

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)

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

Cutting off a branch

void task_exit (int exit_code)

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 ()

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:

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:

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