• Nenhum resultado encontrado

4.2 Refactoring do ARM microkernel SMP para AMP

4.2.1 ARM microkernel singlecore

A versão original do microkernel foi implementada com o intuito de ser executada em várias unidades de processamento em simultâneo (abordagem SMP). Nesse sentido, este possui no seu código várias secções que se destinam a dar suporte a esse tipo de configuração. No entanto, a versão singlecore não necessita desse su- porte e mesmo algumas implementações, como a dos mecanismos de sincronização, necessitam de ser refeitas, pois o que fazia sentido numa implementação SMP pode não fazer numa implementação singlecore. Seguidamente, serão então analisadas as alterações efetuadas, de forma a passar de uma implementação multicore para uma singlecore. Os mecanismos transversais de comunicação e sincronização serão abordados posteriormente na secção 4.3;

Boot

O código de arranque original foi implementado de forma a dar suporte e a possibi- litar uma execução no modo SMP. Por isso, várias secções do código de boot já não são necessárias, para inicializar uma versão singlecore do microkernel, onde ape- nas uma única unidade de processamento é responsável por gerir todo o sistema. Assim, como se pode ver na figura 4.6, o código do boot já não tem nenhuma preo- cupação como a sincronização do processo de arranque, e além disso é responsável

por inicializar todo o processador (pilhas, MMU, sistema de memória) e todas as bibliotecas de suporte. No que diz respeito aos recursos de hardware que se desti- nam a dar suporte ao processamento paralelo, como a SCU, já não são utilizados, pois as funcionalidades destes já não têm utilidade nesta implementação.

Mircrokernel Singlecore boot Inicialização do CPU Inicialização da biblioteca de C Inicialização do GIC (ditributer e interface) Inicialização da biblioteca das threads e instalação

do escalonador

Main()

Figura 4.6: Processo de arranque do ARM microkernel singlecore

Escalonador

No que diz respeito ao escalonador, este em si não sofreu grandes alterações. Ape- nas foram retirados os mecanismos de exclusão mútua utilizados, para garantir o acesso exclusivo a este, pois como o microkernel só é executado por uma única unidade de processamento, este não precisa ser protegido contra acessos concor- rentes. No entanto, a geração do tick que desponta a execução deste teve de sofrer alterações mais significativas. Isto porque na versão original como apenas era uti- lizado um temporizador, existia a necessidade de adicionar um mecanismo que distribuísse o tick por todas as unidades de processamento. No entanto, na versão

singlecore tal já não é necessário, pois a interrupção gerada pelo temporizador

pode despontar diretamente a execução do escalonador. Este mecanismo pode ser observado na figura 4.7.

Escalonador Temporizador Privado

CPU

Tick do Escalonador

Figura 4.7: Geração do tick do escalonador

Sincronização

Os métodos de sincronização, em geral, requereram alterações mais significativas. Com o intuito de facilitar a compreensão das alterações efetuadas e as razões destas, seguidamente serão analisadas as novas implementações juntamente com as originais, de forma a relacionar as alterações efetuadas com o tipo de ambiente de execução a que se destinam (singlecore ou multicore).

Os métodos de sincronização que requereram uma reestruturação mais aprofun- dada foram:

1. Primitiva básica de exclusão mútua

• Implementação original: implementada com recurso a spinlocks, que são capazes de garantir acessos exclusivos a secções de código crítico, num ambiente onde existe verdadeira concorrência.

• Implementação singlecore: já não existe concorrência verdadeira, logo a proteção de secções críticas de código pode ser atingida garan- tindo que essas secções sejam executadas ininterruptamente. Assim sendo, nesta implementação é utilizada a desabilitação e habilitação das interrupções como forma de proteção das secções criticas.

• Implementação original: funcionam como os spinlocks. Quando o

mutex já se encontra adquirido as tarefas ficam bloqueadas num spin- lock, até conseguirem adquirir o mutex. Nesta implementação, as tarefas

não são suspendidas ficando ativas até ao fim do seu time-slice e podem ser resumidas mesmo sem terem adquirido o mutex, continuando assim bloqueadas no spinlock.

• Implementação singlecore: ao contrário do que acontece na im- plementação multicore, só existe uma tarefa a ser executada em cada momento, não havendo portanto a possibilidade do mutex ser libertado enquanto esta se encontra a ser executada. Logo, foi implementado um mecanismo que permite a suspensão de tarefas bloqueadas nos mutexs, colocando estas no estado sleep. Posteriormente é utilizada uma política FIFO, para atribuir o mutex às tarefas bloqueadas.

3. Semaphores

• Implementação original: funcionam de forma semelhante aos spin-

locks, com a diferença de em vez de testar se um lock se encontra blo-

queado ou livre, utiliza um contador que enquanto este não atinge um valor negativo, concede acesso às tarefas. Tal como acontece nos mu-

texs, as tarefas bloqueadas são mantidas ativas, presas no spinlock do semaphore.

• Implementação singlecore: pelo mesmo motivo que levou à alteração da implementação dos mutexs, os semaphores também foram alterados para permitir a suspensão das tarefas. As tarefas bloqueadas são colo- cadas no estado sleep e posteriormente resumidas assim que um novo

post seja executado, seguindo uma política FIFO.

Para além destas alterações, várias outras funções foram alteradas principalmente na forma como utilizavam os mecanismos de sincronização. Na implementação original, todas as secções criticas de código eram protegidas utilizando mutexs. Contudo, estas foram alteradas para usarem um mecanismo mais leve, a desabili- tação e habilitação das interrupções. Seguidamente, são apresentadas e descritas todas as funções presentes na versão original que foram removidas na versão sin-

glecore.

• holding_pen: utilizada na sincronização do processo de inicialização das várias unidades de processamento.

• __cpu_idle: função responsável por finalizar as inicializações locais das uni- dade de processamento secundárias. É também aqui que os outros processa- dores aguardam até receberem a IPI referente à função de escalonamento. • scheduler_timer: funciona em conjunto com o temporizador responsável

por gerar o tick do sistema. Esta função é responsável por enviar a IPI, referente ao escalonador, para todas as unidades de processamento seguindo uma política round-robin.

• acquire_spinlock: permite adquirir um spinlock. • acquire_trylock: tenta adquirir um spinlock. • release_spinlock: liberta um spinlock.

Documentos relacionados