the /proc
File System

Advanced Linux Programming

Cap. 7

The /proc File System

Se executarmos o comando mount obtemos uma linha igual à seguinte:
none on /proc type proc (rw)

o none indica que o filesystem /proc não está associado com uma partição/hardware em particular.

o directório /proc é constituído por objectos que se comportam como ficheiros, mas que providenciam acesso a parâmetros, estruturas de dados e estatísticas do kernel do sistema.

The /proc File System

Exemplo: se fizermos:
% ls -l /proc/version
-r--r--r-- 1 root root 0 Sep 20 10:05 /proc/version

Nota algo de estranho na informação obtida ?

o tamanho do ficheiro é zero!

a data da ultima alteração ao ficheiro é a hora actual!

The /proc File System

Tamanho zero ? Mas se fizermos cat :
% cat /proc/version
Linux version 2.4.18..............

O conteúdo do ficheiro é gerado pelo kernel dinamicamente (na altura), por isso o conceito de tamanho do ficheiro não é aplicável.

The /proc File System

O sistema de ficheiros /proc contém para cada processo em execução um directório com o nome igual ao ID do processo.

/proc/self é um link simbólico para o directório do processo corrente.

Cada directório inclui as seguintes entradas:

cmdline – lista de argumentos do processo.

cwd – link para o directório de trabalho do processo.

environ – contem o ambiente de trabalho do processo.

The /proc File System

continuação:

exe – link para o executável do processo.

fd – directório que contem links para todos os ficheiros que o processo está a usar.

maps – informação sobre memória mapeada.

root – link para o directório raiz do processo ´/´.

status – contém informação sobre o estado e algumas estatísticas sobre o processo.

stat – igual ao status, mas a informação aparece toda na mesma linha.

statm – informação sobre a memória usada pelo processo.

The /proc File System

fd - directório que contem links para todos os ficheiros ou devices que o processo está a usar.

Como exemplo, suponha que tem uma shell com o ID 1261 a correr. Se numa outra janela fizer:
%ls –l /proc/1261/fd
lrwx------ 1 rslopes ............. 0 -> /dev/pts/4
lrwx------ 1 rslopes ............. 1 -> /dev/pts/4
lrwx------ 1 rslopes ............. 2 -> /dev/pts/4
...

0, 1 e 2 são links simbólicos inicializados como standard input, output e error respectivamente.
#echo “Olá Mundo” >> /proc/1261/fd/1

The /proc File System

statm – informação sobre a memória usada pelo processo:

o tamanho total do processo;

a quantidade de memória física que o processo ocupa;

a quantidade de memória partilhada com outros processos;

o tamanho do código do processo;

o tamanho das “lib’s” partilhadas usadas pelo processo

a quantidade de memória para o stack do processo

o número de “dirty pages” – páginas em memória alteradas pelo processo.

The /proc File System

Algumas entradas do /proc providenciam acesso a informação sobre o hardware do sistema:

/proc/cpuinfo

/proc/devices - lista de char e block devices

/proc/pci

...

The /proc File System

no /proc e no /proc/sys/kernel encontramos entradas que permitem obter informação sobre o estado e configuração do Kernel:

/proc/meminfo

/proc/version

/proc/sys/kernel/ostype

/proc/sys/kernel/osrelease

/proc/sys/kernel/hostname

...

The /proc File System

a entrada /proc/uptime possui informação sobre o tempo que passou desde que o sistema fez boot, bem como quanto tempo o sistema esteve idle desde então.

a entrada /proc/loadavg contem informação sobre o load do sistema.

número de processos a correr nos últimos 1, 5 e 15 minutos

número de processos a correr, que não estão bloqueados num system call, e número total de processos no sistema.

a última entrada indica o ID do último processo executado.

Understanding The Linux Kernel

Cap. 11

Kernel Synchronization Techniques

Métodos de Sincronização

Como é que podemos evitar “race conditions” no Kernel ?

O Kernel do Linux 2.6 já é preemptive;

Operações atómicas;

Desactivar os interrupts;

Locking

Semaphores

Spin Locks

O Kernel do Linux já é preemptive

O kernel do Linux <=2.4 não é preemptive, isto é, um processo a correr em “Kernel mode” não é substituído por um outro com prioridade superior.

No kernel <=2.4 as seguintes assumpções são verdade:

Nenhum processo a correr em Modo Kernel pode ser substituído por um outro processo, excepto quando o primeiro liberta o CPU voluntariamente.

Um interrupt ou uma excepção podem interromper um processo a correr em modo Kernel, contudo o processo continua a execução imediatamente depois do interrupt ou a excepção serem tratados.

Um processo do Kernel que está a lidar com um interrupt ou com uma excepção, pode ser interrompido apenas por um novo interrupt ou uma excepção

No kernel >=2.6, com o preemptive activo, um processo a correr em ”kernel mode” pode ser substituido por outro com prioridade superior...
 maior complexidade, principalmente no acesso aos recursos partilhados.

To be or not to be
preemptive

Exemplo: O que acontece se carregarmos um módulo com o seguinte código ?

…

int init_module(void) {

printk(“<1>Hello World.\n”);

while(1);

return 0;

}

…

Mais um exemplo:
Race Conditions

thread 1

thread 0

Supor que i=7 e que ambas as threads vão executar i++

escreve i (8)

-

-

escreve i (8)

incementa i (78)

-

-

incementa i (78)

lê i (7)

-

-

lê i (7)

Atomic Operations

A forma mais simples de evitar “Race Conditions” é através de operações simples que executam numa única instrução do CPU.

Com vários CPUS convêm declarar estas variáveis como volatile.

Adiciona 1 a *v e retorna 1 se o resultado é positivo, caso contrário retorna 0.

atomic_inc_and_test_
greater_zero(v)

Subtrai 1 a *v e retorna 1 se o resultado é 0, caso contrário retorna 0.

atomic_dec_and_test(v)

Decremento 1 de *v

atomic_dec(v)

Incrementa 1 a *v

atomic_inc(v)

Subtrai i de *v

atomic_sub(i,v)

Adiciona i a *v

atomic_add(i,v)

Iguala *v a i

atomic_set(v,i)

Retorna *v

atomic_read(v)

Desactivar o preemtive

preempt_disable();

/* preemption is disable here */

preempt_enable();

Desactivar os interrupts

Para evitar que um processo a correr uma zona critica dentro do Kernel possa ser interrompido devido a um interrupt, podemos desactivar os interrupts.

Podemos desactivar e activar os interrupts (num dado CPU) usando as instruções:

local_irq_disable()	/*executa a inst. cli */

local_irq_enable()	/*executa a inst. sti */

Note porém que zonas criticas “demoradas” devem usar outro método (locking).

Desactivar os interrupts II

O código mais indicado para desactivar os interrupts é o seguinte:

unsigned long flags

…

local_irq_save(flags);

… /* Interrupts are disabled in active CPU */

local_irq_restore(flags);

...

disable_irq(unsigned_int_irq);

...

enable_irq(unsigned_int_irq);

Locking

As formas de “Locking” mais importantes em Linux são:

Kernel semaphores

Spin Locks : para mais de 1 CPU

Kernel Semaphores

Quando um processo tenta aceder a um recurso protegido por um semáforo, o processo é suspenso. O processo volta a correr apenas quando o recurso ficar livre.

Os semáforos em Linux são “sleeping locks”, porque deixam a tarefa em modo “sleep” enquando o recurso está ocupado.

São usados em situações em que o tempo no qual o recurso fica bloqueado pode ser demorado.

Por outro lado, como existe um “overhead” para passar uma tarefa do modo “wake” para “sleep” e vice-versa, os semáforos não devem ser usados em situações em que o tempo de bloqueio de um recurso é pequeno.

Kernel Semaphores

“Kernel Semaphores” são objectos do tipo struct semaphore com os seguintes campos:

count: guarda um valor inteiro. Se for maior do que zero é porque o recurso está livre.

wait: guarda o endereço de uma lista “wait queue” que inclui todos os processos que estão em modo “sleep” à espera que o recurso fique livre.

waking: é usado para garantir que quando o recurso fica livre, ao acordar os processos, apenas um destes sucede ao tentar reservar os recursos.

Kernel Semaphores

O campo count é inicializado pela função sema_init() (usualmente para o valor 1).

Os semáforos são manipulados usando dois métodos:

down: tenta reservar o semáforo, e bloqueia se falhar.
(count--, se count<0 sleep)

up: liberta o semáforo, e acorda os processos bloqueados no mesmo. (count ++, se count <1 wakeup)

Exemplos:

struct semaphore s;	struct semaphore s

sema_init(&s,1);	sema_init(&s,1);

…	…

down(&s);	if (down_interruptible(&s)) …

… /* zona crítica */ …	/* recebeu um sinal (return -EINTR)*/

up(&s);	… /* zona crítica */ …

up(&s);

Spin Locks

Foram criados a pensar em ambientes de vários processadores, ou kernel em modo preemtive.

Funcionam de modo semelhante aos semáforos do kernel, mas quando um processo encontra o recurso bloqueado, fica em ciclo até ao recurso ficar livre.

É útil para casos em que sabemos que a zona crítica é pequena e compensa ficar em ciclo à espera, em vez de passar para o estado “adormecido”.

Spin Locks

Cada “spin lock” é representado pela estrutura spinlock_t que consiste num simples campo lock que pode ter o valor 0 (unlocked) ou 1 (locked).

A macro SPIN_LOCK_UNLOCKED inicia a “spin lock” para estado unlocked (0).

Exemplo:

#include <linux/spinlock.h> (definido em #include<asm/spinlock.h>)

spinlock_t lock = SPIN_LOCK_UNLOCKED;

…

spin_lock(&lock);

… /* Critical section here */ …

spin_unlock(&lock);

Spin Locks +
Desactivar de Interrupts

Existe uma variante do “spin locks” que permite desactivar os interrupts na zona critica do programa.

Exemplo:

spinlock_t lock = SPIN_LOCK_UNLOCKED;

…

unsigned long flags;

spin_lock_irqsave(&lock,flags);

… /* Critical section here */ …

spin_unlock_irqrestore(&lock,flags);

Read / Write locks

rwlock_t l = RW_LOCK_UNLOCKED;

read_lock(&l);

/* critical section (with read only)... */

read_unlock(&l);

--------------------

write_lock(&l);

/* critical section (with write/read)... */

write_unlock(&l);

um write_lock só é permitido se não houver nenhum lock (read ou write) activo.

é possível vários processos usarem um “read lock”.

Cuidado com os
Deadlocks…

CPU1	CPU2

lock A	lock B

…	…

lock B	lock A

…	…

Solução:

Fazer os locks sempre pela mesma ordem…

2001/2002 Aplicações Distribuídas e Internet

Ricardo Lopes

2001-09-26T18:23:03