2009-06-17

Testes, exames, essas cenas

Queria pedir desculpa a todos aqueles que me pediram ajuda no domingo por não ter respondido a ninguém. Não tenho net em casa, e por isso só reparei nos comentários bastante tarde. Também tive teste de CG na segunda-feira e por isso só comecei a estudar para SO segunda à tarde. Ainda acabei o código dos guiões que me faltavam, mas só perto da meia-noite. Duvido muito que por essa altura tenham ajudado alguém, mas gostava de pensar que sim.

Gostava de ouvir comentários sobre o teste, como correu ao pessoal. Pareceu-me bastante fácil, visto os exercícios práticos serem exercícios simples sobre processos e ficheiros. Não era necessário pipes e era necessário escrever um simples e pequeno signal handler para o primeiro.

O primeiro exercício prático (II) pedia para escrever um programa que corresse um outro programa chamado “renovaveisnodia”. Este “renovaveisnodia” tinha uns bugs que faziam com que terminasse abruptamente de tempos a tempos. A solução deveria correr o “renovaveisnodia” novamente sempre que este terminasse anormalmente. Também era pedido que ambos os programas terminassem quando o utilizador usasse o Ctrl+C. Isto podia ser resolvido com algo deste género:

pid_t pid;

// Signal handler
void die(int signum)
{
// Propagar o sinal
kill(pid, signum);
// Sair
exit(EXIT_SUCCESS);
}

int main (int argc, char** argv)
{
int status;

// Registar signal handler para interrupção pelo teclado (CTRL+C)
signal(SIGINT, die);

do
{
pid = fork();
if(pid == -1)
{
perror("fork");
exit(EXIT_FAILURE);
}
if(pid == 0)
{
// Lançar o programa
execlp("renovaveisnodia", "renovaveisnodia", NULL);
exit(EXIT_FAILURE);
}
else
{
// Esperar
wait(&status);
}
} while((WIFEXITED(status) && WEXITSTATUS(status) != EXIT_SUCCESS) ||
(!WIFEXITED(status)) // Enquanto sair sem successo,
// ou terminar anormalmente
return EXIT_SUCCESS;
}

O segundo (III) pedia para escrever um programa que colectasse os outputs de vários programas num ficheiro chamado “xlog.log”. Os programas a executar eram passados como argumentos na linha de comandos, assim:

savelog amsn pidgin …

Podia ser resolvido assim:

int main(int argc, char** argv)
{
int i;
int fdout = creat("xlog.log", 0644);
// int fdout = open("xlog.log", O_CREAT | O_WRONLY | O_APPEND, 0644);

for(i = 1; i < argc; i++)
{
pid_t pid = fork();
if(pid == -1)
{
perror(argv[i]);
}
else if(pid == 0)
{
dup2(fdout, 1);
close(fdout);
execlp(argv[i], argv[i], NULL);

perror(argv[i]);
exit(EXIT_FAILURE);
}
}

close(fdout);

for(i = 1; i < argc; i++)
{
wait(NULL);
}

return EXIT_SUCCESS;
}

Agora vou ver se acabo uns posts para os guiões que me faltavam (processos em background, redireccionamento e pipes), para aqueles que infelizmente tenham de fazer o exame.

6 commentários:

Anónimo disse...

É pah, eu tou bastante lixado com o teste... Não era dificil não senhor, mas eu tava um bocado nervoso, atrapalhei-me bués e compliquei o fácil.

I) Aqui fiz quase o que tu fizeste com a excepção do while, usei antes um signal handler para o SIGCHLD. Dessa forma também controlei o WIFSTOPPED, porque ele podia ter parado em vez de terminar. Não me lembro das palavras exactas do enunciado mas lembro que não dizia apenas "verificar se o processo terminou inesparadamente", falava noutra coisa qualquer e optie por essa solução diferente.

E só uma nota, tens um erro no teu código acima no execlp(), falta um NULL no fim (e no problema 2 também).

II) Quanto a este dois foi o que mais me chateou, primeiro porque fui estupido de mais por pensar que precisaria de pipes (se calhar até precisava, já lá vamos) e fiz uma confusão tremenda na resolução que provavelmente não funciona, mas pronto... Quando cheguei a casa, comecei a pensar no problema e em 5mins apercebi-me que um simples dup2 chegava. Sou mesmo estupido...

Agora, isso falta uma cena, que não é culpa tua... Mas os profs na minha sala falaram em algo que não fala no enunciado mas que deveria ser feito, porque não tinha lógica não o ser e dúvido que deem o total dos pontos a uma solução como a tua, o que é parvo porque o enunciado não era explicitio e pelos vistos tu nem sabias.

O problema aqui é que eles que devido a natureza do que era pedido, as linhas escritas no ficheiro de log podiam estar misturadas, ou seja, um programa podia mandar uma linha po output mas não uma linha completa e nessa situação, um gajo tinha de por um \n no fim dessa linha no ficheiro de log para quando vier a próxima linha de um programa diferente, não ficarem misturadas.

Eu não consigo imaginar porque ao usarmos o dup2 (e mesmo pipes), um gajo só esta a redirecionar o output/input, como é que vamos "parar" isso, detectar se uma linha está completa ou não, se tem um \n no fim e se n tiver, adicionamos nós um?? Tens alguma ideia de como é que se faz isto?

Martinho Fernandes disse...

Ooops. Esqueci-me do pormenor do NULL, e no teste também :(. Lá se vai um ponto...

Quanto ao segundo, eu também comecei a fazer uma resolução estúpida com pipes e depois acabei por riscar duas páginas completas e fazer de novo como fiz aqui. :) O que me safou foi ainda não ter perdido muito tempo.

Quanto a essa cena das linhas, o prof não disse nada, e no enunciado dizia linhas bem demarcadas. Pensei que isso significasse que as linhas eram escritas de forma atómica. Isto aliado ao facto de o input/output ser serializado resolve o problema. Quando um processo escreve num descritor, todas as outras escritas nesse descritor bloqueiam. Se um processo tentar escrever "aaaaaaa" e outro "bbbbbbb" o resultado só pode ser "aaaaaaabbbbbbb" ou "bbbbbbbaaaaaaa", nunca "ababababababab". A única coisa que é necessário garantir é que as linhas são escritas de forma atómica. Assumi que "bem demarcadas" fosse isso. Talvez não devesse tê-lo feito.

Sem essa garantia é praticamente impossível fazer isto sem fazer algum tipo de parsing, o que tornaria o exercício demasiado complexo para fazer no teste.

Anónimo disse...

Exactamente o que eu acho, mas eu só te estou a dizer aquilo que os profs na minha sala disseram ao pessoal.

Bem, vamos ver o que sai daqui...

Anónimo disse...

Viva!

Podias dizer mais ou menos as questões para as resoluções que aqui disponibilizaste?

Obrigado.

Anónimo disse...

podes colocar a resolução do exame do ano passado?

Martinho Fernandes disse...

Desculpa mas não tenho o exame do ano passado e agora não tenho mesmo tempo para resolver isso, porque ainda tenho 4 exames pa fazer :(

Enviar um comentário