Programacao em C no GNU/Linux ¸˜

Lucas Correia Villa Real lucasvr@gobolinux.org 29 de Fevereiro de 2004

´ Conteudo
1 Operacao do GNU/Linux ¸˜ 1.1 Obtendo acesso ao GNU/Linux . . . . . . . . 1.2 Como executar comandos sobre o GNU/Linux 1.3 Obtendo ajuda sobre comandos . . . . . . . . 1.4 Consoles virtuais . . . . . . . . . . . . . . . 1.5 Processos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 3 4 5 5 7 7 8 9 14 14 15 16 17 18 18 21 21 24 28 30 31 32 32 33 38 44 46 54 54 54

2 Ambiente de desenvolvimento 2.1 Compilador GCC . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Arquivos headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 Utilizando os recursos de debug . . . . . . . . . . . . . . . . . . . . 2.4 Autoconf e Automake . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4.1 Escrevendo um arquivo Makefile.am . . . . . . . . . . . . . . 2.4.2 Escrevendo um arquivo configure.in . . . . . . . . . . . . . . 2.5 DDD - Data Display Debugger . . . . . . . . . . . . . . . . . . . . . 2.6 Criando aplicativos que rodem tanto no GNU/Linux como no Windows 3 Explorando os recursos b´ sicos do sistema operacional a 3.1 Lendo parˆ metros curtos e longos passados pela linha de comando a 3.2 Trabalhando com arquivos . . . . . . . . . . . . . . . . . . . . . 3.3 Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4 Descritores de Arquivos . . . . . . . . . . . . . . . . . . . . . . . 4 CGI: Common Gateway Interface 5 Bibliotecas dinˆ micas a 5.1 Criacao de bibliotecas dinˆ micas . . . . . . . . . . . . . . . . . . . . ¸˜ a 6 Processos e threads 6.1 Processos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2 Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 TCP/IP 7.1 Select . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.2 Conex˜ es n˜ o-bloqueantes . . . . . . . . . . . . . . . . . . . . . . . o a 8 Bancos de dados 8.1 Implementacoes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ¸˜ 8.2 Programando com Bancos de Dados em C . . . . . . . . . . . . . . . 1 . . . . . . . .

´ CONTEUDO
9 Interface Gr´ fica a 9.1 Servidor X . . . . . . . . 9.2 A biblioteca Xlib . . . . 9.3 Gerenciadores de Janelas 9.4 GTK+ . . . . . . . . . .

2 58 58 59 59 59 62 62 64 64 66 70 71 73 79 79 80

. . . .

. . . .

. . . .

. . . .

. . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

10 Comunicacao ¸˜ 10.1 Porta Paralela . . . . . . . . . . . 10.2 Porta Serial . . . . . . . . . . . . 10.2.1 A interface Termios . . . . 10.2.2 Modo canˆ nico . . . . . . o 10.2.3 Modo n˜ o-canˆ nico (raw) a o 10.2.4 Modo ass´ncrono . . . . . ı 10.3 USB . . . . . . . . . . . . . . . .

11 Timers 11.1 Sinais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Utilizando timers . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Cap´tulo 1 ı

Operacao do GNU/Linux ¸˜
1.1 Obtendo acesso ao GNU/Linux
Distribuicoes convencionais de GNU/Linux fornecem duas maneiras para que o usu´ rio ¸˜ a autentique-se no computador: uma delas e atrav´ s de login gr´ fico, e a outra e atrav´ s ´ e a ´ e de login via console. A segunda maneira e a mais comum, onde e exigido um nome de usu´ rio e uma ´ ´ a senha. Todo o sistema GNU/Linux mant´ m uma conta de super-usu´ rio, normalmente e a associada ao nome root, e contas opcionais para cada usu´ rio que ir´ operar este host. a a Normalmente s˜ o utilizados dois arquivos para efetuar a autenticacao de um usu´ rio: a ¸˜ a o passwd e o shadow, localizados no diret´ rio de configuracoes de programas da o ¸˜ distribuicao, freq¨ entemente o /etc. O primeiro arquivo mant´ m uma listagem com ¸˜ u e os nomes de usu´ rios, seu identificador unico no sistema (um valor inteiro), o grupo a ´ principal ao qual ele pertence, seu nome completo (al´ m de outros dados opcionais) e e a shell que ser´ utilizada em suas sess˜ es. a o Ap´ s verificar a existˆ ncia deste usu´ rio a partir do passwd, o arquivo shadow o e a e processado. Este arquivo cont´ m uma listagem das senhas de cada usu´ rio, crip´ e a tografadas. A senha fornecida pelo usu´ rio e processada pelo mesmo algoritmo, e e a ´ ´ feito um matching para verificar se ambas senhas criptografadas s˜ o idˆ nticas, encera e rando o processo de autenticacao do usu´ rio no host e dando a ele o acesso a um console ¸˜ a com uma shell. Existem outras formas de autenticacao, como o Linux-PAM, que faz uso de m´ dulos ¸˜ o de autenticacao. Assim, e poss´vel escrever m´ dulos com rotinas espec´ficas para au¸˜ ´ ı o ı tenticar o usu´ rio, como a validacao de algum cart˜ o magn´ tico, reconhecimento facial a ¸˜ a e ou ainda pela voz.

1.2 Como executar comandos sobre o GNU/Linux
As distribuicoes GNU/Linux costumam ser compostas por um conjunto de pacotes ¸˜ base, que capacitam a utilizacao de diferentes servicos, al´ m de interfaces para permitir ¸˜ ¸ e que o usu´ rio faca uso do sistema – normalmente compostas por uma shell, um servidor a ¸ para a interface gr´ fica e um gerenciador de janelas. a Shells s˜ o interfaces em modo texto, onde comandos digitados pelo usu´ rio s˜ o a a a interpretados e executados. Existem diferentes implementacoes destas interfaces, den¸˜ tre as quais podem-se destacar o ASH, BASH, KSH, CSH, TCSH e o ZSH. Estas 3

ı a ou modificar a entrada de dados para que seja feita a partir de um outro fluxo que n˜ o a a entrada padr˜ o (stdin). O que as diferencia e a forma na qual a informacao e apresentada ao usu´ rio. ¸˜ ¸˜ Existem dois formatos predominantes como forma de documentacao de aplicativos ¸˜ no GNU/Linux: as man pages e as info pages. Caso o primeiro caracter do operador de redirecionamento seja “>”. processados na ordem em que aparecem. pode-se executar o programa usando a seguinte forma: $ programa & O “&” indica que o processo filho relativo a execucao de “programa” ser´ criado. ¸˜ . Nota-se que essa e a mesma semˆ ntica obtida com comandos executados no MS´ a DOS. um prompt fica dispon´vel ao usu´ rio. presente em grande parte das distribuicoes atuais. • Uma descricao do que ele faz. sem aguardar pelo a ¸˜ t´ rmino do processo filho. mas ` ¸˜ a que o processo pai (o BASH) ir´ continuar seu fluxo de execucao. aguaro ı a dando a entrada de algum comando. Nestes casos. OPERACAO DO GNU/LINUX ¸˜ 4 implementacoes diferenciam-se pela sintaxe na qual o usu´ rio utiliza para a execucao ¸˜ a ¸˜ de tarefas e pelos recursos que cada uma oferece. um dos interpretadores mais comuns. da esquerda para a direita. ` ı a Tamb´ m h´ casos (em caso de depuracao de mensagem de erros. ¸˜ Ap´ s realizar o login no sistema. cona tendo explicacoes sobre a sua operacao. a Em alguns casos e desej´ vel que o programa seja executado de forma as´ncrona. deseja-se continuar a ter acesso ao console antes mesmo que o programa tenha terminado. A sintaxe padr˜ o para a execucao de um programa a ¸˜ no BASH e: ´ $ programa A execucao deste comando ir´ criar um novo processo. isto pode querer ser feito para redirecionar a sa´da de erro padr˜ o (stderr). e Bem como a execucao de programas.´ CAPITULO 1. no caso) executa o programa de forma s´ncrona. onde a shell (command. por exemplo) e a ¸˜ onde-se quer direcionar ambas sa´das (stdout e stderr) para um arquivo. o redirecionamento refere-se a sa´da padr˜ o (stdout). Da ı a ı a mesma forma. As ´ ¸˜ ´ a man pages apresentam basicamente: • A sinopse do programa.com. enquanto o processo pai (o ¸˜ a BASH) ir´ aguardar pela sua finalizacao para continuar a execucao de outros comana ¸˜ ¸˜ dos. a A forma que o BASH utiliza para fazer o controle de redirecionamentos e atrav´ s ´ e dos operadores “<”e “>”. Esta sess˜ o trata da operacao b´ sica a ¸˜ a sobre o BASH. ou ı seja: Espera que os filhos terminem para retornar o controle do terminal ao usu´ rio. o que pode ser ı obtido com: $ programa >& arquivo_com_mensagens 1. ´ a ı ou seja.3 Obtendo ajuda sobre comandos Cada programa base do GNU/Linux costuma apresentar uma p´ gina de manual. freq¨ entemente e desej´ vel redirecionar a ¸˜ u ´ a sa´da do programa para algum outro dispositivo que n˜ o a sa´da padr˜ o (stdout).

que lista todos os processos da m´ quina. OPERACAO DO GNU/LINUX ¸˜ • Opcoes e argumentos que s˜ o tratados por este programa. utiliza-se o comando setfont(8). principalmente quando existe um grande ¸˜ a volume de dados a ser informado.´ CAPITULO 1. ¸˜ a ¸˜ que inclui o autor do processo. 1. que lista todos os ı ´ processos pertencentes a usu´ rio. ` a • nice(1): executa um comando com uma prioridade diferente de escalonamento. • Autor(es). por permitir que ´ ı ´ ´ um terminal virtual colete mensagens do sistema e warnings. e atrav´ s deste n´ mero e poss´vel manipular este u e u ´ ı processo. Eles s˜ o chamados de “virtuais” pela possibilidade de ı a executar v´ rias instˆ ncias de terminais virtuais – tamb´ m chamados de consoles vira a e tuais – em um unico terminal f´sico. Ele mostra algumas ¸˜ informacoes sobre o sistema. Este formato normalmente e utilizado para deta´ lhar a documentacao de um programa. uma man page e disposta na forma de uma p´ gina cont´nua de infore ´ a ı macoes.5 Processos Qualquer tarefa atribu´da ao GNU/Linux e um processo. Outros parˆ metros uteis s˜ o o “-C nome”. Todo comando executado ı ´ gera um n´ mero de processo (PID). Prioridades no Linux v˜ o de -20 (prioridade alta) a 19 (prioridade baixa). e “-U usuario”. todas em paralelo. que a ´ a listam os processos com um nome espec´fico. 1. a ` A prioridade padr˜ o para execucao de processos e 0. ¸˜ a • Referˆ ncias a p´ ginas manuais semelhantes que sejam relevantes. Alguns destes programas que permitem a manipulacao de processos s˜ o: ¸˜ a • top(1): lista os processos em execucao em tempo real. ¸˜ ı ¸˜ As info pages solucionam este problema. apresentando a documentacao em um for¸˜ mato que permite uma navegacao mais f´ cil. e um a a terceiro terminal rodando uma sess˜ o X. a ¸˜ ´ . podendo muitas vezes tornar dif´cil a localizacao de determinados assuntos. e ¸˜ Para modificar as fontes utilizadas em um terminal. Este recurso e bastante util. e ` a • Problemas conhecidos. a a como a opcao “-x”. a A maneira utilizada para alternar entre os diferentes consoles virtuais e normal´ mente realizada atrav´ s da combinacao de teclas Alt-<Fn>. Algumas das informacoes incluem o nome do processo e a ¸˜ quantidade de mem´ ria e CPU consumidas por ele. e a opcao “-u”. enquanto outro terminal virtual seja utilizado para gerenciar uma sess˜ o de um usu´ rio em modo texto. enquanto as man pages explicam os recursos do ¸˜ programa de forma mais simplista. V´ rios parˆ metros podem ser utilizados.4 Consoles virtuais O kernel Linux oferece suporte a dispositivos de terminais virtuais que suportam dispositivos de v´deo e teclado. bem como uma lista das tarefas sendo gerenciadas ¸˜ pelo kernel Linux. o • ps(1): lista os processos atuais. 5 Al´ m disso.

Este comando e util quando deseja-se rodar algum programa e logo ap´ s efetuar o logoff da ´ ´ o m´ quina: o programa continuar´ em execucao at´ o t´ rmino de sua execucao. este comando mostra-os. faz com que o controle seja dado a um processo. a shell fica liberada para que o usu´ rio continue a execucao de a ¸˜ comandos nela. Caso haja mais de um. ao inv´ s do seu n´ mero.2. Uma lista de sinais encontra-se dispon´vel na man page do signal(7). este comando e ` permite trazer de volta algum job que esteja em background. para tornar e u a dar o controle a ele. e necess´ rio especificar o seu n´ mero. Este comando e implementado pela shell (BASH e ZSH o ´ implementam). e • nohup(): roda algum comando. Este comando e bastante utilizado para chamar programas gr´ ficos no ambiente ´ a X sem bloquear o terminal. OPERACAO DO GNU/LINUX ¸˜ • renice(1): altera a prioridade de escalonamento de algum processo. A forma de deixar um programa em background e disparando´ o com o parˆ metro “&”. como visto na Sess˜ o 1. .´ CAPITULO 1. ou pressionando a tecla a a CTRL+Z durante a execucao do programa. Assim. ´ a u Algumas shells utilizam o nome do procsso. este modo permite que o programa continue sua execucao em uma sub¸˜ shell. 6 • kill(1): envia um sinal para um processo. ¸˜ • fg: tamb´ m pertinente a controle de programas em background. No entanto. a a ¸˜ e e ¸˜ • jobs: caso tenha algum programa (job) sendo executado em background. • bg: assim como o fg. listado com o comando jobs. ı • killall(): envia um sinal para todos os processos especificados na linha de comando atrav´ s de seu nome. ignorando sinais de hangup. e o programa sai do estado de background e torna a executar.

a ı • Ligacao: Nesta fase os arquivos . Este ¸˜ e o compilador padr˜ o de qualquer distribuicao GNU/Linux. ´ a ¸˜ Quando o GCC e invocado. Al´ m disso. A ´ ligacao combina todos os arquivos objetos especificados como entrada em um arquivo ¸˜ execut´ vel. o GCC utiliza o utilit´ rio cpp. ı e 7 . Ada. Nesta fase. ele normalmente realiza quatro etapas para gerar o exe´ cut´ vel: pr´ -processamento. caso ele n˜ o esteja dispon´vel. podem ser utilizados os seguintes comandos: • Pr´ -processamento: e $ gcc -E teste. compilacao. a • Compilacao: Nesta fase e produzida a linguagem de montagem dos arquivos de ¸˜ ´ entrada.c -o teste. com suporte a o a a linguagens como C. ou o montador nativo as. sempre nesta ordem.1 Compilador GCC “GCC” [STA 2002] e uma abreviacao do termo GNU Compiler Collection. onde a abreviacao passa a ter o significado de “GNU C Compiler”.o e as bibliotecas s˜ o “colocados” no exe¸˜ a cut´ vel. O utilit´ rio usado nessa fase e o ld (GNU Linker). Estes passos podem ser melhor descritos como: a • Pr´ -processamento: Esta etapa e respons´ vel pela resolucao de diretrizes do pr´ e ´ a ¸˜ e processador. e encerram produzindo um arquivo objeto. Java e Treelang. Os primeiros trˆ s est´ gios ´ ı e a aplicam-se a um unico arquivo fonte. Nesta etapa.i. o GCC utiliza o utilit´ rio gas (GNU a Assembler). e a e ¸˜ ¸˜ sendo que e poss´vel parar o processo no final de cada etapa. Fortran. C++. #include. • Montagem: Produz o arquivo objeto .Cap´tulo 2 ı Ambiente de desenvolvimento 2. #if. a a ´ Para parar o GCC em alguma determinada etapa. Ele leva ´ ¸˜ este nome pelo fato de que v´ rias vers˜ es do compilador est˜ o integradas. Objective-C. montagem e ligacao. como #define.i Este comando redireciona a sa´da do pr´ -processador para o arquivo teste. ` e ele representa tanto o nome geral do compilador quanto o nome do compilador de programas C. levando em conta a linguagem de montagem dos arquivos de entrada.o.

a seguinte linha de comando poderia ser utilizada para compilar o programa final: $ gcc -o teste arquivo1.c e arquivo2. a 8 Assim.1.c Gera o arquivo objeto teste. No a entanto.c O arquivo teste. utiliza-se o seguinte comando: $ gcc -o teste teste. Tabela 2. Algumas das principais podem a ser vistas na Tabela 2. por exema plo).cc . arquivo1. ´ o . Caso hajam a o dois arquivos.so Interpretacao ¸˜ Programa em linguagem C Programa em linguagem C++ Programa em C pr´ -processado e Programa em C++ pr´ -processado e Programa em linguagem Assembly Programa objeto Bibliotecas compiladas Alguns parˆ metros importantes suportados pelo GCC foram vistos.C .2 Arquivos headers Arquivos headers cont´ m basicamente definicoes utilizadas por bibliotecas do sistema e prot´ e ¸˜ o tipos de funcoes. Normalmente e um symlink para o diret´ rio /usr/X11R6/include/X11.c . • /usr/include/X11: headers para compilar programas que usam o X11.i . Alguns outros diret´ rios importantes s˜ o: o o a • /usr/X11R6/include/X11: cont´ m headers necess´ rios para compilar programas e a que usam o X11 Window System. outras opcoes podem ser importantes para compilar um projeto.ii .c No entanto. para gerar um execut´ vel para um simples programa (teste. A localizacao dos arquivos headers em uma distribuicao GNU/Linux convencional fica no ¸˜ ¸˜ diret´ rio /usr/include.s ser´ gerado.´ CAPITULO 2. a maioria dos programas consistem em v´ rios arquivos de c´ digo.S .o . de forma que um programa sendo compilado possa realizar a verificacao de ¸˜ ¸˜ sintaxe e tipos corretamente. a a • Montagem: $ gcc -c teste.c. AMBIENTE DE DESENVOLVIMENTO • Compilacao: ¸˜ $ gcc -S teste. 2.c O GCC interpreta os arquivos de acordo com a sua extens˜ o.o.c arquivo2. Algumas destas est˜ o ¸˜ a listadas na Tabela 2. j´ em linguagem assembly da arquitetura.a .c Gera o arquivo execut´ vel teste. como o -c e -o. • Ligacao: ¸˜ $ gcc -o teste teste.1: Algumas extens˜ es reconhecidas pelo GCC o Extens˜ o a .c.s .2.

• /usr/include/asm: Arquivos contendo as funcoes. a Executa a ligacao usando bibliotecas est´ ticas.c Para retirar os s´mbolos gerados pela opcao -g. ¸˜ ¸˜ ´ 2. ¸˜ Otimiza o c´ digo. chama-se o execut´ vel a partir da shell. ´ Busca bibliotecas primeiro em diretorio. e necess´ rio utilizar a seguinte linha de comando: ´ a $ gcc -g -o teste teste. Neste caso. ı a a • /usr/include/linux: link simb´ lico para o diret´ rio contendo os headers utilizao o dos na vers˜ o do Linux usada para compilar a GNU libc. ı ¸˜ a Desligando recursos do GCC incompat´veis com o padr˜ o ANSI. ´ Liga a biblioteca libnome ao execut´ vel. ¸˜ a Inclui informacoes para o depurador. Para utilizar o depua ´ rador. Emite todas as mensagens de warning. AMBIENTE DE DESENVOLVIMENTO Tabela 2. a ı ¸˜ . ¸˜ • /usr/include/g++: headers para compilar programas C++ que utilizam o compilador GNU C++.2: Algumas extens˜ es reconhecidas pelo GCC o Opcao ¸˜ -o FILE -c -I <diret´ rio> o -L <diret´ rio> o -lnome -static -g. Em alguns casos.out). pode-se utilizar o comando strip(1) com ı ¸˜ a opcao –strip-debug sobre o arquivo bin´ rio (neste caso chamado de teste): ¸˜ a $ strip --strip-debug teste O depurador padr˜ o da GNU e o GDB [GIL 2003]. Busca arquivos de headers primeiro em diretorio. contendo informacoes so¸˜ ¸˜ ´ ´ ¸˜ bre o contexto atual do processo quando o erro ocorreu. Vale ressaltar que esta operacao s´ gera algum dado relevante quando o programa ¸˜ o que gerou esta excess˜ o tiver sido compilado com suporte a s´mbolos de depuracao. parˆ metros e definicoes es¸˜ a ¸˜ pec´ficas arquitetura na qual os bin´ rios gerados ser˜ o criados. sua execucao e abortada e um arquivo core e gerado. e poss´vel passar o arquivo ´ ı core como parˆ metro extra. a Gera somente o objeto (.o). de forma que o depurador salte imediatamente para a instrucao que a ¸˜ causou o erro. Mostra os comandos usados em cada passo da compilacao. A opcao -g do GCC pera ´ u ¸˜ mite que sejam gerados c´ digos de informacao para o depurador. quando o programa est´ sendo executado e realiza uma a operacao ilegal. -ggdb -O -On -ansi -w -Wall -Werror -v 9 Descricao ¸˜ Especifica o nome do arquivo compilado (padr˜ o a. o Estes diret´ rios s˜ o uteis para localizar a definicao de uma funcao que n˜ o apresenta uma o a ´ ¸˜ ¸˜ a man page ou uma info page. Para compilar um programa o ¸˜ com suporte ao uso em um depurador. pois freq¨ entemente erros acontecem. Converte todas as mensagens de warning em erro. Algumas distribuicoes ainda a ¸˜ praticam o erro de apontar para o diret´ rio do kernel Linux atual sendo utilizado no host. o Especifica um n´vel de otimizacao entre 0 e 3 (0 n˜ o otimiza). Um comando que auxilia a localizacao de definicoes e o grep(1). ı a Inibe as mensagens de warning (aviso). o GNU Debugger.3 Utilizando os recursos de debug Estes recursos s˜ o muito uteis. passando o nome do programa a ser depurado a como argumento.´ CAPITULO 2.

. Type "show warranty" for details. onde comandos espec´ficos do GDB poder˜ o ı a ser utilizados para entender o que est´ acontecendo no c´ digo do programa. exit (0).. This GDB was configured as "i686-pc-linux-gnu".2 Copyright 2002 Free Software Foundation. return resultado . resultado = calcula ( a . } int main() { int a . covered by the GNU General Public License. a • Modificar vari´ veis no programa. ¸ A utilizacao padr˜ o do GDB ent˜ o e feita da seguinte maneira. quando o programa tiver encerrado a sua execucao. b = 2.. especificando algum parˆ metro que possa afetar seu comportamento. resultado ). Inc. AMBIENTE DE DESENVOLVIMENTO 10 O GDB pode fazer quatro tipos de operacoes (al´ m de outras operacoes de suporte a estas) ¸˜ e ¸˜ para ajudar a encontrar problemas no c´ digo: o • Parar o programa em uma condicao espec´fica.h> #include <unistd . There is absolutely no warranty for GDB. and you are welcome to change it and/or distribute copies of it under certain conditions. int b) { int resultado . ¸˜ #include <stdio . ¸˜ ı • Iniciar o programa. } Para executar este programa no GDB. printf ( ”Resultado: %d\n” . basta executar a operacao run: ¸˜ $ gdb teste . b . a = 1. O seguinte programa a o ser´ utilizado como exemplo para as explicacoes de operacao do GDB: a ¸˜ ¸˜ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 • Examinar o que houve. resultado = a + b. de forma a poder corrigir os efeitos causados por um a problema e avancar para poder aprender sobre um novo.´ CAPITULO 2. b ). h> int calcula ( int a . (gdb) run . GDB is free software. Type "show copying" to see the conditions. tomando como exemplo um ¸˜ a a ´ programa chamado teste: $ gdb teste GNU gdb 5. resultado .. (gdb) O prompt de comando agora passa a ser (gdb).

poder´amos alterar o valor de ¸˜ ı a para 2. Para isto.c. alterando o resultado da soma. que interrompe a execucao do programa ´ ¸˜ quando uma determinada express˜ o for realizada. que continua executando o programa at´ encontrar uma outra e linha do c´ digo. calcula (a=1.´ CAPITULO 2. para iniciar a execucao passo a passo a partir da funcao ¸˜ ¸˜ ¸˜ calcula. 11 Como n˜ o houve nenhum problema durante a execucao deste programa. ele encerrou e rea ¸˜ tornou ao prompt do GDB. pode-se ¸˜ ¸˜ utilizar o comando next [count]. os comandos “list” e “list -” podem ser usados para listar as pr´ ximas 10 linhas de c´ digo. b=2) at teste.c. No entanto. Uma caracter´stica importante do step o a ı [count] e que ele n˜ o entra em funcoes ou loops: caso haja uma chamada a uma funcao. basta executar: (gdb) break calcula Breakpoint 1 at 0x8048446: file teste. Resultado: 4 Program exited normally. line 7. retornando ent˜ o o controle ao GDB. O GDB permite que o usu´ rio a ` a a modifique o valor de uma vari´ vel com o comando set variable <vari´vel=valor>.c:7 7 resultado = a + b. (gdb) run Starting program: /Users/lucasvr/teste Breakpoint 1. podemos querer executar o programa passo a passo. b=2) at teste. invoca-se o comando break <linha>.c:7 7 resultado = a + b. Para isto. Outra forma bastante utilizada e marcar o breakpoint em detero ´ minadas funcoes. como no exemplo abaixo. AMBIENTE DE DESENVOLVIMENTO Starting program: /Users/lucasvr/teste Resultado: 3 Program exited normally. pode ser informada o e nome da funcao a ser utilizada como breakpoint: ¸˜ (gdb) break calcula Breakpoint 1 at 0x8048446: file teste. (gdb) run Starting program: /Users/lucasvr/teste Breakpoint 1. Ele pode ser usado para verificar quando uma a vari´ vel tem seu valor modificado. (gdb) Outro recurso bastante utilizado e o watchpoint. podea mos utilizar o comando step. calcula (a=1. a o ¸˜ ¸˜ Caso deseja-se ter um controle maior sobre a execucao de funcoes. que segue o fluxo do programa. com o uso do comando continue. ao inv´ s de especificar a linha desejada para o comando break. (gdb) set variable a=2 (gdb) continue Continuing. ou as ultimas 10 linhas de o o ´ c´ digo. loops e switches. a a No caso do breakpoint realizado anteriormente na funcao calcula. de forma progressiva. A partir deste ponto. Para isto. por ´ a ¸˜ ¸˜ exemplo. ou execut´ -lo passo a passo. onde uma mudanca no valor de b e a ¸ ´ a condicao para o retorno do comando ao depurador: ¸˜ . No nosso exemplo. line 7. Para listar o c´ digo sendo depurado e descobrir o a linha que deseja-se utilizar como ponto de parada (breakpoint). podemos continuar a execucao do programa at´ que ele encerre nor¸˜ e malmente. ele ir´ retornar o controle ao GDB apenas ap´ s a execucao completa dessa funcao. Outros comandos interessantes s˜ o os referentes a vari´ veis.

O comando backtrack do GDB imprime os stack frames do processo.´ CAPITULO 2. Assim. Como o programa a ser depurado estar´ em um ponto desconhecido de execucao.c:14 14 a = 1.c:16 16 resultado = calcula (a. e interessante a ¸˜ ´ verificar onde ele encontra-se. a O GDB permite ainda ser anexado a um processo em execucao. resultado = a + b. e cont´ m os argumentos enviados a ela. Cada frame e um dado ´ ı a ´ associado a uma chamada de funcao. iremos anexar o GDB a sua instˆ ncia. o GDB deve ser ¸˜ executado passando o PID do processo como segundo argumento. line 14. int b) { int resultado . AMBIENTE DE DESENVOLVIMENTO (gdb) break main Breakpoint 1 at 0x804846a: file teste. executando o GDB em seguida: $ ps -C teste PID TTY 15247 pts/6 TIME CMD 00:00:00 teste . ¸˜ ¸ ¸˜ a Para fazer um teste. e assim e poss´vel saber onde o programa est´ sendo executado. Para isto. (gdb) watch b Hardware watchpoint 2: b (gdb) continue Continuing./teste Agora. seguindo o nome do programa. Para isto. em outro terminal. } Ap´ s recompilar o programa – n˜ o esquecendo da opcao -g –. iremos execut´ -lo: o a ¸˜ a $ . (gdb) print b $1 = 2 12 Nota-se que o controle e retomado logo ap´ s a execucao da operacao que modificou b. Hardware watchpoint 2: b Old value = 0 New value = 2 main () at teste. A funcao calcula ¸˜ a a ¸˜ dever´ ficar da seguinte forma: a int calcula ( int a . ´ o ¸˜ ¸˜ logo a execucao continua tendo como indicacao a pr´ xima linha a ser executada pelo programa. (gdb) run Starting program: /Users/lucasvr/teste Breakpoint 1.c. modificaremos nosso programa exemplo para que ele faca a leitura ¸ de uma tecla para continuar a execucao. getchar (). ¸˜ ¸˜ o Utilizamos ainda o comando print. return resultado . main () at teste. j´ que ele executa muito r´ pido para podermos anexar o GDB a ele. poderemos depur´ -lo enquanto estiver em ¸˜ a execucao. as vari´ veis locais ` ¸˜ e ` a a esta funcao e o endereco no qual a funcao est´ executando. e necess´ rio obter ` a ´ a o PID do processo. b). que e usado para imprimir o valor de alguma vari´ vel – ´ a neste caso a vari´ vel b.

6 _IO_file_underflow () from /System/Links/Libraries/libc. Agora.6 _IO_default_uflow () from /System/Links/Libraries/libc. mas a ¸˜ n˜ o sabemos ainda onde ele est´ . Caso a funcao seja recursiva. a (gdb) quit $ .´ CAPITULO 2.2.so.6 (gdb) Neste exemplo. ¸˜ A partir deste ponto pode-se retornar ao GDB e encerr´ -lo. Loaded symbols for /System/Links/Libraries/ld-linux. Pode-se ainda utilizar os comandos up [n] e down [n].so. b=2) at teste. podem existir ¸˜ ¸˜ ´ ¸˜ v´ rios frames para a mesma funcao.. Loaded symbols for /System/Links/Libraries/libc.done.c. veremos que nossa modificacao no GDB foi refletida no processo que foi modificado.c:8 8 getchar ().so. e a cada retorno ¸˜ ´ de funcao. ao retornar ao terminal utilizado para disparar o processo teste e pressionar a tecla ENTER. modificar o ` ¸˜ valor da vari´ vel resultado e continuar a execucao do programa: a ¸˜ (gdb) frame 6 #6 0x08048487 in calcula (a=1.done. A partir deste ponto. a ¸˜ Para escolher algum frame espec´fico.2 0x400e76d4 in read () from /System/Links/Libraries/libc.so. iremos modificar o valor do resultado a ser retornado para a funcao main()..6 Esta stack deve ser interpretada a partir do maior valor.so. as funcoes referentes a implementacao desta chamada na GNU libc foram executadas.6 __uflow () from /System/Links/Libraries/libc. como mostrou o backtrace).6 calcula (a=1. pode-se utilizar o comando frame. que indica a base de execucao do ¸˜ programa – neste caso a funcao libc start main().so. AMBIENTE DE DESENVOLVIMENTO 13 $ gdb teste 15247 -silent Attaching to program: /Users/lucasvr/teste.. Para isso.so. process 15247 Reading symbols from /System/Links/Libraries/libc. iremos ¸˜ escolher o frame referente a funcao calcula() (frame 6.so. o processo teste encontrava-se no PID 15247. e finalmente realizando a chamada getchar(). a GNU libc.6 Reading symbols from /System/Links/Libraries/ld-linux. da biblioteca padr˜ o do C.. seguido do n´ mero ı u do frame desejado. na linha 8.so.so. Nota-se que para cada funcao chamada. Nesse ponto temos controle sobre o processo. com o comando quit. b=2) at teste.so.c:8 main () at teste. (gdb) set variable resultado=10 (gdb) continue Continuing. e pode¸˜ ` ¸˜ se verificar que o processo encontra-se aguardando a leitura de algum dado com a chamada de sistema read().6. vamos listar os stack frames do processo: a a (gdb) backtrace #0 0x400e76d4 in #1 0x40146238 in #2 0x40085b63 in #3 0x40087ffd in #4 0x40087e46 in #5 0x4008230a in #6 0x08048487 in #7 0x080484b8 in #8 0x4002cfe4 in read () from /System/Links/Libraries/libc.6 sys_sigabbrev () from /System/Links/Libraries/libc. e este valor foi informado como parˆ metro para a execucao do GDB. chamando a funcao ¸˜ ¸˜ calcula() a seguir. um novo frame e criado.6 getchar () from /System/Links/Libraries/libc. Para modificarmos nosso programa agora.so. Para descobrir.c:17 __libc_start_main () from /System/Links/Libraries/libc. o frame para esta funcao e eliminado. que avancam ¸ ou retrocedem a escolha do frame desejado na stack. ¸˜ a Em seguida a funcao main() foi executada na linha 17 do programa teste.

o • src/: diret´ rio contendo os arquivos fontes do programa. existem dois arquivos Makefile.am. e O processo para gerar arquivos Makefile utilizando estas ferramentas consiste nos seguintes passos: • Escrever um arquivo configure. o • Rodar automake -a -c para gerar um arquivo Makefile. o Automake e utilizado para gerar um o ¸˜ ¸˜ ´ arquivo Makefile a partir das exigˆ ncias feitas pelo Autoconf. • configure. como nome do bin´ rio e ar¸˜ a quivos fontes usados para constru´-lo.in: arquivo a ser gerado pelo programador. existˆ ncia de headers. ı 2. a • COPYING: cont´ m a licenca pela qual o projeto e distribu´do.4. • Rodar aclocal para criar c´ pias locais de macros utilizadas pelo autoconf.in a partir do arquivo Makefile. tamanhos de tipos de vari´ veis. u ı • Makefile. o a partir do diret´ rio base dos fontes do projeto: o • BUGS: listagem dos problemas conhecidos do projeto.am Como visto.am (o automake verifica o arquivo configure.am: o arquivo a ser gerado pelo programador. • Escrever um arquivo Makefile. em arquiteturas diferentes da utilizada pelo programador. • FAQ: perguntas freq¨ entemente feitas a respeito de alguma caracter´stica do programa. A estrutura utilizada em projetos GNU segue a seguinte hierarquia de arquivos e diret´ rios. pois muitas o ¸˜ a vezes os programas rodam nas plataformas mais diversas. O conte´ do dele normalo e ¸˜ u mente e: ´ AUTOMAKE_OPTIONS = foreign gnu SUBDIRS = src EXTRA_DIST = BUGS COPYING ChangeLog INSTALL README FAQ . e de formas de submeter bugs encontrados pelo usu´ rio. ı • NEWS: cont´ m novidades sobre o programa. e o ¸˜ • INSTALL: processo de instalacao do programa. Estas verificacoes s˜ o importantes. O Autoconf e respons´ vel por realizar uma s´ rie de checagens no host. como seu prop´ sito e formas de contato com ¸˜ o o autor e/ou mailing lists.am: regras de compilacao dos fontes. O que reside no diret´ rio raiz do projeto ino forma os subdiret´ rios que cont´ m os fontes e algumas opcoes extras. e ¸ ´ ı • ChangeLog: cont´ m um hist´ rico com modificacoes realizadas no projeto. informando alguns dados importantes para que o arquivo Makefile seja constru´do. e • README: informacoes sobre o programa. contendo verificacoes que ¸˜ devem ser feitas antes de compilar o programa. Ap´ s a realizacao destas verificacoes. ¸˜ • AUTHORS: arquivo contendo os nomes dos autores do projeto. ´ a e como a vers˜ o do compilador.´ CAPITULO 2.am. AMBIENTE DE DESENVOLVIMENTO 14 2.in.4 Autoconf e Automake O Autoconf e Automake s˜ o duas ferramentas que auxiliam o programador a gerar arquivos a Makefile para o projeto. • Rodar autoconf para gerar o script configure. entre muitos outros.in para obter informacoes sobre o pro¸˜ jeto). bibliotecas a a e (bem como suas vers˜ es). o • src/Makefile. • include/: diret´ rio contendo os arquivos headers do programa.1 Escrevendo um arquivo Makefile.

• gnu: verifica se o projeto inclui os arquivos exigidos pelo GNU standards para pacotes de software.h]) # Checks for programs. a O campo SUBDIRS informa diret´ rios onde residem arquivos fontes do programa.c arquivo2. a pr´ xima etapa e a criacao de um arquivo configure. AC_PREREQ(2.Autoconf -*# Process this file with autoconf to produce a configure script. AC_HEADER_STDC AC_CHECK_HEADERS([stdlib. stdin.am interno ao diret´ rio src/ pode conter informacoes complexas com o ¸˜ regras que devem ser utilizadas para cada arquivo. • no-dependencies: usado em situacoes onde n˜ o existem informacoes suficientes para ¸˜ a ¸˜ fazer a deteccao autom´ tica de dependˆ ncias no pacote.c no diret´ rio src/ com um o printf e dois includes. este e o resultado gerado pelo autoscan: ´ # -*. Ap´ s renomeado para cono figure. a ´ e Ele examina os arquivos fonte a partir do diret´ rio corrente. recursivamente. algumas mudancas devem ser feitas.h e unistd. Para uma estrutura contendo apenas um arquivo chamado teste. VERSION. e aconselha-se a leitura da info page do automake para ¸˜ a consult´ -las. structures.2 Escrevendo um arquivo configure. BUG-REPORT-ADDRESS) AC_CONFIG_SRCDIR([src/teste.c]) AC_CONFIG_HEADER([config.in A maneira mais f´ cil de gerar um arquivo configure.h. and compiler characteristics. como informar o nome e vers˜ o do projeto. e-mail ¸ a para reportar bugs. e gera um arquivo o configure. # Checks for header files.´ CAPITULO 2.57) AC_INIT(FULL-PACKAGE-NAME. AMBIENTE DE DESENVOLVIMENTO O campo AUTOMAKE OPTIONS aceita alguns n´veis.in. e EXo TRA DIST informa que os arquivos ali listados devem ser ignorados pelo automake e pelo autoconf. O arquivo Makefile.in e atrav´ s do comando autoscan(1). ¸˜ a e As opcoes suportadas s˜ o muitas.scan base no qual pode ser gerado o arquivo configure.in. entre outros.in.h]) # Checks for typedefs. AC_PROG_CC # Checks for libraries. # Checks for library functions. o o ´ ¸˜ 2.4. .sample Ap´ s gerar estes arquivos. mas no entanto o seguinte e suficiente para ´ gerar pacotes com estas ferramentas: bin_PROGRAMS = Programa Programa_SOURCES = arquivo1.c EXTRA_DIST = config.c arquivo3. dentre os quais: ı 15 • foreign: verifica se o projeto est´ de acordo com os padr˜ es exigidos para distribuir o a o software.

in e Makefile. o que frustra a ´ a a a maioria dos usu´ rios iniciantes em GNU/Linux e n˜ o permite que toda a potencialidade do a a debugger seja aproveitada em sua totalidade. foi desenvolvido o DDD [ZEL 2000].am. Para suprir tal dificuldade. configure. o mesmo ainda continua o sendo um mero front-end para o debugger da GNU.5 .Data Display Debugger Apesar do GDB ser um poderoso debugger. como pode ser visto na janela inferior da Figura 2. como matrizes e arrays. sendo at´ poss´vel com ele debuggar o pr´ prio e ı o kernel do sistema operacional.5 DDD .1: Operando com o DDD sobre o programa exemplo Vale notar que mesmo com todas as extens˜ es do DDD ao GDB. automake e autoconf. Um exemplo de a a operacao do DDD pode ser visto na Figura 2. permitindo que e o gr´ ficos sejam plotados a partir do valor de vari´ veis. o DDD possui ainda extens˜ es ao processo de debugging tradicional.5 ¸˜ Figura 2. que e simplesmente uma ´ interface gr´ fica para o debugger. a Por´ m. a sua interface em linha de comando n˜ o e amig´ vel para usu´ rios pouco familirizados com a ferramenta. como explicado anteriormente. 2. sendo poss´vel executar todos os comandos ı do GDB na janela no final da janela principal do DDD. assim com aplicativos multi-threaded. AMBIENTE DE DESENVOLVIMENTO 16 AC_CONFIG_FILES([Makefile src/Makefile]) AC_OUTPUT Ap´ s preparados estes dois arquivos.´ CAPITULO 2. o projeto pode ser gerado o executando aclocal.

que est˜ o dispon´veis em ambos. o servidor Apache e o servidor XFree86. pode-se usar a flag -ansi do GCC ı para restringir as funcoes usadas as definidas e suportadas pelo ANSI. de forma a mapear nomes de dispositivos existentes apenas no GNU/Linux para o Windows. Ele consiste de uma camada de bibliotecas que atuam como wrappers.com . o usando um ambiente no Windows chamado Cygwin1 . e evitar ao m´ ximo o uso de funcoes ¸˜ a ı a ¸˜ espec´ficas de um determinado sistema operacional.cygwin. a biblioteca GTK+. entretanto. 1 ver http://www. Uma grande variedade de bibliotecas e interfaces e aplicativos j´ encontram suporte neste a ambiente. Assim. E bastante comum isolar c´ digos ¸˜ o especificos de uma determinada arquitetura ou sistema operacional desta forma. Por exemplo: # if defined ( linux ) # define DIR SEPARATOR ’\\’ # else if defined ( WIN32) # define DIR SEPARATOR ’/’ #endif Existe ainda uma forma de portar c´ digo nativo criado no GNU/Linux para o Windows. AMBIENTE DE DESENVOLVIMENTO 17 2. isto n˜ o e poss´vel. e ent˜ o pode ser necess´ rio utilizar diretivas a ´ ı a a ´ de compilacao #ifdef para verificar o sistema em uso. apenas alguns cuidados que devem ser atendidos. como bibliotecas de threads. SCSI e seriais. ¸˜ ` Em alguns casos.´ CAPITULO 2.6 Criando aplicativos que rodem tanto no GNU/Linux como no Windows N˜ o existe nenhuma regra espec´fica a ser seguida para executar o mesmo c´ digo em sistemas a ı o operacionais diferentes. como dispositivos IDE. entre outros. O mais comum e ape´ nas utilizar funcoes ANSI.

h> int 18 . h> int main ( int argc . que o a s˜ o o argv. i++) printf ( ”Argumento %d: %s\n”. } Este programa ir´ imprimir a quantidade de argumentos recebidos.Cap´tulo 3 ı Explorando os recursos b´ sicos a do sistema operacional 3. podemos escrever um programa chamado soma que receber´ os ¸˜ a parˆ metros 1 e 2 que ser˜ o passados via linha de comando: a a $ soma 1 2 Estes parˆ metros s˜ o passados para o programa atrav´ s dos argumentos da funcao main(). a a e ¸˜ O m´ dulo principal do programa (main) pode receber dois parˆ metros externos opcionais. um vetor de ponteiros para strings. existir´ apenas uma a a a string no array (no ´ndice 0).1 Lendo parˆ metros curtos e longos passados pela linha a de comando Em “C” e poss´vel a um programa coletar parˆ metros passados na linha de comando no mo´ ı a mento de sua ativacao. que indica a quantidade de strings a contidas neste array. e argc ter´ o valor 1. i. argv[ i ]). e o argc. e comum encontrar o seguinte tipo de c´ digo: a ´ o 1 2 3 #include <stdio . for ( i = 0. ı a Tomando por exemplo o programa soma. E normal que os programas realizem a consistˆ ncia a e dos parˆ metros recebidos. printf ( ”Numero de argumentos: %d\n”.h> #include <unistd . e em seguida ir´ mostrar a a ´ cada argumento recebido como parˆ metro. Caso um programa n˜ o receba nenhum parˆ metro. Dessa forma. exit (0). char ∗∗argv) { int i . argc ). poder´amos escrevˆ -lo da seguinte forma: ı e 1 2 3 4 5 6 7 8 9 10 11 12 #include <stdio . i < argc . contendo o nome do programa executado. Assim.

Os caracteres deste elemento (fora o “-” inicial) s˜ o caracteres de opcao.h> como: struct option { const char ∗name. em optarg. (A opcao -W e reservada pelo POSIX.2 provˆ uma funcao para tratar argumentos de entrada. } } O padr˜ o POSIX. O seguinte prot´ tipo a define: a o #define GNU SOURCE #include <getopt . a ´ ¸˜ optstring e uma string contendo os caracteres de opcao leg´timos. extern char ∗optarg . h> int getopt ( int argc . . EXPLORANDO OS RECURSOS BASICOS DO SISTEMA OPERACIONAL19 4 5 6 7 8 9 10 main ( int argc . Se tal caractere e seguido ´ ¸˜ ı ´ por dois-pontos. ele retorna sucessivamente cada um dos caracteres de opcao de cada ´ ¸˜ um dos elementos de opcao. iniciadas por dois tracos. respectivamente. Nomes de opcoes longas podem ser abreviados se a ¸˜ ¸ ¸˜ abreviacao for unica ou se iguala exatamente a alguma opcao definida. ¸˜ Um elemento de argv que inicia com “-” (e n˜ o e exatamente “-” ou “–”) e um elemento de a ´ ´ opcao. Neste caso. A funcao getopt(3) analisa os argumentos da linha de comando.2 para extens˜ es de implementacao. int ∗ longindex ). char ∗ const argv []. ele e retornado em optarg. Uma opcao longa pode ¸˜ ´ ` ¸˜ ¸˜ requerir um parˆ metro da forma –arg=param ou –arg param. Esta e uma ex´ a ´ ´ tens˜ o GNU. Se getopt(3) ¸˜ a ¸˜ e chamado repetidamente. longopts e um ponteiro para o primeiro elemento de um array de struct option. }. ou para o texto do elemento seguinte de argv.) ¸˜ ¸˜ ´ o ¸˜ Este comportamento e uma extens˜ o GNU. char ∗ const argv []. ela retorna este caractere. argv [0]). exceto que ele tamb´ m aceita ¸˜ e opcoes longas. Seus argumentos argc e ¸˜ argv s˜ o.´ ´ CAPITULO 3. Ent˜ o optind e o ´ndice em a a ¸˜ a ´ ı argv do primeiro elemento de argv que n˜ o e uma opcao. o getopt(3). a contagem de argumentos e o array de strings passados para a funcao a ¸˜ main() na invocacao do programa. ¸˜ ¸˜ atualizando a vari´ vel externa optind e uma vari´ vel est´ tica nextchar de forma que a pr´ xima a a a o chamada a getopt(3) pode continuar a busca com o caractere de opcao seguinte ou um ele¸˜ mento de argv. optopt . a opcao requer um argumento. char ∗∗argv) { if ( argc != 3) { fprintf ( stderr . getopt(3) retorna −1. const char ∗ optstring ). opterr . Se n˜ o h´ mais caracteres de opcao. int has arg . caso contr´ rio optarg e zerado. int ∗ flag . Se optstring cont´ m W seguido de um ponto-e-v´rgula. ¸˜ Se a funcao getopt(3) encontra um outro caractere de opcao. ´ declarado em <getopt. Dois dois-pontos significam que uma opcao recebe um argumento opcional. ent˜ o getopt atribui um ponteiro para o texto ¸˜ a que segue no mesmo elemento de argv. extern int optind . exit (1). const char ∗ optstring . se h´ texto no ¸˜ a elemento de argv atual. ”Sintaxe: %s valor1 valor2 \n” . h> int getopt long ( int argc . const struct option ∗ longopts . ent˜ o -W foo e tratado como a e ı a ´ a opcao longa –foo. int val . A funcao getopt long(3) funciona como getopt(3). n˜ o dispon´vel em bibliotecas anteriores a GNU libc ´ a a ı ` 2. a e ¸˜ definida pelo seguinte prot´ tipo: o #include <unistd .

0. if ( optarg ) printf ( ” com argumento %s”. required argument ¸˜ a (ou 1) se a opcao requer um argumento. a ¸˜ ´ a ent˜ o getopt long(3) retorna val. ´ a • nome: e o nome da opcao longa. ’c’ }. c = getopt long ( argc . case ’a’ : printf ( ”opcao a\n”). char ∗∗argv) { int c. & option index ). 1. 0. 0}. 0} }.´ ´ CAPITULO 3. 0}. {0. 0.h> #include <unistd . if ( c == −1) break. 0. int main ( int argc . h> #define GNU SOURCE #include <getopt . 0. Se flag e NULL. long options . • flag: especifica como os resultados s˜ o retornados para uma opcao longa. 1. 0}. ´ • val: e o valor a retornar. {” create ” . ¸˜ a ´ O ultimo elemento do array deve ser preenchido com zeros. {”verbose” . case ’b’ : . break. ou a ´ ¸˜ ´ deixada intocada se a opcao n˜ o e encontrada. ou optional argument (ou 2) se a opcao recebe ¸˜ ¸˜ um argumento opcional. {”append”. name). ”abc:d:” . 0. 0. getopt long(3) retorna 0. 1. Caso contr´ rio. while (1) { int option index = 0. 1. printf ( ”\n”). optarg ). e a flag aponta para uma vari´ vel. ´ ¸˜ O seguinte exemplo ilustra o uso de getopt long(3) com a maioria de seus recursos: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <stdio . 0. 0}. long options [ option index ]. EXPLORANDO OS RECURSOS BASICOS DO SISTEMA OPERACIONAL20 O significado destes campos s˜ o: a • has arg: no argument (ou 0) se a opcao n˜ o recebe um argumento. argv . {” file ” . ou a carregar para a vari´ vel apontada por flag. break. switch ( c ) { case 0: printf (”opcao %s”. a qual e ajustada para val se a opcao e encontrada. {” delete ” . 0. 0. h> static struct option long options [] = { {”add” . 0}.

Tanto descritores de arquivos como streams podem representar uma conex˜ o a ı a um dispositivo (como um terminal). e est˜ o declaradas no arquivo header stdio. representados por objetos do tipo FILE *. ( ”opcao c com valor ‘%s’\n” . ( ” erro : getopt retornou %d\n”. Os descritores de arquivos s˜ o usados quando e a ´ necess´ rio realizar operacoes de controle sobre algum dispositivo espec´fico.´ ´ CAPITULO 3. u ainda para representar um arquivo normal. } exit (0). } 3.3 Streams Quando a funcao main do programa e invocada. optarg ). ou streams. ou ainda quando a ¸˜ ı precisam realizar I/O em modos especiais.2 Trabalhando com arquivos Arquivos em C podem ser manipulados com o uso de descritores de arquivos. como n˜ o-bloqueante. optarg ). pois nem a a todas as operacoes sobre descritores de arquivos est˜ o implementadas em outros sistemas opera¸˜ a cionais – sobretudo o conjunto de operacoes GNU. bem como funcoes orientadas a e ¸˜ ¸˜ ¸˜ ¸˜ caracter e linhas. case ’c’ : printf break. e muito mais rico e que as facilidades cor¸˜ ¸˜ ´ respondentes para os descritores de arquivos. ı A maior vantagem de utilizar a interface de streams e que o conjunto de funcoes para realizar ´ ¸˜ operacoes de I/O. case ’d’ : printf break. Descritores de arquivos provˆ em uma interface primitiva e de baixo-n´vel para operacoes de e ı ¸˜ entrada e sa´da. case ’?’ : break.1 a 3. apesar de que grande parte delas encontram¸˜ se no padr˜ o POSIX 1. ( ”opcao d com valor ‘%s’\n” . default : printf } } ( ”opcao b\n”). dado que streams n˜ o oferecem a a recursos de baixo n´vel. if ( optind < argc ) { printf ( ”parametros nao referentes a opcoes : ” ). ela j´ disponibiliza trˆ s streams abertas e ¸˜ ´ a e prontas para o uso. que e a origem normal de entrada de dados ´ a ´ em um programa. . ou um pipe ou socket para comunicar com outro processo.h: a • FILE *stdin: e a stream de entrada padr˜ o. A interface de descritores de arquivos provˆ apenas e operacoes simples para transferˆ ncia de blocos de caracteres. Elas representam os canais standard de entrada e sa´da que foram estaı belecidos para o processo. argv[ optind ++]). ´ E importante ressaltar que streams s˜ o mais port´ veis que descritores de arquivos. ao oposto de operacoes de controle. c ). EXPLORANDO OS RECURSOS BASICOS DO SISTEMA OPERACIONAL21 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 printf break. representados por objetos do tipo int. while ( optind < argc ) printf ( ”\t%s\n”. enquanto a interface de streams ¸˜ e provˆ funcoes poderosas para formatacao de funcoes de I/O.

int size. Se um e o caracter de nova linha for lida. que e usada para imprimir os dados de sa´da do ´ a ı ´ ı programa. A stream e ´ posicionada no in´cio do arquivo. escreve a string s para stream. com o ı a uso da operacao fflush(3). que j´ deve e a estar pr´ -alocado. desassocia a stream “stream” do arquivo ao qual ela estava operando. testa o indicador de fim-de-arquivo para a stream apontada por “stream”. • int feof (FILE *stream). EXPLORANDO OS RECURSOS BASICOS DO SISTEMA OPERACIONAL22 • FILE *stout: e a stream padr˜ o de sa´da. lˆ nmemb elementos de dados. a ´ – a+: abre o arquivo para leitura e append. const char *mode). ´ A string modo pode ainda incluir a letra “b” ap´ s indicar o modo desejado para explicitar o que o arquivo a ser trabalhado ser´ bin´ rio. a • int fclose (FILE *stream). ou ´ a truncado caso contr´ rio. forca a escrita de todos os dados em espaco de usu´ rio que estejam mantidos em buffer ¸ ¸ a para a sa´da informada ou atualizam a stream “stream” atrav´ s da funcao write associada ı e ¸˜ a ela. retornando um valor n˜ o-zero caso este indicador esteja setado. e a stream ´ a e posicionada no final do arquivo. FILE *stream). a partir da stream e apontada por stream. e armazenando-os no local apontado por ptr. abre o arquivo apontado pela string “path” e retorna uma stream associada a ele. a ´ ı – a: abre o arquivo para append (escrita no final do arquivo). Apesar de n˜ o ter efeito em um a a a a programa que ir´ operar no GNU/Linux. • int fputs (const char *s. e a stream e posicionada no final do arquivo. A leitura encerra ap´ s encontrar EOF ou uma nova linha. examina o argumento “stream” e retorna um inteiro relativo ao seu descritor de arquivo. ela e muito importante caso o programa ir´ rodar a ´ a em algum ambiente n˜ o-UNIX. – w: trunca o arquivo para zero bytes e cria o arquivo texto para escrita. FILE *stream). • FILE *stderr: da mesma forma que a stream stdout. Um caracter “ ´ 0” e armazenado ap´ s o ultimo caracter do buffer. Caso a stream estivesse sendo usada para dados de sa´da. . FILE *stream). fread retorna o n´ mero de itens lidos ¸˜ a u com sucesso. os dados em buffer s˜ o escritos antes. A stream e posicionada no in´cio do arquivo. posicionando a stream no in´cio do ı arquivo. a a • int fileno (FILE *stream). O arquivo e criado caso ele n˜ o exista. size t size. Ele e criado caso ele n˜ o exista. size t nmemb. Os seguintes modos s˜ o utilizados para abrir o arquivo: a – r: abre um arquivo texto para leitura. • char *fgets (char *s. Esta operacao costuma ¸˜ ser utilizada para operacoes em arquivos bin´ rios. e n˜ o texto. ´ o ´ • size t fread(void *ptr.´ ´ CAPITULO 3. lˆ size caracteres a partir de stream e os armazena no buffer apontado por s. ı – w+: abre o arquivo para leitura e escrita. ele e armazenada no buffer. sem o caracter “ 0” de final de string. o Algumas das operacoes mais comuns de serem realizadas sobre streams s˜ o: ¸˜ a • FILE *fopen (const char *path. ou 0 caso ainda n˜ o seja fim de arquivo. por´ m para imprimir mensagens de e erro e de diagn´ stico pelo programa. Ele e criado caso ele ´ n˜ o exista. ¸˜ • int fflush (FILE *stream). ı – r+: abre um arquivo texto para leitura e escrita. posicionando a stream no in´cio do arquivo. cada um tendo o tamanho de size bytes.

long offset. while (! feof ( stream origem )) { fgets ( buffer . 0L. } /∗ processa linhas do arquivo origem ∗/ i = 1. fwrite retorna o n´ mero de itens ¸˜ a u escritos com sucesso. • int fseek (FILE *stream. aponta o indicador de posicao de arquivo para a stream apontada por stream para o in´cio ¸˜ ı do arquivo. a posicao corrente do indicador ou ´ ı ` ¸˜ ao final do arquivo. escrevendo apenas as linhas pares para o segundo. escreve nmemb elementos de dados. char ∗ destino ) { FILE ∗stream origem. h> int copia arquivo ( char ∗origem . ”w”). Esta operacao costuma ¸˜ ser utilizada para operacoes em arquivos bin´ rios. return −1. Ela e equivalente a executar a funcao fseek (stream. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <stdio . A nova ¸˜ posicao. medida em bytes. if (! stream destino ) { perror ( ”fopen” ). int i . stream destino ). criando este ultimo ∗/ stream origem = fopen ( origem . • long ftell (FILE *stream). e ¸˜ • void rewind (FILE *stream). stream origem ). Caso whence seja definido como SEEK SET. ´ ` ¸˜ O programa a seguir ilustra o uso destas operacoes: ele abre um arquivo para leitura e um ¸˜ outro para escrita.´ ´ CAPITULO 3. int whence). posiciona o indicador de posicao de arquivo para a stream apontada por stream. respectivamente.h> #include <unistd . size t size. ∗ stream destino . sizeof ( buffer ). return −1. size t nmemb. SEEK CUR ou SEEK END. char buffer [1024]. fclose ( stream origem ). EXPLORANDO OS RECURSOS BASICOS DO SISTEMA OPERACIONAL23 • size t fwrite (const void *ptr. para a stream apontada por stream. /∗ abre arquivos de origem e destino . obt´ m o valor atual do indicador de posicao de arquivo para a stream apontada por stream. } stream destino = fopen ( destino . FILE *stream). . ”r” ). if ( i % 2 == 0) /∗ numero par ∗/ fputs ( buffer . o offset e relativo ao in´cio do arquivo. e obtida atrav´ s da soma de offset bytes para a posicao es¸˜ ´ e ¸˜ pecificada por whence. obtidos a partir do local apontado por ptr. if (! stream origem ) { perror ( ”fopen” ). cada um tendo o tamanho de size bytes. SEEK SET).

retornando um descritor de arquivo representado por um inteiro. que requisitam a abertura do arquivo no modo somente leitura. e ı respectivamente). a – O TRUNC: caso o arquivo esteja sendo aberto em modo de escrita em conjunto com este modo. ou leitura e escrita.4 Descritores de Arquivos Assim como quando operando sobre streams. argv [0]). Neste caso. } /∗ fecha as streams e retorna ∗/ fclose ( stream origem ). a a As operacoes b´ sicas sobre descritores de arquivos s˜ o: ¸˜ a a • int open(const char *pathname. } 3. dispositivos de rede. int flags). fclose ( stream destino ). if ( argc != 3) { printf ( ”Sintaxe: %s <arq origem> <arq destino>\n”. quando utilizando descritores de arquivos temos os trˆ s canais de entrada e sa´da abertos automaticamente (stdin. dentre as quais est˜ o: ¸˜ a – O CREAT: se o arquivo n˜ o existe. Ou ´ ´ seja. exit (1). o prot´ tipo da a a o funcao open listado abaixo ser´ utilizado. } int main ( int argc . a . Um conceito importante e o de que em sistemas operacionais UNIX. EXPLORANDO OS RECURSOS BASICOS DO SISTEMA OPERACIONAL24 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 i++. ou 0. o arquivo ser´ truncado para 0 bytes. ele ser´ criado. As flags devem ser O RDONLY. abre o arquivo especificado por pathname. } exit (0). Desta forma e poss´vel manipular todos os disposia a ´ ı tivos do sistema com o uso de operacoes sobre arquivos: por isto as operacoes sobre descritores ¸˜ ¸˜ de arquivos s˜ o t˜ o importantes. return 0. exit (1). argv [2]). diret´ rios e os pr´ prios arquivos de dados ı o o do usu´ rio s˜ o representados por arquivos. 1 e 2. de terminais. v´deo. a funcao a ¸˜ retornar´ um erro. ”Um erro ocorreu durante a copia\n”). de som. respectivamente. somente escrita. Estes modos podem ser combinados via bitwise OR com zero ou mais opcoes. if ( res < 0) { fprintf ( stderr . char ∗∗argv) { int res . ¸˜ a – O EXCL: quando usado em conjunto com O CREAT e o arquivo j´ existir. } res = copia arquivo ( argv [1].´ ´ CAPITULO 3. tudo e um arquivo. stdout e stderr. O WRONLY ou O RDWR.

/∗ /∗ /∗ /∗ atoi (3) open (2) open (2) open (2) ∗/ ∗/ ∗/ ∗/ . – O DIRECTORY: caso pathname n˜ o seja um diret´ rio. O valor retornado informa quantos bytes foram escritos com sucesso. – O NOFOLLOW: caso pathname seja um link simb´ lico. • ssize t write(int fd. para adicionar novos dados ao final do arquivo. lˆ at´ count bytes a partir da posicao corrente do arquivo representado pelo descritor fd e e ¸˜ para o buffer apontado por buf. void *buf. ¸˜ ´ O exemplo abaixo lida com um arquivo bin´ rio atrav´ s de descritores de arquivos. escreve at´ count bytes no arquivo representado pelo descritor fd a partir do buffer apone tado por buf. este prot´ tipo dever´ ¸˜ o a ser utilizado. float valor .h> #include <sys/ stat . size t count). ´ e u 1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio . fildes e refere-se ao descritor de arquivo que ser´ utilizado na operacao de seek. fecha o descritor de arquivo indicado por fd. Entre as informacoes retornadas. • off t lseek(int fildes. h> #include < stdlib . a • int fstat(int filedes. por´ m sobre descritores de arquivos. struct stat *buf).´ ´ CAPITULO 3. ou -1 em caso de erro. off t offset. EXPLORANDO OS RECURSOS BASICOS DO SISTEMA OPERACIONAL25 – O APPEND: abre o arquivo no modo append. e em seguida lˆ e imprime o seu conte´ do. Algumas outras operacoes costumam ser realizadas sobre descritores de arquivos. caso o modo O CREAT seja passado como flag para a funcao open. entre outros.h> #include <sys/ fcntl . offset informa a ¸˜ quantos bytes ser˜ o movimentados na operacao e whence informa a posicao relativa a a ¸˜ ¸˜ ` qual ser´ feito o seek. est˜ o a ¸ ¸˜ a quantidade de hard links feitas para este arquivo. Podemos ¸˜ destacar: • ssize t read(int fd. }. Neste a e exemplo.h> struct informacao { int quantidade . retorna informacoes sobre o arquivo representado pelo descritor filedes. a chamada retorna um erro. int whence). mode t mode). ou -1 em caso de erro. a data de ultima ´ alteracao e de ultimo acesso. size t count). a chamada e interrompida o ´ e retorna um erro. int flags. o seu inode number. ele adiciona um novo campo do mesmo tipo de estrutura da qual ele e composto ap´ s ´ o seu ultimo byte de dados. para explicitar o modo no qual o arquivo ser´ aberto. a o • int open(const char *pathname. opera da mesma forma que o fseek(3). esta funcao e equivalente a chamada open com as flags iguais a O CREAT | O WRONLY ¸˜ ´ ` | O TRUNC. mode t mode). O valor retornado informa quantos bytes foram lidos com sucesso.h> #include <unistd . Maiores informacoes a ¸˜ sobre os parˆ metros podem ser consultados na p´ gina manual do open(2). char nome[128]. a a • int creat(const char *pathname. armazenando-as ¸˜ no endereco da struct stat apontada por buf. const void *buf. • int close(int fd). h> #include <sys/ types .

info . lseek ( fd . n = write ( fd. sizeof ( info . 0. char ∗arquivo ) { ssize t n. struct informacao info . 0. ”arquivo %s” . valor = 123. } void le arquivo ( int fd ) { size t n. } } void adiciona entrada ( int fd . char ∗∗argv) { . arquivo ).45 ∗ ( float ) num. SEEK END). } int main ( int argc .nome. if ( n < 0) perror ( ” write” ). int num. valor . EXPLORANDO OS RECURSOS BASICOS DO SISTEMA OPERACIONAL26 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 int cria arquivo ( char ∗nome) { int fd . sizeof ( info )). info . S IRWXU | S IRWXG | S IRWXO). fd = open (nome. O RDWR | O CREAT | O TRUNC. info . info . quantidade ). struct informacao info . sizeof ( info )). if ( n == 0) { /∗ fim de arquivo ∗/ break. & info . snprintf ( info . if ( fd < 0) { perror ( ”open”).nome. info . SEEK SET). & info . quantidade = 10 ∗ num.´ ´ CAPITULO 3.nome). } return fd . while (1) { n = read ( fd. num = atoi ( numero). char ∗numero. } printf ( ”nome: %s\nvalor: %f\nquantidade: %d\n\n”. lseek ( fd . exit (1).

´ ´ CAPITULO 3. EXPLORANDO OS RECURSOS BASICOS DO SISTEMA OPERACIONAL27
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

int fd ; if ( argc != 3) { fprintf ( stderr , ”Sintaxe: %s <arquivo destino > <algum numero>\n”, argv[0]); exit (1); } fd = open ( argv [1], O RDWR); if ( fd < 0) { perror ( ”open”); printf ( ”tentando criar arquivo ...\ n\n”); fd = cria arquivo ( argv [1]); } adiciona entrada ( fd , argv [2], argv [1]); le arquivo ( fd ); close ( fd ); exit (0); }

Cap´tulo 4 ı

CGI: Common Gateway Interface
O CGI define uma maneira de interacao entre o web browser e programas externos de geracao ¸˜ ¸˜ de conte´ do, normalmente referidos como programas CGI ou scripts CGI. u Existem duas principais diferencas entre criar um programa convencional e um CGI. Primeira¸ mente, toda a sa´da do programa CGI deve ser precedida por um header do tipo MIME. Isto e ı ´ um cabecalho HTTP que informa ao client o tipo de conte´ do que ele est´ recebendo. Na maior ¸ u a parte do tempo, o conte´ do ser´ : u a Content-type: text/html Em segundo lugar, toda a sa´da precisa estar formatada em HTML ou em algum outro forı mato que o browser ser´ capaz de mostrar. Na maior parte do tempo isto e HTML, mas ocasioa ´ nalmente poder´ ser necess´ rio escrever algum programa que gere a sa´da de uma imagem GIF a a ı ou algum outro conte´ do n˜ o-HTML. u a Fora estes dois detalhes, um programa em CGI parece-se com um programa convencional qualquer. O exemplo abaixo lista o conte´ do de um arquivo texto: u
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

#include <stdio .h> #include <unistd . h> #define ARQUIVO ”/tmp/teste.txt” int main ( int argc , char ∗∗argv) { char buffer [256]; FILE ∗fd; printf (”Content−type: text /html\r\r\n\n”); printf (”<html><head><title> Conteudo do arquivo %s </title></head>\n”, ARQUIVO); fd = fopen ( ARQUIVO, ”r”); if (! fd ) { printf ( ”<b> ERRO </b>: arquivo %s ano existe\n”, ARQUIVO); ˜ printf (”</body></html>\n”); exit (1);

28

´ CAPITULO 4. CGI: COMMON GATEWAY INTERFACE
22 23 24 25 26 27 28 29 30 31 32 33

29

} while (! feof ( fd )) { fgets ( buffer , sizeof ( buffer ), fd ); printf ( ”%s <br>\n”, buffer); } fclose ( fd ); printf (”</body></html>\n”); exit (0); } Ap´ s a compilacao do programa, basta copi´ -lo para o diret´ rio cgi-bin do Apache, ou o ¸˜ a o do httpd em uso, e acess´ -lo via browser, como no exemplo abaixo: a http://localhost/cgi-bin/teste No entanto, e bastante comum o uso de alguma biblioteca para facilitar a formatacao dos ´ ¸˜ dados em HTML, para evitar erros e agilizar o desenvolvimento do programa CGI. Existem v´ rias bibliotecas dispon´veis cadastradas no site da Freshmeat1 . a ı

1 ver

http://www.freshmeat.net

Cap´tulo 5 ı

Bibliotecas dinˆ micas a
O objetivo de bibliotecas dinˆ micas e a centralizacao de implementacao de funcoes em bibliotea ´ ¸˜ ¸˜ ¸˜ cas espec´ficas, permitindo que o gerenciamento e atualizacao das mesmas se torne propag´ vel ı ¸˜ a a todos os programas que usam suas funcoes de forma trivial. ¸˜ No GNU/Linux, existe o conceito de shared objects, que e an´ logo ao conceito de DLL do ´ a Microsoft Windows. Para utilizar bibliotecas dinˆ micas no GNU/Linux, se usam as funcoes dlopen(3) e a ¸˜ dlclose(3). Para carregar os s´mbolos das funcoes a serem utilizadas a funcao dlsym(3) ı ¸˜ ¸˜ deve ser utilizada. Um exemplo do uso de bibliotecas dinˆ micas pode ser visto a seguir: a
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

#include <stdio .h> #include <dlfcn .h> int main ( int argc , char ∗∗argv) { void ∗ biblioteca ; double (∗seno )(double); char ∗ erro ; biblioteca = dlopen ( ”libm.so” , RTLD LAZY); if (! biblioteca ) { fprintf ( stderr , ”%s\n”, dlerror ()); exit (1); } seno = dlsym ( biblioteca , ” simbolo nao existe ” ); if (( erro = dlerror ()) != NULL) { fprintf ( stderr , ”%s\n”, erro ); exit (1); } printf ( ”%f\n”, (∗seno )(2.0)); dlclose ( biblioteca ); exit (0); } Existem basicamente 2 modos para resolucao dos s´mbolos disponibilizados por uma bi¸˜ ı ¸˜ a blioteca: RTLD LAZY, que significa que os ponteiros para funcoes n˜ o resolvidos em tempo de

30

so” . exit (1).1 Criacao de bibliotecas dinˆ micas ¸˜ a Para criar bibliotecas dinˆ micas no GNU/Linux o processo e simples: basta compilar o c´ digo a ´ o com a flag -shared. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <stdio . } Para compilar a biblioteca. char ∗ erro . biblioteca = dlopen ( ”libm. (∗seno )(2. dlerror ()). exit (1). } printf ( ”%f\n”. basta: $ gcc minha_biblioteca -o libminha_biblioteca. BIBLIOTECAS DINAMICAS 31 compilacao devem ser apenas resolvidos pela biblioteca dinˆ mica em tempo de execucao. erro ).h> int main ( int argc .0)).so -shared . gerando a biblioteca. dlclose ( biblioteca ). ou ¸˜ a ¸˜ RTLD NOW.h> int mundo (void) { printf ( ”Bem−vindo ao GNU/Linux\n”). sendo que a abertura da biblioteca dever´ falhar caso algum s´mbolo n˜ o a ı a possa ser definido. tal como: $ gcc dl-now. } seno = dlsym ( biblioteca .c -o dl-now -ldl 5. ”sin” ).h> #include <dlfcn . char ∗∗argv) { void ∗ biblioteca . RTLD NOW). } Para usar as funcoes de bibliotecas dinˆ micas a biblioteca dl deve ser especificada em tempo ¸˜ a linkagem. if (! biblioteca ) { fprintf ( stderr . ”%s\n”. double (∗seno )(double). if (( erro = dlerror ()) != NULL) { fprintf ( stderr .´ ˆ CAPITULO 5. Um exemplo de uma biblioteca simples que exporta apenas uma funcao pode ser visto a ¸˜ seguir: 1 2 3 4 5 6 7 #include <stdio . exit (0). que significa que todos os s´mbolos da biblioteca dinˆ mica devem ser resolvidos na ı a abertura da mesma. ”%s\n”.

args [0] = strdup ( ” ls ” ).h> int main ( int argc . a ´ • <0: Sinaliza que a chamada de sistema n˜ o pˆ de ser completada com sucesso. h> #include <sys/ types . e a outra atrav´ s da criacao de threads. retorna os seguintes valores: a • >0: Sinalizando que o processo que est´ executando no momento e o do pai.h> #include <unistd . a o #include <stdio . args [2] = NULL. pid t pid . args = ( char ∗∗) malloc ( sizeof ( char ∗) ∗ 3). h> #include < stdlib . pid = fork (). que podem ser vistas e ¸˜ como processos leves [STE 98] 6. A chamada de sistema n˜ o ı e a recebe nada como parˆ metro.h> #include <sys/wait . 32 .Cap´tulo 6 ı Processos e threads Existem duas maneiras de criar novos fluxos de processos no GNU/Linux. args [1] = strdup ( ”−a”). Uma delas e atrav´ s ´ e da chamada de sistema fork(2). if ( pid == 0) { char ∗∗args . printf ( ”Processo filho executando \” ls −a\”\n”). a ´ Um exemplo de criacao de um sub-processo pode ser visto no exemplo abaixo: ¸˜ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 • 0: Sinalizando que o processo que est´ executando no momento e o do filho criado.1 Processos ´ E poss´vel criar processos atrav´ s da chamada de sistema fork(2). h> #include < string . char ∗∗argv) { int status .

com a excess˜ o a ` ¸˜ a de que a spawnl() j´ explicita em seus argumentos se o processo pai deve aguardar pelo seu a t´ rmino de execucao ou n˜ o. } else if ( pid > 0) { printf ( ”Processo pai aguardando processo filho . Todas as threads em um processo compartilham o estado deste processo. O conjunto do uso do fork(3) com o execvp(3) e waitpid(3) aprea senta uma semˆ ntica semelhante a funcao spawnl() do Microsoft Windows.\ n” ). • Ganhos de performance em hardware multiprocessado. . free ( args ). e uma constante chamada WUNTRACED. } else if ( pid < 0) { /∗ algum erro ocorreu ∗/ perror ( ”fork” ). args ). free ( args [1]). Elas residem no mesmo enderecamento de mem´ ria. • Possibilidade de criar programas bem estruturados. descrevendo os argumentos que este pro´ grama ir´ receber. e o ´ segundo argumento e um array terminado por NULL. O primeiro argumento para ela e o pathname para um programa. vˆ em as mesmas funcoes e os mesmos dados. else printf ( ”processo filho nao executou normalmente\n”). e ¸˜ a Outra funcao utilizada na listagem do programa acima e a waitpid(3). Os parˆ metros enviados a ela s˜ o o pid do processo a ser e ¸˜ a a aguardado. que significa que ela ¸˜ deve parar de aguardar pelo filho que j´ teve sua execucao parada e se encontra em um status a ¸˜ desconhecido.2 Threads Threads tˆ m o mesmo prop´ sito de um processo: gerar um novo fluxo de execucao. a devido ao fato de elas implementarem o conceito de processos leves. waitpid ( pid. } exit (0). if ( WIFEXITED(status)) printf ( ”processo filho executou normalmente\n”). que aguarda pelo ¸˜ ´ t´ rmino da execucao de algum processo. • Mudanca de m´ todos de comunicacao entre os processos. WUNTRACED). & status . free ( args [0]). } A funcao execvp(3) e utilizada para trocar a imagem do processo corrente pela imagem ¸˜ ´ de um novo processo. 6. ¸ e ¸˜ • Apenas um bin´ rio executa bem tanto em arquiteturas SMP (Symmetric Multi Processors) a quanto UP (Uni Processor). • Uso eficiente dos recursos do sistema.. e o ¸˜ elas s˜ o mais adequadas para uso em programas que precisam disparar muitos processos filhos. PROCESSOS E THREADS 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 33 execvp ( args [0]. No entanto. As maiores ¸ o e ¸˜ vantagens de utilizar threads em programas s˜ o: a • Aumento da responsividade do programa. onde ser˜ o armazenas informacoes sobre a execucao a ¸˜ ¸˜ do processo (como sinais que foram entregues a ele para que ele fosse encerrado e valor de retorno da execucao do processo).´ CAPITULO 6. um ponteiro para um inteiro.

o modelo de threads POSIX.´ CAPITULO 6.h> int pthread create ( pthread t ∗ thread . isto e acarreta em um overhead desnecess´ rio para os fluxos de execucao. PROCESSOS E THREADS • Apenas um unico arquivo fonte pode ser usado em m´ ltiplas plataformas. Para dar suporte a este modelo. devendo ser desalocado ap´ s ter sido utilizado o pelo programa. aprovado pelo padr˜ o IEEE e e a 1003. a ¸˜ Para criar um novo fluxo de execucao com o uso de threads no GNU/Linux. as distribuicoes GNU/Linux fornecem ¸˜ a biblioteca LinuxThreads. O ultimo caso e equivalente a chamar ¸˜ ´ ´ pthread exit(3) com o resultado retornado pela funcao start routine como retorno. definida pelo seguinte prot´ tipo: ¸˜ o #include <pthread . Uma outra caracter´stica e a de que threads Win32 mant´ m uma ı ´ e dependˆ ncia entre janelas e threads. Este texto baseia-se na implementacao das Lin¸˜ uxThreads. e o a a e tem uma pol´tica de escalonamento normal (n˜ o-realtime). utiliza-se a funcao pthread join(3): ¸˜ #include <pthread . Em relacao as threads Win32. como prioridades de escalonamento e m´ scaras de sinal. O exemplo abaixo ilustra a criacao e sincronizacao de uma thread no GNU/Linux.so e possa fazer uso de suas funcoes. pthread attr t ∗ attr . via pthread exit(3). void ∗ arg ). pthread join(3) suspende a execucao da thread corrente at´ que a thread identificada ¸˜ e por th termine. e a A s´ rie 2. e necess´ rio passar a flag -lpthread. A nova thread termina explicitamente. um program counter e algumas informacoes a respeito de sua instˆ ncia. h> #include <pthread .6 do kernel Linux est´ fazendo uso de um outro modelo de threads. ¸˜ 1 2 3 4 5 6 7 8 #include <stdio . ou sendo cancelada. ou pode ser NULL caso os atributos padr˜ o devam ser utilizados: a thread criada e joinable. apenas retornando da funcao start routine. ou ¸˜ implicitamente. e ap´ s configurados ¸˜ o com o uso de alguma das funcoes listadas na p´ gina manual pthread attr init(3). passando arg como seu ¸˜ argumento. A nova thread aplica a funcao start routine. chamado NPTL e a (Native POSIX Threading Library) [The 2003]. as threads POSIX s˜ o muito mais leves. Caso o argumento thread return seja n˜ o nulo. Para com¸˜ ¸˜ pilar este programa. ´ u 34 Uma thread consiste de uma stack e um stack pointer. at´ a s´ rie 2. tanto explicitamente. Como nem todas threads constroem e usam janelas. h> #include <unistd . Os atributos a serem passados para a ı a thread devem ser inicializados com a funcao pthread attr init(3). pthread create(3) cria uma nova thread de controle que executa concorrentemente com a thread que a gerou. ¸˜ a a armazenadas na sua estrutura. os registradores da CPU s˜ o tamb´ m armazenados e a e (sendo que a stack pointer e o program counter s˜ o alguns destes registradores). a O Linux utiliza. ou seja. utiliza-se a ¸˜ funcao pthread create(3). ¸˜ O argumento attr especifica algum atributo a ser aplicado para a nova thread. chamando a funcao pthread exit(3). ele e utilizado ¸˜ a ´ para armazenar o valor de retorno da thread th. que implementa grande parte das exigˆ ncias feitas por este padr˜ o.h> void ∗ calcula ( void ∗dados) { .4. contendo primi¸˜ ` a tivas mais simples de uso. Al´ m disso. ¸˜ a Para sincronizar um processo (ou uma thread) com o resultado de uma outra thread. para que o programa seja linkado ´ a com a biblioteca de threads libpthread.1b-1993 [Ame 94].h> int pthread join ( pthread t th . void ∗ (∗ start routine )( void ∗). seus a ´ recursos de mem´ ria n˜ o ser˜ o liberados at´ que algum processo sincronize com esta thread. void ∗∗ thread return ).h> #include < stdlib . atrav´ s da e funcao pthread cancel(3).

ret = ( int ∗) malloc ( sizeof ( int )). pthread create (& tid . h> #include <pthread . dados = ( int ∗) malloc ( sizeof ( int )). ∗ resultado ). i < 10000. exit (0). caso alguma outra thread j´ tenha a adquirido o lock.´ CAPITULO 6. PROCESSOS E THREADS 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 35 int ∗ ret = NULL. uti¸˜ lizando mecanismos de exclus˜ o m´ tua: a u 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include <stdio . A forma mais comum de compartilhar dados ¸˜ entre diferentes threads e atrav´ s de vari´ veis globais a elas. dados ). ∗dados. Caso n˜ o desej´ va-se que a execucao seja interrompida. e a a ¸˜ pthread mutex trylock(3) pode ser usado: caso o lock n˜ o esteja dispon´vel ela cona ı tinua a execucao do programa. e mantendo a coerˆ ncia das leituras ´ e a e e escritas destes dados com o uso de mecanismos de exclus˜ o m´ tua (mutexes) e sem´ foros. void ∗ incrementa ( void ∗dados) { int i . a thread que tentou peg´ -lo pela segunda vez tem sua execucao interrompa ¸˜ ida at´ que a outra thread o libere. ∗dados = 5. } Como threads podem compartilhar recursos entre si. pthread join ( tid . int ∗ valor = ( int ∗) dados. Na primeira primitiva. char ∗∗argv) { pthread t tid . ¸˜ O exemplo abaixo mostra como compartilhar um dado entre duas threads de execucao. calcula . i++) { . free ( dados ). h> #include <unistd . printf ( ”%d ∗ %d = %d\n”. for ( i = 0. a u a O uso de mutexes e feito basicamente atrav´ s das primitivas pthread mutex lock(3) ´ e e pthread mutex unlock(3). pthread mutex t mutex = PTHREAD MUTEX INITIALIZER. pthread exit ( ret ).h> static int valor = 0.h> #include < stdlib . NULL. free ( resultado ). ( void ∗∗) & resultado ). ∗dados. } int main ( int argc . ∗ ret = ∗ valor ∗ ∗ valor . int ∗dados . ∗ resultado . n˜ o e necess´ rio fazer uso de mecanisa ´ a mos pesados de intercomunicacao entre processos.

O argumento a a a a ´ pshared indica se o sem´ foro e local ao processo atual (neste caso pshared deve ser zero) ou se a ´ ele n˜ o e compartilhado entre v´ rios processos (neste caso pshared deve ser n˜ o zero). int sem wait(sem t ∗ sem). join ( tid . sem init(3) inicializa o sem´ foro apontado por sem com o valor especificado em value. } int main ( int argc .h> int sem init (sem t ∗sem. } void ∗ decrementa ( void ∗dados) { int i . NULL). a Este valor indica quantas threads poder˜ o entrar na sess˜ o cr´tica ao mesmo tempo. Eles funcionam como contadores para a e recursos compartilhados entre threads. unsigned int value ). } Sem´ foros tamb´ m tem um uso bastante comuns. printf ( ” valor da variavel global : %d\n” . incrementa. valor ). valor ++. exit (0). } pthread exit ( NULL). ¸˜ sem post(3) e sem destroy(3): #include <semaphore. No a ´ a a entanto. a implementacao das LinuxThreads n˜ o implementa o compartilhamento de sem´ foros ¸˜ a a entre v´ rios processos. As operacoes b´ sicas realizadas em sem´ foros s˜ o incre¸˜ a a a mentar o contador atomicamente e aguardar at´ que o contador seja n˜ o nulo e decrement´ -lo e a a atomicamente. join ( tid2 . sem wait(3). PROCESSOS E THREADS 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 36 pthread mutex lock (&mutex). podem ser usadas as funcoes sem init(3). retornando um erro na inicializacao do sem´ foro caso pshared seja um a ¸˜ a valor diferente de zero. char ∗∗argv) { pthread t tid . int sem post(sem t ∗ sem). NULL). Nestes casos. tid2 . } pthread exit ( NULL). NULL). valor −−. create (& tid2 . NULL). pthread mutex unlock (&mutex). . Nos casos a a ı mais comuns s˜ o utilizados sem´ foros bin´ rios. pthread mutex unlock (&mutex). int sem trywait (sem t ∗ sem). int pshared . i < 10000. int sem destroy (sem t ∗ sem).´ CAPITULO 6. NULL. e ent˜ o este valor e iniciado com 1. decrementa. NULL. for ( i = 0. pthread pthread pthread pthread create (& tid . i++) { pthread mutex lock (&mutex).

NULL). create (& tid2 . 0. } pthread exit ( NULL). valor −−. join ( tid . NULL).´ CAPITULO 6. join ( tid2 .h> #include <semaphore. NULL). i++) { sem wait (&semaforo). } int main ( int argc .h> static int valor = 0. 1). incrementa. sem post (&semaforo). h> #include <unistd . valor ++. h> #include <pthread . for ( i = 0. i < 10000. } . NULL. printf ( ” valor da variavel global : %d\n” . sem t semaforo. i++) { sem wait (&semaforo). decrementa. } void ∗ decrementa ( void ∗dados) { int i . sem destroy (&semaforo). pthread pthread pthread pthread create (& tid . exit (0). tid2 . i < 10000. } pthread exit ( NULL). sem post (&semaforo). sem init (&semaforo . NULL. PROCESSOS E THREADS O exemplo abaixo apresenta o uso de sem´ foros para controle de uma sess˜ o cr´tica: a a ı 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 37 #include <stdio . NULL). valor ). void ∗ incrementa ( void ∗dados) { int i .h> #include < stdlib . for ( i = 0. char ∗∗argv) { pthread t tid .

sin family = AF INET. sin addr ) <= 0) err quit ( ” inet pton ” ). em um formato formatado e leg´vel. if ( connect ( sockfd . if ( argc != 2) { fprintf ( stderr .h” int main ( int argc . ( struct sockaddr ∗) & servaddr . /∗ servidor de daytime ∗/ if ( inet pton ( AF INET. } if (( sockfd = socket ( AF INET. n. argv [0]). servaddr . ”Sintaxe: %s <endereco IP>\n”. SOCK STREAM. while (( n = read ( sockfd . char ∗∗argv) { int sockfd . &servaddr . struct sockaddr in servaddr . memset (&servaddr . nos modos bloqueante e n˜ o-bloqueante no IPv4 [STE 98a]. argv[1]. Este cliente estabelece uma conex˜ o TCP com ¸˜ a um servidor. Abaixo encontra-se listada uma implementacao de um ´ ¸˜ cliente TCP de uma aplicacao do tipo timeofday. Este cap´tulo visa apresentar a utilizacao de sockets no GNU/Linux para ´ ı ¸˜ comunicacao entre cliente e servidor. e o servidor apenas envia de volta a hora e data atuais. sin port = htons (13). char recvline [MAXLINE + 1]. sizeof ( servaddr )). sizeof ( servaddr )) < 0) err quit ( ”connect” ). 0)) < 0) err quit ( ”socket” ). /∗ terminada por NULL ∗/ 38 . servaddr . recvline . 0.Cap´tulo 7 ı TCP/IP O conjunto de funcoes dispon´veis para serem utilizadas na comunicacao atrav´ s do protocolo ¸˜ ı ¸˜ e TCP/IP e muito grande. ¸˜ a Provavelmente a maneira mais simples de explicar como programar sockets neste ambiente e com o uso de um exemplo comentado. exit (1). MAXLINE)) > 0) { recvline [n ] = 0. ı 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include ”timeofday .

Como o TCP e um protocolo byte-stream. char buff [MAXLINE]. e ´ ele n˜ o tem registro sobre limites do conte´ do sendo transportado. at´ que os ultimos ´ e ´ bytes sejam lidos. que e o nome dado para um socket TCP. exit (0). } if ( n < 0) err quit ( ”read” ). ou seja: os bytes a u retornados podem vir de uma unica vez. deve utilizar a flag -lnsl. Desta forma. e necess´ rio a ´ a escrever um. . a 1 2 3 4 5 6 7 8 9 10 11 12 #include ”timeofday . • 18 − 23: especificacao do endereco IP de um servidor e uma porta. Assim. A vers˜ o do servidor para este cliente encontra-se listado logo abaixo. sempre que estivermos lendo o conte´ do de um socket u TCP. • 28 − 35: lˆ e mostra o reply do servidor. como as ¸˜ chamadas ao connect e ao read.´ CAPITULO 7. if (( listenfd = socket ( AF INET. e necess´ rio fazˆ -lo em um loop. a Como o programa anterior n˜ o pode executar corretamente sem um servidor. e e ¸˜ u ´ utilizada a funcao inet pton (presentation to numeric) para converter o endereco IP em ¸˜ ¸ ASCII para o formato necess´ rio. stdout ) == EOF) err quit ( ” fputs ” ). quando compilado. utilizado para realizar as chamadas de funcoes futuras. ou em n pequenas leituras. char ∗∗argv) { int listenfd . struct sockaddr in servaddr . connfd. SOCK STREAM. nem sempre e garantido que com um unico read venha ´ ´ toda a resposta do servidor. Os detalhes de seu conte´ do s˜ o ¸ ¸˜ u a mostrados mais a seguir. A funcao socket cria uma stream (SOCK STREAM) de ¸˜ ¸˜ ´ ¸˜ Internet (AF INET). O IP fornecido e a porta nesta estrutura precisam estar em formatos espec´ficos: ¸ ı para isto. para ser linkado com as funcoes de sockets da Glibc. estabelece uma conex˜ o TCP com o servidor especificado pela estrutura a socket address apontada pelo segundo argumento. • 15: criacao de um socket TCP. time t ticks . u ´ ¸˜ configurada para usar a fam´lia de enderecos AF INET e para usar a porta 13 (que e a ı ¸ ´ porta conhecida para o servidor de daytime em qualquer host TCP/IP que suporte este servico). TCP/IP 30 31 32 33 34 35 36 37 38 39 if ( fputs ( recvline . 0)) < 0) err quit ( ”socket” ).h” int main ( int argc . a • 25 − 26: estabelecimento da conex˜ o com o servidor. terminando-o quando read retornar 0 (o outro lado ´ a e encerrou a conex˜ o) ou um valor menor do que 0 (quando ocorre um erro). A estrutura e zerada com o uso da funcao memset. ¸˜ Existem v´ rios detalhes a serem considerados neste programa: a • 1: o cabecalho em comum com a aplicacao do servidor. } Este exemplo. A funcao connect. Uma estrutura do ¸˜ ¸ tipo Internet socket address (a sockaddr in sockaddr) e preenchida com o endereco IP do ´ ¸ servidor e com o n´ mero da porta. a funcao htons (host to network short) para converter o n´ mero da porta. Esta funcao retorna o descritor de um socket. quando aplicada a ¸˜ a um socket TCP.

} } Assim como no cliente. sizeof ( servaddr )). ´ a O arquivo header utilizado em ambos exemplos encontra-se abaixo: • 34: a conex˜ o com o cliente e encerrada. Esta string e ent˜ o escrita de volta para o cliente. strlen ( buff ))) < 0) err quit ( ” write” ). e o valor de retorno desta funcao e um novo descritor (connfd). Quando e feita a chamada ao listen. sin family = AF INET. NULL)) < 0) err quit ( ”accept” ). sin port = htons (13).´ CAPITULO 7. ticks = time ( NULL). MAX CONNECT)) < 0) err quit ( ” listen ” ). sin addr . sizeof ( buff ). e ` a .) { if (( connfd = accept ( listenfd . if (( write ( connfd .h. a funcao a ´ ¸˜ accept retorna. A constante MAX CONNECT ´ est´ especificada no header timeofday. socket. A funcao ctime converte o valor inteiro retornado em uma forma leg´vel para ¸˜ ı humanos. a ´ • 11 − 12: cria o socket TCP. bind e o e listen s˜ o os passos utilizados para preparar qualquer listening descriptor (descritor de a escuta) em um servidor TCP (que neste caso e o listenfd). ´ conex˜ es ao socket passam a ser aceitas pelo kernel. alguns detalhes precisam ser considerados na vers˜ o do servidor: a • 19−20: realiza um binding (amarra) da porta conhecida com o socket. idˆ ntico a vers˜ o do cliente. for (. Uma conex˜ o TCP usa o que e chamado de um three-way handa ´ shake para estabelecer uma conex˜ o. que permite que o servidor aceite uma conex˜ o em qualquer interface. aguardando que uma conex˜ o de um cliente ´ ` a chegue e seja aceita. 0. ”%.. • 22 − 23: converte o socket para um listening socket. a • 26−32: aceita conex˜ es dos clientes e envia um reply. Um novo descritor e retornado pelo accept a cada cliente ´ que conecta ao servidor. e especifica a quantidade m´ xima de clientes que a a ir˜ o conectar-se ao listening descriptor. Normalmente o processo do servio dor e posto para dormir na chamada a accept. E especificado o endereco IP como ¸ INADDR ANY. s addr = htonl ( INADDR ANY). preenchendo uma estru¸ ´ ´ tura de Internet socket address e chamando o bind. A funcao time retorna a hora e data atual.24s\r\n”. servaddr . para o servico de daytime) e ligada ao socket. e quando este handshake e completado. ( struct sockaddr ∗) & servaddr . close ( connfd ). servaddr . O novo descritor e usado para ´ comunicar com o novo cliente. if (( listen ( listenfd . chamado ¸˜ ´ de connected descriptor (descritor do cliente conectado). /∗ servidor de daytime ∗/ if (( bind ( listenfd . na forma dos segundos que ocorreram desde a ¸˜ epoca do Unix: 1o de janeiro de 1970. as 00:00:00 horas UTC (Coordinated Universal ´ ` Time). buff . TCP/IP 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 40 memset (&servaddr . ctime (& ticks )). A porta conhecida do servidor (13. snprintf ( buff . Estes trˆ s passos. ( struct sockaddr ∗) NULL. sizeof ( servaddr ))) < 0) err quit ( ”bind” ). a caso o host tenha mais de uma. servaddr .

exit (1).0. e muitas vezes e desej´ vel utilizar e ´ a o nome do host que disponibiliza o servico. int h length . o cliente deve ser exe¸˜ cutado passando um endereco IP v´ lido como parˆ metro.h ∗/ #define MAX CONNECT SOMAXCONN #define MAXLINE 1024 #endif /∗ timeofday h ∗/ Ap´ s ter o servidor compilado e rodando em um terminal. terminada por NULL ∗/ tipo do endereco do host ∗/ tamanho do endereco ∗/ lista de anderecos .h> 41 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 /∗ /∗ /∗ /∗ /∗ socket () ∗/ inet pton () ∗/ htons () ∗/ memset() ∗/ time () ∗/ #define err quit (msg ) ({ perror (msg). eles ainda usam valores num´ ricos para referenciar o servidor. definida no ¸ e <netdb.h> #include <unistd .0. que coincida com o ¸˜ ¸˜ servico name que utiliza o protocolo proto. ¸ ¸˜ como: • struct hostent *gethostbyname(const char *name): retorna um ponteiro para uma estrutura do tipo hostent para o host name.h>. A estrutura hostent. normalmente /etc/services. int h addrtype . que pode estar representado tanto na notacao de ¸˜ um endereco IP num´ rico quanto como um hostname. }) /∗ SOMAXCONN fica definido em bits/socket .h> #include < string . O unico tipo v´ lido de endereco e atualmente AF INET. ´ a ¸ ´ • struct servent *getservbyname(const char *name. No entanto. Caso proto seja NULL.h> #include <sys/ socket .´ CAPITULO 7. Para isto. char ∗∗ h addr list . TCP/IP #ifndef timeofday h #define timeofday h 1 #include <stdio . Como estamos especificando qualquer ¸ a a interface para escuta no servidor.h> #include < netinet / in . int type): retorna um ponteiro para uma estrutura do tipo hostent para o endereco do host especificado em addr de ¸ tamanho len e de tipo type. pode ser utilizada a interface loopback: $ timeofday-client 127. a . char ∗∗ h aliases .h> #include <arpa/ inet . Para isto algumas funcoes podem ser utilizadas. h> #include < stdlib . const char *proto): retorna um ponteiro para uma estrutura do tipo servent para a linha do arquivo services do diret´ rio o de configuracoes da distribuicao. h> #include <time. h> #include <sys/ types . um outro terminal pode ser utio lizado para efetuar a comunicacao entre o cliente e o servidor. } #define h addr h addr list /∗ /∗ /∗ /∗ /∗ nome oficial do host ∗/ lista de aliases . terminada por NULL ∗/ [0] /∗ backward compatibility ∗/ • struct hostent *gethostbyaddr(const char *addr. e composta pelos seguintes elementos: ´ struct hostent { char ∗h name.1 Mon Oct 13 00:50:12 2003 Estes exemplos funcionam e podem servir como base para programas maiores. qualquer protocolo ¸ ser´ aceito. int len.

h” int main ( int argc . } /∗ /∗ /∗ /∗ nome oficial do servico ∗/ lista de aliases . struct sockaddr in servaddr . char recvline [MAXLINE + 1]. usando o protocolo proto. const char *proto): retorna um ponteiro para uma estrutura do tipo servent para a linha do arquivo services que coincida com a porta especificada em port. O pr´ ximo exemplo mostra como estes recursos podem ser incorporados ao programa anteo rior: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include ”timeofday .sin addr . /∗ terminada por NULL ∗/ if ( fputs ( recvline . ”Sintaxe: %s <endereco IP> <porta>\n”.h> como segue: ´ struct servent { char ∗s name. sin port = htons ( atoi ( argv [2])). char ∗ s proto . char ∗∗ s aliases . int s port . terminada por NULL ∗/ numero da porta ∗/ protocolo a ser usado ∗/ 42 • struct servent *getservbyport(int port. . char ∗∗argv) { int sockfd . if ( connect ( sockfd . ht−>h addr list [0]. 0. qualquer um ser´ aceito no matching. if (( ht = gethostbyname (argv [1])) < 0) err quit ( ”gethostbyname”). sin family = AF INET. exit (1). 0)) < 0) err quit ( ”socket” ). sizeof ( struct in addr )). memcpy (&servaddr. sizeof ( servaddr )). SOCK STREAM. argv[0]). struct hostent ∗ ht . n. TCP/IP A estrutura servent e especificada no arquivo <netdb. } if (( sockfd = socket ( AF INET. recvline . servaddr . memset (&servaddr . } if ( n < 0) err quit ( ”read” ). MAXLINE)) > 0) { recvline [n ] = 0.´ CAPITULO 7. while (( n = read ( sockfd . Caso o protocolo seja NULL. servaddr . sizeof ( servaddr )) < 0) err quit ( ”connect” ). ( struct sockaddr ∗) & servaddr . A porta deve estar informada em network byte order a (htonl(3)). if ( argc != 3) { fprintf ( stderr . stdout ) == EOF) err quit ( ” fputs ” ).

if (( write ( connfd . vemos que a partir de agora o endereco e copiado a partir das e ¸ ´ informacoes dispon´veis na estrutura hostent− >h addr list. sizeof ( buff ). e conectamos a ele. 0. time t ticks . } Podemos ver na linha 19 que agora e feita uma chamada para gethostbyname(3). struct sockaddr in servaddr . ntohs ( cliaddr .´ CAPITULO 7.sin addr . 0)) < 0) err quit ( ”socket” ). O restante do programa mant´ m-se inal` e terado. ticks = time ( NULL). } if (( listenfd = socket ( AF INET. for (. A forma de realizar a c´ pia da interface a ser utilizada a o tamb´ m foi mudada: na linha 25.h” int main ( int argc . exit (1). ”%. buff . MAX CONNECT)) < 0) err quit ( ” listen ” ). sizeof ( servaddr )).) { if (( connfd = accept ( listenfd . char buff [MAXLINE]. memset (&servaddr . sin family = AF INET. ( struct sockaddr ∗) & cliaddr . A seguir vamos analisar as mudancas na vers˜ o do servidor: ¸ a 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include ”timeofday . if (( listen ( listenfd . cliaddr . snprintf ( buff . printf ( ”conexao estabelecida com %s na porta %d\n”. if ( argc != 2) { printf ( ”Sintaxe: %s <porta>\n”. sin addr . . sizeof ( buff )). sin port )). & len )) < 0) err quit ( ”accept” ). Na linha 24. servaddr .. argv [0]). buff . char ∗∗argv) { int listenfd . servaddr . TCP/IP 39 40 43 exit (0). sin port = htons ( atoi ( argv [1])). servaddr . Utilizamos o primeiro endereco ¸˜ ı ¸ referente as interfaces neste host. infora mamos a porta atrav´ s do parˆ metro passado pelo usu´ rio (a funcao atoi(3) realiza a cone a a ¸˜ vers˜ o de uma string para um inteiro). connfd. s addr = htonl ( INADDR ANY). sizeof ( servaddr ))) < 0) err quit ( ”bind” ). ctime (& ticks )). strlen ( buff ))) < 0) err quit ( ” write” ). ( struct sockaddr ∗) & servaddr . socklen t len . que ´ realiza o lookup do nome fornecido como parˆ metro na linha de comando. &cliaddr. inet ntop ( AF INET. if (( bind ( listenfd .24s\r\n”. SOCK STREAM.

h> #define err quit (msg ) ({ perror (msg).sin addr que usa a fam´lia AF INET para uma string.h> #include < netinet / in . A funcao accept agora tamb´ m informa ¸˜ e um ponteiro para a estrutura sockaddr cliaddr.h> /∗ /∗ /∗ /∗ /∗ /∗ socket () ∗/ inet pton () ∗/ htons () ∗/ memset() ∗/ gethostbyname () ∗/ time () ∗/ #include <sys/ select . Um ponteiro para este buffer e retornado. declarando o cabecalho <netdb.h> #include < string .h> /∗ de acordo com padroes mais novos ∗/ . }) #define MAXLINE 1024 #define MAX CONNECT 100 #endif /∗ timeofday h ∗/ 7. a ı O header usado foi levemente modificado. e necess´ rio introduzir a funcao select(2). h> #include < stdlib . passando o resultado ao campo sin port da ` estrutura servaddr para que esta porta seja usada.´ CAPITULO 7. h> #include <netdb. ¸ ı que e copiada para buffer. e usamos este ponteiro para ´ ´ imprimir o hostname do client.1−2001 ∗/ include <sys/ select . al´ m de j´ incluir headers para suporte a chamada ` e a ` select(2): 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #ifndef timeofday h #define timeofday h 1 #include <stdio .h> #include <arpa/ inet .1 Select Uma conex˜ o n˜ o-bloqueante envolve v´ rias operacoes sobre os descritores.h> #include <time.h> #include < fcntl .h> #include <sys/ socket . e ent˜ o usa seu resultado para imprim´-lo. Essa funcao aguarda at´ que um n´ mero de ´ a ¸˜ ¸˜ e u descritores de arquivo mudem seu status.h> para prover ¸ suporte a chamada gethostbyname(3). Isto permite que o accept armazene dados sobre a conex˜ o do cliente. Antes de apresent´ a a a ¸˜ a las. Na linha 23. Estes dados s˜ o ent˜ o usados nas linhas 35 − 37: o inet ntop a a a converte o endereco passado em &cliaddr.h> /∗ select () ∗/ #include <sys/ stat . } } As modificacoes foram semelhantes as realizadas no cliente. e feita a convers˜ o ¸˜ ` ´ a da string relativa a porta a ser usada para inteiro.h> #include <errno . TCP/IP 43 44 45 46 44 close ( connfd ).h> #include <unistd . A funcao htohs e usada apenas para converter o n´ mero em ¸˜ ´ u network byte order para host byte order. exit (1). Seu prot´ tipo e definido como segue: o ´ /∗ de acordo com o POSIX 1003. h> #include <sys/ types .

que pode ser atualizado para indicar quanto tempo j´ se passou do timeout especifidado. Na sa´da. FD CLR(int fd. a Trˆ s conjuntos independentes de descritores s˜ o monitorados. quatro macros s˜ o disponibilizadas. fd set ∗ set ). tv .h> include <unistd .h> int select ( int n . /∗ micro segundos ∗/ } O valor de retorno de uma chamada ao select(2) e o n´ mero de descritores contigo no ´ u conjunto de descritores. a chamada pode bloquear indefinidamente. char ∗∗argv) { fd set rfds . e FD ISSET testa para ver se um descritor faz parte do conjunto. Os que est˜ o listados em readfds e a a ser˜ o monitorados para verificar se algum caracter fica dispon´vel para leitura (para verificar se a ı a leitura n˜ o vai bloquear). struct timeval ∗ timeout ). ´ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <stdio . tv sec = 5. int retval . O exemplo abaixo mostra o uso de select(2) para aguardar at´ que algum dado seja lido e da stdin.h> #include <sys/time . fd set ∗ writefds .´ CAPITULO 7. e os em exceptfds ser˜ o monitorados quanto a excecoes. O timeout e configurado para 5 segundos. FD SET (0.h> #include <unistd . FD SET(int fd . Os listados em writefds ser˜ o monitorados para verificar se alguma a a escrita n˜ o ir´ bloquear. mais 1. Caso timeout seja ´ e NULL. 45 A funcao select(2) usa um timeout que e uma struct timeval (com segundos e microse¸˜ ´ gundos). &rfds). TCP/IP include <sys/time . u e timeout e o tempo que deve ser aguardado at´ que select(2) retorne.h> struct timeval { long tv sec . fd set ∗ set ). FD SET e FD CLEAR adicionam ou removem um descritor de um conjunto. /∗ segundos ∗/ long tv usec . fd set ∗ readfds . ´ O valor n indica o descritor de maior n´ mero em qualquer um dos trˆ s conjuntos. FD ZERO(fd set ∗set). FD ZERO zera um cona junto. A seguinte estruturas e usada para definir os timeouts: ´ #include <sys/time .h> include <sys/ types . h> int main ( int argc . a Para operar esses conjuntos. os a a a ¸˜ ı conjuntos s˜ o modificados para indicar os descritores que tiveram seu status alterado. fd set ∗ exceptfds . /∗ monitora a stdin (0) ∗/ FD ZERO (&rfds).h> #include <sys/ types . struct timeval tv . Isso e util ap´ s o retorno de select(2). que pode ser zero caso o timeout tenha expirado antes que qualquer coisa acontecesse. ´ ´ o para garantir que o descritor que foi modificado e o mesmo que tinha-se interesse em monitorar. fd set ∗ set ). . FD ISSET(int fd .

const void *optval. NULL.h> cont´ m definicoes para opcoes a serem utilizadas e ¸˜ ¸˜ no n´vel de sockets. TCP/IP 18 19 20 21 22 23 24 25 26 27 28 46 tv . A funcao fcntl(2) realiza operacoes sobre descritores de arquivo (neste caso. e est˜ o sempre presentes no n´vel mais alto de socku ı a ı ets. Para getsockopt(2) elas identificam um buffer no qual o valor para a opcao requisitada dever´ ser retornado. a Esta funcao permite operar com operacoes do tipo close-on-exec. Antes de apresentar os exemplos de um cliente e um servidor a a escritos seguindo este modelo. & rfds .\n” ). socklen t *optlen). } Vale notar que ap´ s a chamada a select(2).2 Conex˜ es n˜ o-bloqueantes o a Ap´ s visto como funciona o uso da operacao select(2). Quando as opcoes do socket s˜ o manipuladas. socklen t *optlen). entre outros. exit (0). Caso n˜ o haja nenhum a a valor para ser informado ou retornado. Os parˆ metros optval e optlen s˜ o usados para acessar os valores das opcoes. optlen e um ¸˜ a ´ parˆ metro informando o tamanho do buffer apontado por optval. que pode ser um long ou um ponteiro para uma struct flock. int level. int cmd. struct flock *lock). para ı u indicar que uma opcao ser´ interpretada pelo protocolo TCP. a optname e passado para o m´ dulo apropriado do protocolo. retval = select (1. int optname. ı • int fcntl(int fd. quando a a ¸˜ usado com setsockopt(2). para que l´ ele seja interpre´ o a tado. e n˜ o deve ser o ` ´ a usado para obter informacoes a respeito do tempo que se passou. int fcntl(int fd. Para manipular opcoes no n´vel de socket. if ( retval ) { printf ( ”Dados disponiveis . o n´vel em que a opcao reside e o ¸˜ a ı ¸˜ nome desta opcao devem ser especificadas. o valor de tv e desconhecido. o n´ mero do protocolo deve ser informado. int setsockopt (int s. que podem existir em ¸˜ ¸˜ m´ ltiplos n´veis do protocolo. int fcntl(int fd. Por exemplo. int optname. especi¸˜ ¸˜ ficados por fd). A operacao e determinada por cmd. Neste caso. ¸˜ ¸˜ ı ¸˜ o parˆ metro level e especificado como SOL SOCKET. tv usec = 0. } else printf (”Nenhum dado veio em 5 segundos\n”). pode ser ¸˜ ´ ¸˜ utilizado um parˆ metro extra. O arquivo header <sys/socket. optval pode ser NULL. e dependendo da operacao. void *optval.´ CAPITULO 7. NULL. Um tutorial completo no uso ¸˜ do select(2) e fornecido na man page do select tut(2). realizar advisory lockings (locks baseados em arquivos) e manipular sinais. fica mais f´ cil entender o processo o ¸˜ a de uma conex˜ o n˜ o-bloqueante. ´ 7. As opcoes dispon´veis ¸˜ ı est˜ o documentadas na man page do socket(7). int level. int cmd). al´ m de permitir obter ¸˜ ¸˜ e as flags de status de um arquivo. &tv). long arg). o parˆ metro level deve conter ¸˜ a a o valor TCP. A seguir e visto o c´ digo de um servidor que faz o uso de conex˜ es n˜ o-bloqueantes: ´ o o a . Estas funcoes manipulam as opcoes associadas a um socket s. algumas funcoes s˜ o importantes de serem vistas: ¸˜ a • int getsockopt (int s. Para manipular opcoes em algum a ´ outro n´vel do protocolo. int cmd.

TCP/IP #include ”timeofday . if ( select sock out ) FD SET (connfd. NULL. ret = select ( max fd. if ( FD ISSET (connfd. read set . NULL). } } else { . sock EOF = 0. in size ). int int int int max fd = connfd. } if ( in size > 0) { ret = write ( connfd . if ( select sock in ) FD SET (connfd.´ CAPITULO 7. if ( in size == 0) sock EOF = 1. & write set . done = 0.h” void processa clientes ( int listenfd . &read set )) { in size = read ( connfd . max fd++. FD ZERO (&read set). buff . & read set . &write set ). char buff [MAXLINE]. FD ZERO (&write set). if ( ret < in size ) { if ( errno != EAGAIN) { err quit ( ” write” ). else if ( in size < 0) err quit ( ”read” ). sizeof ( buff )). int connfd) { int select sock in = 1. buff . int ret . while (! done) { fd set write set . &read set ). if ( ret < 0) err quit ( ” select ” ). int select sock out = 1. 47 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 if ( listenfd > max fd) max fd = listenfd . } else { printf (”EAGAIN em write\n”). in size = 0.

fd set read set . NULL. } } int main ( int argc . NULL. if ( argc != 2) { printf ( ”Sintaxe: %s <porta>\n”. servaddr . F GETFL). long flags . exit (1). TCP/IP 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 48 in size = 0. char ∗∗argv) { int listenfd . . s addr = htonl ( INADDR ANY). servaddr . argv [0]). select sock in = (! sock EOF && in size == 0). servaddr . ( struct sockaddr ∗) & servaddr . fcntl ( listenfd . flags = fcntl ( listenfd . SO REUSEADDR. memset (&servaddr . FD SET ( listenfd . &optval. sizeof(optval)) < 0) err quit ( ” setsockopt ” ). done = 1. sin port = htons ( atoi ( argv [1])). SOL SOCKET. sizeof ( servaddr )) < 0) err quit ( ”bind” ). 0. /∗ prepara o select para leitura em listenfd ∗/ FD ZERO (&read set).´ CAPITULO 7. if ( listen ( listenfd . 0)) < 0) err quit ( ”socket” ). sin addr . optval . if ( setsockopt ( listenfd . flags | O NONBLOCK). 5) < 0) err quit ( ” listen ” ). if ( bind ( listenfd . optval = 1. NULL) <= 0) err quit ( ” select ” ). } } if ( sock EOF && in size == 0) { close ( connfd ). connfd. } select sock out = ( in size > 0 || sock EOF). sin family = AF INET. sizeof ( servaddr )). F SETFL. } if (( listenfd = socket ( AF INET. struct sockaddr in servaddr . if ( select ( listenfd + 1. & read set ). & read set . SOCK STREAM.

e a imprime. este servidor lˆ os dados enviados pelo cliente e os ¸˜ e retorna ao cliente. a ¸˜ • 81 − 82: cria um socket TCP. visto que os programas nos exemplos ´ precisam dos mesmos headers e usam a mesma constantes MAXLINE e a macro err quit(). connfd ). Neste caso em que utilizamos um socket da fam´lia AF INET. A seguir. F GETFL). ¸ • 87 − 90: especificacao do protocolo. fecha o descritor a e encerra a execucao da funcao. Ele envia uma stream de bytes ´ para o servidor. o servidor lˆ os dados a partir do e socket representado por este descritor para o buffer buff . • 95 − 96: prepara o socket para aceitar requisicoes. a o ¸˜ • 115: processa a requisicao. A an´ lise do c´ digo ´ ¸ ¸ a o ser´ feita a partir da funcao main(). ¸˜ • 102 − 108: prepara o uso do select(2) para o descritor listenfd. processa clientes ( listenfd . fcntl ( connfd . interfaces e portas para usar no bind. explicada abaixo. e • 58−61: caso j´ tenha lido a stream toda e reconhecido o final de arquivo. ¸˜ • 92 − 93: faz o bind. escrevendo a quantidade de dados lidas at´ o momento. } Ao receber uma requisicao de um cliente. e aguardado at´ que o status de algum deles seja modificado. e com a opcao SO REUSEADDR indicamos que as regras usadas para a ¸˜ validacao do endereco usada no bind(2) devem permitir a reutilizacao de um endereco ¸˜ ¸ ¸˜ ¸ local. Ap´ s. • 98 − 99: configura as opcoes do descritor listenfd de forma a manter as opcoes atuais ¸˜ ¸˜ (linha 98). NULL.h.´ CAPITULO 7. Este e um servico conhecido como um servico de echo. ¸˜ • 37 − 43: caso o descritor connfd tenha sido modificado. o u . Como visto no exemplo do servidor. a resposta vinda do servidor e o ´ pr´ prio conte´ do do arquivo. & read set )) err quit ( ” select ” ). • 17 − 19: define o valor m´ ximo dos descritores em uso para utilizar na chamada ao a select(2). • 24−35: configura os conjuntos de descritores de leitura e escrita para uso no select(2). Os parˆ metros ¸˜ ¸˜ a passados a ela indicam que estamos trabalhando no n´vel de socket. prepara o descritor novamente para o a operar em modo n˜ o bloqueante para as pr´ ximas operacoes. ent˜ o o devolve no mesmo socket para o a cliente. flags = fcntl ( listenfd . NULL)) < 0) err quit ( ”accept” ). • 84−85: configura as opcoes deste socket com a funcao setsockopt(2). exit (0). ¸˜ ¸˜ O arquivo utilizado como header e o mesmo timeofday. ¸˜ • 110 − 111: aguarda pela conex˜ o de algum cliente. Nota-se que n˜ o est´ o ´ e a a sendo usado nenhum timeout nessa operacao. isto significa que ı o socket deve realizar o bind. • 45 − 56: se algum dado foi lido anteriormente. TCP/IP 108 109 110 111 112 113 114 115 116 117 118 49 if (! FD ISSET ( listenfd . a • 113 − 114: ap´ s receber a conex˜ o de um cliente. a n˜ o ser que exista um outro socket ativo escutando no a mesmo endereco. flags | O NONBLOCK). if (( connfd = accept ( listenfd . adicionando uma constante informando que ele dever´ operar no modo n˜ oa a bloqueante. A seguir e mostrado o programa cliente para este servidor. com a constante ı SOL SOCKET. contendo os dados de um arquivo texto. realiza a leitura da resposta do servidor. F SETFL.

close (fd ). 50 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 if (( fd = open(filename . & write set . if ( in size == 0) { file EOF = 1. if ( select sock in ) FD SET (sockfd. sock EOF = 0. int sockfd) { int select sock in = 1. buff . int int int int int max fd = sockfd . & read set . read set . file EOF = 0. & write set ). char buff [MAXLINE]. /∗ le conteudo do arquivo para o buffer buff ∗/ if (! file EOF && in size == 0) { in size = read ( fd . ret = select ( max fd. shutdown write sock = 0. if ( fd > max fd) max fd = fd . int out size = 0. while (! done) { fd set write set . TCP/IP #include ”timeofday . &read set ). O RDONLY)) <= 0) err quit ( ”open”). } . FD ZERO (&write set). int fd . NULL). int select sock out = 1.h” void conecta ao servidor ( char ∗filename . NULL.´ CAPITULO 7. int in size = 0. FD ZERO (&read set). if ( ret < 0) err quit ( ” select ” ). ret . max fd++. done = 0. } else if ( in size < 0) { err quit ( ”read” ). sizeof ( buff )). if ( select sock out ) FD SET (sockfd. char outbuff [MAXLINE].

} } if ( file EOF && in size == 0 && !shutdown write sock ) { shutdown (sockfd . outbuff ). int sock error = 0. fd set write set . long flags . &read set )) { out size = read ( sockfd . socklen t sock error len . TCP/IP 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 51 } /∗ escreve o conteudo de buff para o sockfd ∗/ if ( in size > 0) { ret = write ( sockfd . select sock in = (! sock EOF && out size == 0). } else { err quit ( ” write” ). SHUT WR). } } if ( out size > 0) out size = 0. if ( out size == 0) { sock EOF = 1. char ∗∗argv) { int sockfd . SHUT RD). struct timeval tv . } /∗ le reply do servidor ∗/ if ( FD ISSET (sockfd. . in size ). if ( ret < in size ) { if ( errno == EAGAIN) { printf (”EAGAIN em write\n”). } printf ( ”%s”. } } else { in size = 0. shutdown (sockfd . buff . shutdown write sock = 1. struct sockaddr in servaddr . sizeof ( outbuff )). } int main ( int argc . outbuff . if ( sock EOF) done = 1.´ CAPITULO 7.

NULL. memset (&servaddr . SO ERROR. NULL. ( struct sockaddr ∗) & servaddr . sizeof ( servaddr )). tv usec = 0. if ( connect ( sockfd . servaddr . sin port = htons ( atoi ( argv [2])). sockfd ). flags = fcntl ( sockfd . nao e ’ necessario usar select () ∗/ } else { switch ( errno ) { case EINPROGRESS: /∗ select para escrita ∗/ FD ZERO (&write set).´ CAPITULO 7. ¸˜ • 119 − 122: conecta-se ao host local. &sock error len) < 0) err quit ( ”getsockopt ” ). exit (0). argv[0]). O uso da constante ¸ INADDR ANY permite que o bind seja feito em todas elas simultaneamente. } if (( sockfd = socket ( AF INET. sin family = AF INET. 0. s addr = htonl ( INADDR LOOPBACK). /∗ aguarda no maximo 30 segundos ∗/ tv . & write set )) err quit ( ” select ” ). exit (0). 0)) < 0) err quit (”socket” ). &tv) <= 0) err quit ( ” select ” ). if (! FD ISSET (sockfd. if ( getsockopt (sockfd . F GETFL). cada um correpondendo a uma interface de rede diferente. F SETFL. • 125 − 126: especifica o timeout a ser usado na chamada ao select(2). Novamente. if ( select ( sockfd + 1. sizeof ( servaddr )) == 0) { /∗ conexao ocorreu imediatamente . comecando a partir da funcao main(): ¸ ¸˜ • 113 − 117: cria um socket TCP e configura opcoes para o socket. servaddr . sin addr . Uma m´ quina em particular pode ter mais de um a endereco IP. conecta ao servidor ( argv [1]. SOL SOCKET. &sock error. FD SET (sockfd. & write set ). } Nesta vers˜ o do cliente temos tamb´ m algumas informacoes relevantes e que valem a pena a e ¸˜ serem descritas. tv sec = 30. TCP/IP 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 52 if ( argc < 3) { printf (”Sintaxe: %s <arquivo in> <porta>\n”. flags | O NONBLOCK). tv . fcntl ( sockfd . . servaddr . } } sock error len = sizeof ( sock error ). default : err quit ( ”connect” ). &write set. break. SOCK STREAM.

Esta funcao finaliza totalmente ou parcialmente uma conex˜ o full-duplex no socket especifiado ¸˜ a como primeiro argumento. n˜ o s˜ o permitidas a a a recepcoes futuras neste socket. executando os passos descritos abaixo. • 147 − 149: pega e limpa qualquer erro que tenha acontecido no socket. Esta chamada e desbloqueada assim que algum deles tiver seu valor ´ modificado. ou aguarda pela mudanca do estado do descritor de escrita do socket sockfd at´ receber o reply do ¸ e servidor. que impede transmiss˜ es ¸˜ o ¸˜ o sobre o socket. chama shutdown(2). • 32 − 43: prepara os conjuntos de descritores de leitura e escrita a serem monitorados pelo select(2). usando a chamada shutdown(2). e u • 57 − 68: caso tenha sido lido algum conte´ do. • 24 − 26: determina o maior descritor utilizado. O timeout imposto no exemplo e de 30 segundos. onde est´ u a estabelecida a conex˜ o com o servidor. Caso ele tenha lido o sinal de fim de e arquivo. • 21 − 22: abre o arquivo origem a ser enviado para o servidor. finaliza o socket para leitura. que impede recepcoes e transmiss˜ es sobre este socket. para uso no select(2). • 46 − 54: lˆ o conte´ do do arquivo para o buffer especificado por buff . Caso o segundo parˆ metro seja SHUT RD. ´ . TCP/IP 53 • 128: tenta conectar-se ao servidor. Ele pode ainda ser SHUT WR. que e o mesmo que foi enviado.´ CAPITULO 7. Neste exemplo. a • 69 − 72: caso o fim de arquivo tenha sido encontrado. ou ainda SHUT RDWR. ´ • 151: conecta-se ao servidor. segue adiante. ele finaliza o socket para escrita. escreve-o para o socket sockfd. • 75 − 80: lˆ o reply do servidor para o buffer outbuff. • 91: imprime o buffer lido. Caso consiga de imediato.

Essa funcao obt´ m do servidor todas as ´ ` ¸˜ e colunas retornadas pela query e as armazena no cliente. as colunas selecionadas s˜ o obtidas na forma de um conjunto de resultados. trˆ s implementacoes excelentes e e ¸˜ bastante est´ veis de banco de dados relacionais para o GNU/Linux. e ent˜ o a funcao mysql real connect() e chamada com este handler a a ¸˜ ´ (al´ m de outras informacoes como o hostname. o cliente pode enviar queries SQL para o servidor a usando mysql query() ou mysql real query(). a funcao mysql free result() libera o ¸˜ a mem´ ria utilizada durante ele. Uma delas e pela chamada a mysql store result(). o 54 . como INSERT. UPDATE e DELETE. pode-se citar o MySQL. nome do usu´ rio e senha). A diferenca entre estas duas funcoes ¸ ¸˜ est´ em que mysql query() espera que a query seja especificada como uma string terminada a a por NULL. a 8. Quando a a conex˜ o estiver encerrada. que inicia uma recuperacao coluna a coluna a partir do conjunto de ¸˜ resultados retornado. Ele inclui a biblioteca mysqlclient ¸˜ ´ ı e permite que programas em C acessem bancos de dados [MyS 2003]. caso uma query n˜ o possa ser efetuada devido a uma conex˜ o a ` a perdida. ¸˜ ı Entre eles. Para queries e ¸˜ do tipo SELECT. deve ser utilizada a mysql real query(). a Para queries que n˜ o envolvem selecao. Em ambos casos. Sobre esta conex˜ o. a Estes conjuntos de resultados podem ser processados de duas formas pelo cliente.1 Implementacoes ¸˜ Existem diversas implementacoes de servidores de banco de dados dispon´veis para o GNU/Linux. e feita uma chamada a funcao mysql init() para inicializar o ´ ` ¸˜ handler da conex˜ o. Esta flag indica que. A segunda forma e pelo uso da funcao ´ ¸˜ mysql use result(). o acesso as colunas e feito usando a chamada mysql fetch row(). e ¸˜ a a mysql real connect() configura o valor da flag reconnect (parte da estrutura do MySQL) para 1. a ¸˜ Enquanto uma conex˜ o estiver ativa. e poss´vel ver a ¸˜ ´ ı quantas colunas foram afetadas atrav´ s da funcao mysql affected rows(). Para conectar ao servidor. Ap´ s o processamento do conjunto de resultados. PostgreSQL e o Firebird. O banco de dados usado nos a exemplos ser´ o MySQL. enquanto a funcao mysql real query() espera uma string de tamanho j´ con¸˜ tado. a funcao mysql close() a termina. uma nova tentativa de reconex˜ o deve ser feita antes de retornar um erro. O tamanho dos dados em cada coluna pode ent˜ o ser informado atrav´ s da funcao a e ¸˜ mysql fetch lengths().Cap´tulo 8 ı Bancos de dados 8.2 Programando com Bancos de Dados em C A API para programacao em C e distribu´da com o MySQL. mysql fetch row() acessa as colunas que j´ foram lidas a do servidor. ` ´ Com mysql store result(). Caso a string contenha algum dado bin´ rio.

mas antes e necess´ rio criar o banco de dados e a tabela. e ´ a ´ necess´ rio executar alguns passos. mysql> CREATE DATABASE tabela_teste. Type ’\c’ to clear the buffer. Para compilar este exemplo basta: ¸˜ gcc insert_test. a a Ap´ s criado o banco de dados. insert.15a Type ’help.* TO user@localhost IDENTIFIED by ’senha’ Com isto o banco de dados tabela teste foi criada. Commands end with . com uma string chamada varchar e um inteiro chamado num. -> PRIMARY KEY (num) -> ). update. +------------------------+ | Tables_in_tabela_teste | +------------------------+ | produtos | +------------------------+ 1 row in set (0. update ¸˜ e exclus˜ o para o usu´ rio user@localhost. 0 rows affected (0. A senha deve ser informada entre aspas simples. Para isto. descritos logo abaixo: a $ mysql -u root -p Enter password: Welcome to the MySQL monitor. 1 row affected (0. produtos. e foi garantido acesso de insercao. or \g. -> num int not null.01 sec) mysql> SHOW TABLES.´ CAPITULO 8. Query OK. +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | name | varchar(80) | | | | | | num | int(11) | | PRI | 0 | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0. BANCOS DE DADOS 55 Com estas descricoes j´ e poss´vel escrever um aplicativo que comunique-se com o servi¸˜ a´ ı dor de banco de dados. delete -> ON tabela_teste.06 sec) mysql> GRANT select.’ or ’\h’ for help. Query OK.c -o insert_test -Wall ‘mysql_config --libs‘ .01 sec) Uma tabela chamada produtos foi criada sobre o banco tabela teste. Database changed mysql> CREATE TABLE produtos ( -> name varchar(80) not null. Your MySQL connection id is 4 to server version: 4. e necess´ rio criar a tabela sobre a qual as operacoes ser˜ o o ´ a ¸˜ a feitas: mysql> USE tabela_teste. O exemplo abaixo conecta-se ao servidor MySQL e realiza uma insercao de dados sobre a tabela criada.00 sec) mysql> DESCRIBE produtos. A partir de agora e poss´vel operar sobre estas estruturas ´ ı utilizando um programa em C.0.

qbuf )) { fprintf ( stderr . if (! sock ) { fprintf ( stderr . mysql error ( mysql )). ” mysql real connect : %s\n” . } A execucao deste programa pode ser feita da seguinte maneira: ¸˜ $ . 0. if ( argc != 3) { fprintf ( stderr . NULL. if (! mysql) { fprintf ( stderr . count). exit (1). INSERT QUERY. char qbuf [160]. argv [1]. if ( mysql query (sock . ”mysql query: %s\n” . BANCOS DE DADOS #include <stdio . ”senha” .h> #define INSERT QUERY ”insert into produtos (name. } mysql close ( sock ). exit (1). } mysql = mysql init ( mysql). } 56 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 sock = mysql real connect ( mysql .´ CAPITULO 8. %d)” int main(int argc . exit (0). ” mysql init : %s\n” . ” localhost ” . int count .h> #include < stdlib .num) values (’ item %d’. 0). while ( count < num) { sprintf ( qbuf . exit (1). ”Sintaxe: %s <dbname> <numero>\n”. argv[0]). h> #include <mysql/mysql. } count++. count = 0./insert_test tabela_teste 5 E o resultado ser´ refletido imediatamente no banco de dados: a . mysql error ( sock )). num. MYSQL ∗mysql = NULL. } num = atoi ( argv [2]). exit (1). ” lucasvr ” . mysql error ( mysql )). char ∗∗argv) { MYSQL ∗sock = NULL. count.

00 sec) 57 .´ CAPITULO 8. +--------+-----+ | name | num | +--------+-----+ | item 0 | 0 | | item 1 | 1 | | item 2 | 2 | | item 3 | 3 | | item 4 | 4 | +--------+-----+ 5 rows in set (0. BANCOS DE DADOS mysql> SELECT * from produtos.

caso seja utilizado um.2 a • Laco de tratamento de eventos: finalmente. ¸˜ ¸˜ ı O X Window System define padr˜ es que devem ser adotados por implementacoes deste o ¸˜ ambiente. A seguinte estrutura deve ser respeitada para a criacao de uma aplicacao no X: ¸˜ ¸˜ • Inicializacao: durante a inicializacao. estes eventos s˜ o primeiro tratados internamente e. o programa far´ o tratamento de opcoes de linha de ¸˜ ¸˜ a ¸˜ comando. teclado e a ´ ı mouse. e subjanela de outra. chamada de raiz. o X n˜ o e nem possui uma interface com o usu´ rio. como no OS/2 e no QNX. explicada ¸˜ na Sess˜ o 9. dependendo a 58 . movimento do mouse ou requisicao do servidor para redesenhar o conte´ do de ¸˜ u suas janelas. exceto uma. Uma aplicacao pode usar muitas janelas de cada vez.1 Servidor X O X Window System[SCH 86] foi criado em 1984 no Massachussets Institute of Technology (MIT) para dar suporte a dois projetos: o projeto Athena. mecanismos de comunicacao ena e a ¸˜ tre clientes e entrada de dados por dispositivos como mouse e teclado. menus. que precisava de ¸˜ um ambiente de depuracao para aplicacoes multiprocessadas distribu´das [KOJ 2000]. bot˜ es etc. o ¸˜ e Qualquer coisa que se queira apresentar na tela deve ser desenhada dentro de uma janela. ou usando as funcoes primitivas da Xlib.Cap´tulo 9 ı Interface Gr´ fica a 9. como pressionamento de teclas ou bot˜ es do o mouse. e em outras ´ ´ ı ¸ ele o e sobre a forma de uma licenca comercialial. conectados ao servidor atrav´ s de uma rede. ou seja. ´ ¸ O sistema possui arquitetura cliente-servidor. Portanto. o programa entra em um laco. conex˜ o com o servidor X e alocacao de estruturas internas. O servidor localiza-se na estacao de trabalho ¸˜ do usu´ rio e provˆ acesso transparente ao hardware gr´ fico. Menus e outros elementos da interface ¸˜ podem ser constru´dos com janelas que se sobrep˜ em as demais. O ambiente que o implementa e d´ suporte para os sistemas operacionais UNIX e a GNU/Linux e o XFree86. e como um driver de v´deo. • Montagem da interface gr´ fica: ap´ s aberta a conex˜ o com o servidor. Qualquer janela. As janelas s˜ o organizadas em ı o ` a uma hierarquia. o programa pode a o a criar e montar sua interface (janelas. ´ O X foi projetado de forma a fornecer mecanismos para que diferentes pol´ticas de interface ı com o usu´ rio pudessem ser implementadas. Tudo isto e feito a ¸˜ ´ internamente pelo toolkit. o que facilita o gerenciamento. que precisava de um sistema de janelas que pudesse ser usado em centenas de estacoes de trabalho e o projeto Argus. Em toolkits. onde fica ¸ ¸ esperando por eventos vindos do servidor. chamadas ´ toolkits. Nestas plataformas ele e distribu´do sob uma licenca livre. A funcao de prover a ´ a ¸˜ tal interface e delegada aos clientes e bibliotecas especiais externos ao servidor X.) utilizando os widgets (elementos o da interface) oferecidos pelo toolkit. Os clientes podem ser executados na pr´ pria estacao ou remotamente.

´ ´ CAPITULO 9. tais como gerenciadores de janelas e pro¸˜ ı cessadores de imagens. por exemplo). } . h> #include <gtk/gtk . redimensionamento e sobreposicao de janelas. criacao. ou quase. al´ m da construcao de interfaces com o usu´ rio. a ¸˜ a Alguns exemplos s˜ o o KDE. gpointer data ) { gtk main quit (). E por isto que existem os toolkits. Eles fazem isto com base em um conjunto ¸˜ de convencoes estabelecidas entre ele e os clientes. ¸˜ ı Gerenciadores de janelas s˜ o muito uteis porque implementam as pol´ticas de atribuicao do a ´ ı ¸˜ foco. ter˜ o obrigatoriamente que usar as funcoes da Xlib. Devido ´ ¸˜ ¸˜ a essa caracter´stica. e 9.h> void quit hello ( GtkWidget ∗widget. ¸˜ a ¸˜ A criacao de um programa GTK+ e feita conforme os seguintes passos mostrados no exem¸˜ ´ plo abaixo (este programa deve ser compilado com a flag -lgtk para ser linkado com a biblioteca GTK+): 1 2 3 4 5 6 7 8 9 #include <unistd . por meio de uma disciplina de programacao. a programacao nela pode se tornar um tanto tediosa.4 apresenta o modelo de programacao usado com a toolkit GTK+. pois e necess´ rio ı ¸˜ ´ a emular a programacao orientada a objetos “na m˜ o”. com o protocolo ¸˜ e X. Os toolkits permitem. a ¸˜ 9. com inspiracao em orientacao a objetos. ¸˜ N˜ o e aconselh´ vel usar apenas a Xlib para escrever aplicacoes complexas. s˜ o repassados ao ´ a a programa atrav´ s de callbacks ou mecanismos similares. usando mecanismos diversos como trocas de ¸˜ mensagens e eventos. que oferece funcoes com correspondˆ ncia direta. destruicao e ¸˜ a ¸˜ ¸˜ manipulacao de janelas. pois al´ m disso ser muito trabalhoso levar´ a existˆ ncia de a e a` e ´ aplicacoes com interfaces inconsistentes umas com a as outras. que usa o GTK+ (C). tratar ı e ¸˜ a de outras necessidades da aplicacao. ¸˜ que utilizam a Xlib na sua implementacao. Ela foi definida como padr˜ o pelo X Consortium e e uma biblioteca a ´ em linguagem C.3 Gerenciadores de Janelas Programas que realizam operacoes de baixo n´vel. INTERFACE GRAFICA 59 do caso (quando o mouse e clicado em um widget bot˜ o. desenho e recebimento de eventos. Uma abordagem a ¸˜ bastante comum em aplicacoes complexas e usar um toolkit para construir a interface e funcoes ¸˜ ´ ¸˜ da Xlib para operacoes de baixo n´vel. entre outros.2 A biblioteca Xlib A Xlib e a API (Application Programs Interface) de mais baixo n´vel dispon´vel para se pro´ ı ı gramar aplicacoes para X (a n˜ o ser que a aplicacao utilize o protocolo X diretamente para se ¸˜ a ¸˜ comunicar com o servidor). mas oferecem um maior grau de abstracao e funcoes ¸˜ ¸˜ ¸˜ de mais alto n´vel. que utiliza o toolkit Qt (C++) e o GNOME. ¸ 9. a A Sess˜ o 9. Possui funcoes para abrir uma conex˜ o com um servidor (display). tais como configuracao.4 GTK+ GTK+ e uma biblioteca de widgets escrita em C. Normalmente o gerenciador de janelas utilizado no desktop do programador o influencia na tomada de decis˜ o sobre qual biblioteca de widgets usar para criar suas aplicacoes gr´ ficas. que possuam a ´ a ¸˜ interfaces com usu´ rio sofisticadas. tratamento de erros e acesso a ¸˜ ¸˜ servicos do sistema operacional.

exit (0). GTK OBJECT (window)). ı Como pode-se imaginar. gtk container add ( GTK CONTAINER (window). pois o usu´ rio ter´ o compromisso de escrever todas as rotinas de a a posicionamento de janelas e bot˜ es manualmente. ¸˜ a • 15: inicializacao do GTK+. ¸˜ a ¸˜ • 18 − 19: conex˜ o do sinal destroy a funcao quit hello(). o • 30: entra em um loop infinito de processamento de eventos. char ∗∗argv) { GtkWidget ∗window.2 mostram o processo de criacao de um bot˜ o em uma nova janela e uma ¸˜ a janela mais complexa. torna-se invi´ vel escrevˆ -lo a e diretamente sobre o GTK+. INTERFACE GRAFICA 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 60 int main ( int argc . gtk signal connect ( GTK OBJECT (window). GTK SIGNAL FUNC (gtk widget destroy). que faz o seguinte: ´ • 4 − 8: declara a funcao que ser´ chamada quando a janela receber o sinal destroy. window = gtk window new (GTK WINDOW TOPLEVEL). a ` ¸˜ • 21: criacao de um bot˜ o. } Este e um dos programas mais simples que pode ser escrito em GTK+. gtk widget show ( window). a ¸˜ passando como parˆ metro o objeto window. gtk signal connect object ( GTK OBJECT (button). na medida em que o programa cresce. pode ser utilizado o Designer para desenvolver aplicacoes gr´ ficas muito rapidamente. contendo bot˜ es e combo boxes. ”clicked”. ` e Uma solucao que v´ rios projetos tˆ m criado e a adocao de uma interface gr´ fica para mani¸˜ a e ´ ¸˜ a pular as bibliotecas de widgets. o que acaba tomando muito tempo e levando o a ocorrˆ ncia dos bugs mais diversos. a ´ • 28: faz com que a janela seja vis´vel na tela. a • 17: criacao de uma janela principal (TOPLEVEL). o ¸˜ ´ a tratamento de opcoes de linha de comando padr˜ o e outras inicializacoes internas.´ ´ CAPITULO 9. NULL). gtk main ().1 e 9. que tamb´ m ¸˜ a e aumenta muito a producao de c´ digos baseados no ambiente de janelas do XFree86. chama a funcao gtk widget destroy. No caso do QT. ¸˜ a • 22 − 24: quando o bot˜ o receber o sinal clicked. gtk widget show ( button ). ¸˜ o As Figuras 9. gtk init (&argc. button = gtk button new with label ( ”Ola” ). button). ”destroy”. GTK SIGNAL FUNC (quit hello). ¸˜ • 26: o bot˜ o e colocado dentro da janela principal. &argv ). e com o GTK+ pode ser usado o Glade. . Nesta etapa e realizada a conex˜ o com o servidor X. ∗button. ı • 27: faz com que o widget seja vis´vel.

´ ´ CAPITULO 9.2: Construcoes mais complexas s˜ o constru´das rapidamente no Glade ¸˜ a ı .1: Inserindo um bot˜ o em uma nova janela com o Glade a Figura 9. INTERFACE GRAFICA 61 Figura 9.

O argumento port e definido como unsigned e ` ´ long para algumas plataformas. ou complexas demais a ponto de ser importante utilizar alguma biblioteca para auxiliar as operacoes sobre estes dispositivos. lp1 para a segunda e assim ¸˜ ´ sucessivamente. unsigned short int port). lˆ em ou escrevem count bytes. a forma mais simples e r´ pida de program´ -la e com o uso da fam´lia inb(2) a a ´ ı e outb(2) [RUB 2001]. • unsigned int inl (unsigned short int port). A porta paralela tamb´ m pode ser programada utilizando diretamente o dispose itivo port. acessam portas de 16-bits. lˆ em ou escrevem bytes (8 bits) a porta port. Elas n˜ o est˜ o dispon´veis nas plataformas M68K e S390. e unsigned short para outras. void *addr. void outb (unsigned char value.1 Porta Paralela Existem duas formas de acesso a dispositivos na porta paralela. void *addr. tudo e um arquivo. que a a ı suportam apenas I/O orientado a bytes. ı • void insb (unsigned short int port. Seguindo esta filosofia. estas macros acessam portas de 32-bits. unsigned short int port). A seguir s˜ o definidos os prot´ tipos das macros associadas a elas: a o ` • unsigned char inb (unsigned short int port). a maneira utilizada para programar dis´ positivos e a mesma usada para tratar arquivos utilizando operacoes com descritores de arquivos. Neste caso. Assim como em I/O de 16-bits. unsigned long int count). ¸˜ No entanto.Cap´tulo 10 ı Comunicacao ¸˜ Em UNIX. de acordo com a plataforma. operacoes sobre certos dispositivos podem ser triviais o suficiente para n˜ o necessitar ¸˜ a o uso destes recursos. unsigned short int port). que j´ d´ suporte ao acesso a porta. ´ ¸˜ No entanto. ¸˜ A seguir s˜ o apresentadas as formas de acesso aos dispositivos serial. esta operacao n˜ o est´ ¸˜ a a dispon´vel nos M68K e S390. usando operacoes sobre descritores de arquivos como read(2) e write(2). iniciando no endereco de mem´ ria addr. paralelo e USB. value e declarado unsigned long ou unsigned ´ int. o dependendo da distribuicao) e o lp0 para a primeira porta paralela. unsigned long int count). a 10. void outsb (unsigned short int port. void outl (unsigned char value. void outw (unsigned char value. O que acontece com ela no Linux ` e que existe um driver padr˜ o chamado lp. o ´ a a a ` dispositivo criado na entrada /dev (ou outro diret´ rio usado para armazenar os dispositivos. Os dados s˜ o e ¸ o a 62 . e • unsigned short int inw (unsigned short int port). O tipo de retorno de inb tamb´ m difere entre diferentes arquiteturas.

h> /∗ para a libc5 ∗/ #include <sys/io . esta funcao permite que as permiss˜ es sejam herdadas tanto pelo fork(2) ¸˜ o como pelo exec(3). void *addr. ¸˜ e a As permiss˜ es de acesso n˜ o s˜ o herdadas no fork(2). unsigned short int port). para o valor turn on. caso contr´ rio as referˆ ncias n˜ o poder˜ o ı ¸˜ ı a e a a ser resolvidas em tempo de linkagem do programa. Alguns processadores implementam ¸ a instrucoes especiais para transferir uma seq¨ encia de bytes. unsigned long int count). Os problemas podem ocorrer porque o processador e overclocked em respeito ao bus ISA. o iopl(2) deve ser utilizado: #include <sys/io . h> int iopl ( int level ). 63 Estas macros {in. Podem ser utilizadas as flags -O ou -O2. mas s˜ o no exec(3).out}s* operam com os mesmo tipos das macros anteriores. void outb p (unsigned char value. e vai at´ 3. unsigned long int count). Para isto s˜ o utilizados os a a programas ioperm(2) ou o iopl(2): #include <unistd . lˆ em ou escrevem valores de 16-bits para uma porta de 16-bits. esta ¸˜ a macro e expandida para as funcoes correspondentes sem o “ p”. ioperm(2) configura os bits de acesso a porta para o processo para num bytes. Para portas fora deste intervalo. por exemplo. unsigned long int count). ¸˜ e ı Assim. • void insw (unsigned short int port. elas s˜ o a ¸˜ a implementadas via software na forma de um loop. void outl p (unsigned char value. void outw p (unsigned char value. void outsw (unsigned short int port. o a a a e ioperm(2) permite acesso para as primeiras 0x3ff portas de I/O. Para poder operar sobre as portas seriais e paralelas em espaco de usu´ rio. unsigned long num. Nas arquiteturas que n˜ o enfrentam este problema. lˆ em ou escrevem valores de 32-bits para uma porta de 32-bits. h> /∗ para a glibc ∗/ int ioperm (unsigned long from . COMUNICACAO ¸ ˜ lidos e escritos na porta port. inclusive permitindo que o pro` cesso desabilite interrupcoes (o que provavelmente ir´ causar um crash no sistema). No caso da arquitetura n˜ o suportar este tipo de instrucao. unsigned short int inw p (unsigned short int port). unsigned long int count). com a diferenca de que estas s˜ o orientadas a strings. Diferente ¸˜ a da ioperm(2). unsigned short int port). Esta funcao altera os privil´ gios de I/O do processo atual para o n´vel especificado em level. unsigned int inl p (unsigned short int port). ı a ´ e . void *addr. O n´vel padr˜ o para um processo normal e 0. que podem acontecer quando ´ os dispositivos da placa s˜ o muito lentos. ´ ¸˜ Estas funcoes s˜ o na verdade definidas como macros inline. e necess´ rio ¸ a ´ a requisitar acesso para o kernel para as portas de I/O em quest˜ o. o processo tem acesso irrestrito a portas de acesso I/O.´ CAPITULO 10. void outsl (unsigned short int port. e • void insl (unsigned short int port. comecando ` ¸ na porta from. e • unsigned char inb p (unsigned short int port). void *addr. e precisam ser compiladas com ¸˜ a n´vel de otimizacao habilitado para serem substitu´das. A solucao nestes casos e inserir um pequeno a ¸˜ ´ delay entre cada instrucao de I/O. words ou longs de e para ¸˜ uˆ uma porta de I/O. unsigned short int port). void *addr. Algumas plataformas – principalmente o i386 – pode ter problemas quando o processador tenta transferir dadas muito rapidamente do ou para o bus. O uso desta funcao requer privil´ gios de superusu´ rio. Al´ m disto. int turn on ).

equivalente a ` COM1 no DOS. ¸˜ ı • tcflag t c cflag: descreve opcoes de controle. caracteres especiais como erase. como o erase e o delete. Feito isso. pelo fato de ter caracter´sticas extras a serem consideradas quando ı programadas – como a baud rate e paridade de bits –.c cflag |= CS8. a Devido as diferentes interfaces que s˜ o dispon´veis para configurar a baud rate entre v´ rios ` a ı a sistemas operacionais. COMUNICACAO ¸ ˜ 64 10. ı Relativo a paridade. controlam a baud rate. ou seja: uma operacao de leitura s´ ir´ retornar o ¸˜ o a quando tiver lido um caracter de fim de linha (\n) ou um caracter de carriage return (\r). onde n indica o n´ mero a e u da porta serial. e a leitura n` o e afetada caso caracteres especiais sejam a ´ lidos. o a o • tcflag t c iflag: opcoes de entrada de dados. • cc t c cc[]: caracteres de controle. Existem trˆ s modos de operacao de leitura sobre portas seriais.c cflag |= CS7 | PARENB. • Sem paridade (8N1): options. e ent˜ o restaurar o seu estado ao ´ a a t´ rmino do programa. delete s˜ o reconhecidos e tratados a como tal. a quantidade de ¸˜ bits de dados. ¸˜ • cc t c line: disciplina da linha. stop bits e o controle de fluxo de hardware. mas sobre a o a ´ quantidades fixas de caracteres.2 Porta Serial Portas seriais s˜ o identificadas no Linux atrav´ s dos dispositivos ttySn. • Modo Ass´ncrono: este modo permite que a chamada read(2) retorne imediatamente.c cflag |= CS7 | PARENB | PARODD. Por exemplo. uma estrutura chamada struct termios e usada. ı sendo que um sinal e enviado ao programa (SIGIO) quando os dados estiverem dispon´veis ´ ı para leitura. kill. No entanto. 10. basta especificar as informacoes necess´ rias para configurar e ¸˜ a a porta serial e iniciar a leitura e escrita de dados a porta com o uso da chamada read(2) e ` write(2). respectivamente. • Modo N˜ o-Canˆ nico (raw): o processamento n˜ o e realizado sobre linhas. a porta ttyS0 referencia a primeira porta serial. ¸˜ • tcflag t c lflag: flags para o modo local (canˆ nico. n˜ o-canˆ nico). paridade. A constantes dispon´veis ı para serem usadas podem ser vistas na Tabela 10. a programacao sobre portas paralelas ¸˜ envolve alguns passos extras. Nesse modo. Elas ir˜ o garan¸˜ a tir que o programa n˜ o vir´ a ser o “propriet´ rio” da porta relativo a controles espor´ dicos de job a a a ` a e de sinais de hangup. Ela apresenta ´ os seguinte membros: • tcflag t c oflag: opcoes para a sa´da de dados. ` Na listagem abaixo assume-se que a c cflag foi previamente inicializada com algum outro campo (como o CLOCAL | CREAD): • Com paridade par (7E1): options.1 A interface Termios Para lidar com a serial no Linux. costuma-se usar as funcoes cfsetispeed(3) e cfsetospeed(3) ¸˜ para informar a taxa de entrada e sa´da. e que o driver da interface serial ser´ capaz de ler dados de entrada. • Com paridade ´mpar (7O1): options. Outro detalhe a ser visto e o da configuracao da porta serial: como o programa ir´ modific´ ´ ¸˜ a a la.´ CAPITULO 10.2. ı . e interessante salvar o estado da porta antes de alter´ -la. que s˜ o: e ¸˜ a • Modo Canˆ nico: trabalha sobre linhas. representadas pela c cflag. basta combinar as flags sobre a c cflag para obter a paridade desejada.1 Duas opcoes da c cflag devem estar sempre habilitadas: CLOCAL e CREAD. As opcoes de controle.

5 baud 150 baud 200 baud 300 baud 600 baud 1200 baud 1800 baud 2400 baud 4800 baud 9600 baud 19200 baud 38400 baud 57.600 baud 76. O restante das opcoes s˜ o mantidas por raz˜ es hist´ ricas e datam da ¸˜ a o o epoca em que impressoras e terminais n˜ o conseguiam manter-se em sincronia com as streams ´ a .3.´ CAPITULO 10. As opcoes de entrada s˜ o informadas pelo membro c iflag. O membro c oflag cont´ m opcoes de filtro de sa´da.1: Constantes para o membro c cflag Constante B0 B50 B75 B110 B134 B150 B200 B300 B600 B1200 B1800 B2400 B4800 B9600 B19200 B38400 B57600 B76800 B115200 EXTA EXTB CS5 CS6 CS7 CS8 CSTOPB CREAD PARENB PARODD HUPCL CLOCAL LOBLK CRTSCTS Descricao ¸˜ 0 baud (descarta informacao de Data Terminal Ready) ¸˜ 50 baud 75 baud 110 baud 134.2 mostra as opcoes dispon´veis para este o a o ¸˜ ı campo. As opcoes locais podem ser configuradas sobre o membro c lflag. de acordo com os valores vistos ¸˜ a na Tabela 10. A Tabela 10. Normalmente ele ser´ configurado para a a o modo canˆ nico ou n˜ o-canˆ nico (raw). provavelmente a unica utilizada ser´ a ONLCR para mapear novas ¸˜ ´ a linhas para pares CR-LF. pode ser e ¸˜ ı escolhido modo processado ou raw.200 baud Taxa externa de clock Taxa externa de clock 5 bits de dados 6 bits de dados 7 bits de dados 8 bits de dados 2 stop bits (1 otherwise) Habilita recepcao de dados ¸˜ Habilita bit de paridade Usa paridade ´mpar ao inv´ s de par ı e Hangup (descarta DTR) no ultimo close ´ Linha local . Como nos modos de entrada.n˜ o modifica o “propriet´ rio” da porta a a Bloqueia sa´da de controle de jobs ı Habilita fluxo de controle em hardware 65 • Com paridade de espaco (7S1): utiliza a mesma configuracao do modo sem paridade ¸ ¸˜ (8N1). COMUNICACAO ¸ ˜ Tabela 10. ¸˜ ı De todas estas opcoes. A Tabela 10. e ditam como os caracteres ¸˜ de entrada (leitura) ser˜ o manipulados pelo driver serial.800 baud 115.4 mostra as opcoes dispon´veis.

Alguns ds dados suportados ¸˜ a neste array est˜ o listados na Tabela 10.´ CAPITULO 10. COMUNICACAO ¸ ˜ Tabela 10. Neste exemplo. O ultimo conjunto de opcoes que restam para permitir a configuracao da porta serial s˜ o ´ ¸˜ ¸˜ a os caracteres de controle. pode-se utilizar o modo canˆ nico – a o orientado a linhas.2 Modo canˆ nico o Para comunicar-se com um modem configur´ vel via serial. O programa a seguir pode ser utilizado para resetar o modem e ler os dados enviados por ele. SIGSUSP.5. a a .2: Constantes para o membro c lflag Constante ISIG ICANON XCASE ECHO ECHOE ECHOK ECHONL NOFLSH IEXTEN ECHOCTL ECHOPRT ECHOKE FLUSHO PENDIN TOSTOP Descricao ¸˜ Habilita sinais SIGINTR.2. O restante pode ser consultado a partir do header a bits/termios. n˜ o h´ uma forma de encerrar o programa de forma natural. Eles s˜ o configur´ veis em um array chamado c cc que cont´ m tanto a a e definicoes de caracteres de controles como parˆ metros de timeout.3: Constantes para o membro c iflag Constante INPCK IGNPAR PARMRK ISTRIP IXON IXOFF IXANY IGNBRK BRKINT INLCR IGNCR ICRNL IUCLC IMAXBEL Descricao ¸˜ Habilita checagem de paridade Ignora erros de paridade Marca erros de paridade Tira bits de paridade Habilita controle de fluxo de software para sa´da ı Habilita controle de fluxo de software para entrada Permite que qualquer caracter inicie o fluxo novamente Ignora condicao de break ¸˜ Envia um sinal SIGINT quando uma condicao de break for detectada ¸˜ Mapeia nova linha (NL) para carriage return (CR) Ignora caracter CR Mapeia CR para NL Mapeia uppercase para lowercase Ecoa BEL para linhas de entrada muito longas de dados da porta serial. 10. SIGDSUSP e SIGQUIT Habilita modo de entrada canˆ nico (raw mode caso contr´ rio) o a Mapeia uppercase para lowercase (obsoleto) Habilita eco de caracteres de entrada Ecoa o caracter de erase como BS-SP-BS Ecoa nova linha (NL) ap´ s o caracter de kill o Ecoa NL Desabilita flush de buffers de enrada ap´ s caracteres de interrupt ou quit o Habilita funcoes estendidas ¸˜ ˜ Ecoa caracteres de controle como char e delete como ? ˆ Ecoa caracteres apagados como um caractere apagado BS-SP-BS em toda a linha quando receber um line kill Sa´da sendo flushed ı Processa entrada pendente na pr´ xima leitura ou caracter de entrada o Envia SIGTTOU para sa´da em background ı 66 Tabela 10.h.

4: Constantes para o membro c oflag Constante OPOST OLCUC ONLCR OCRNL NOCR ONLRET OFILL OFDEL NLDLY NL0 NL1 CRDLY CR0 CR1 CR2 CR3 TABDLY TAB0 TAB1 TAB2 TAB3 BSDLY BS0 BS1 VTDLY VT0 VT1 FFDLY FF0 FF1 Descricao ¸˜ P´ s-processa a sa´da (n˜ o setado = sa´da raw) o ı a ı Mapeia lowercase para uppercase Mapeia NL para CR-NL Mapeia CR para NL N˜ o gera CR na sa´da na coluna 0 a ı NL realiza a funcao de CR ¸˜ Usa caracteres de preenchimento (fill) para delay Caractere de preenchimento e DEL ´ M´ scara para delay entre linhas a Nenhum delay para NLs Delay de novas sa´das ap´ s NL para 100 mili-segundos ı o M´ scara para delay para retornar o carro para a coluna da esquerda a Nenhum delay para CRs Delay ap´ s CRs dependendo da posicao da coluna atual o ¸˜ Delay de 100 mili-segundos ap´ s enviar CRs o Delay de 150 mili-segundos ap´ s enviar CRs o M´ scara para delay ap´ s TABs a o Nenhum delay para TABs Delay ap´ s TABs dependendo da posicao da coluna atual o ¸˜ Delay de 100 mili-segundos ap´ s enviar TABs o Expande caracteres de TAB para espacos ¸ M´ scara para delay ap´ s BSs a o Nenhum delay para BSs Delay de 50 mili-segundos ap´ s enviar BSs o M´ scara para delay ap´ s VTs a o Nenhum delay para VTs Delay de 2 segundos ap´ s enviar VTs o M´ scara para delay ap´ s FFs a o Nenhum delay para FFs Delay de 2 segundos ap´ s enviar FFs o 67 Tabela 10.´ CAPITULO 10. COMUNICACAO ¸ ˜ Tabela 10.5: Constantes para o membro c cc[] Constante VINTR VQUIT VERASE VKILL VEOF VEOL VEOL2 VMIN VTIME Descricao ¸˜ Interrupt Quit Erase Kill-line Fim de arquivo Fim de linha Segundo fim de linha N´ mero m´nimo de caracteres para serem lidos u ı Tempo para aguardar por dados (d´ cimos de segundos) e Valor default CTRL-C CTRL-Z Backspace (BS) CTRL-U CTRL-D Carriage return (CR) Line feed (LF) - .

O RDWR | O NOCTTY).h> ∗/ #define BAUDRATE B9600 #define DEVICE ”/dev/ttyS0” int main ( int argc . h> #include <sys/ types .h> #include <unistd .´ CAPITULO 10. char ∗∗argv) { int fd . senao um CR nos ∗ dados de entrada pode nao terminar a leitura ∗/ newtio . COMUNICACAO ¸ ˜ 68 pois o loop de leitura e infinito. res . /∗ ∗ Abre porta para leitura / escrita e nao como uma tty de controle . 1 stopbit ) ∗ CLOCAL : Conexao local .h> /∗ Configuracoes de baud rate sao definidas em <asm/termbits. Em um caso real. /∗ ∗ IGNPAR : ignora bytes com erros de paridade ∗ ICRNL : mapeia CR (carriage return ) para NL (new line ). . 0. & oldtio ). sem controle do modem ∗ CREAD : Habilita a recepcao de caracteres ∗/ newtio . } /∗ Salva a configuracao atual da porta serial e inicia uma nova ∗/ tcgetattr ( fd. seria necess´ rio verificar o conte´ do do buffer ´ a u lido para decidir quando encerrar o loop.h> #include <termios . newtio. /∗ ∗ CRTSCTS : Controle de fluxo de saida do hardware ∗ CS8 : 8 n1 (8 bit .h> #include <sys/ stat . c iflag = IGNPAR | ICRNL.h> #include < fcntl . /∗ Seta baud rate de entrada e saida ∗/ cfsetispeed (&newtio . exit (1). if ( fd < 0) { perror ( ”open”). BAUDRATE). sizeof ( newtio )). memset (&newtio . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <stdio . char buf [255]. c cflag = CRTSCTS | CS8 | CLOCAL | CREAD. struct termios oldtio . no parity . para ∗ evitar que o programa encerre se vier um CTRL+C na linha ∗/ fd = open (DEVICE. h> #include < string . h> #include < stdlib .

/∗ reseta o dispositivo ( modem) ∗/ if ( write ( fd . TCIFLUSH). c cc [VWERASE] = 0. c cc [VSTART] = 0. ”[%s] (%d)\n” . // Ctrl−W newtio .´ CAPITULO 10. 4) < 4) perror ( ” write” ). // bloqueia leitura ate ’ ler 5 caracteres newtio . // DEL newtio . c cc [VMIN] // ’\0’ newtio . while (1) { res = read ( fd . para poder imprimir o conteudo com printf ∗/ buf[ res ] = 0. ”ATZ\r”. c cc [VSUSP] = 0. /∗ ∗ ICANON : habilita entrada em modo canonico ∗ desabilita funcionalidades de ’ echo ’. c lflag = ICANON. c cc [VEOL] = 0. c cc [VKILL] = 0. COMUNICACAO ¸ ˜ 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 69 cfsetospeed (&newtio . res ). c cc [VEOF] = 4. c cc [VEOL2] = 0. } /∗ Seta final de string . /∗ ∗ Inicializa todos os caracteres de controle . c oflag = 0. e nao envia sinais para o programa ∗/ newtio . buf . /∗ Saida em modo ’raw’ ∗/ newtio . // Ctrl−Q newtio . ∗ Os valores padrao podem ser encontrados em ’/ usr / include / termios . c cc [VLNEXT] = 0. // Ctrl−U newtio .1 segs) = 5. c cc [VTIME] = 0. c cc [VSWTC] = 0. if ( res < 0) { perror ( ”read” ). c cc [VERASE] = 0. newtio . BAUDRATE).h’ ∗/ newtio . // CR // Ctrl−R newtio . // @ newtio . // timeout entre leituras ( t=VTIME ∗ 0. c cc [VQUIT] = 0. &newtio). // Ctrl−’\’ newtio . buf . c cc [VREPRINT] = 0. // Ctrl−Z newtio . exit (1). 255). // Ctrl−D ∗/ newtio . tcsetattr ( fd . } /∗ Restaura as configuracoes antigas da porta ∗/ . // ’ Ctrl−C newtio . // Ctrl−S newtio . c cc [VINTR] = 0. /∗ ’ Limpa’ a linha e ativa as configuracoes para a porta ∗/ tcflush ( fd . TCSANOW. fprintf ( stdout . c cc [VSTOP] = 0. // Ctrl−V // LF newtio . c cc [VDISCARD] = 0. newtio .

0. newtio. Ele configura um timeout entre leituras de caracteres (ap´ s o sinal de nova linha) de 0. &oldtio). habilitando a entrada em modo n˜ o-canˆ nico.h> #include <sys/ stat .h> ∗/ #define BAUDRATE B9600 #define DEVICE ”/dev/ttyS0” int main ( int argc . h> #include < stdlib . a o O exemplo abaixo mostra como trabalhar neste modo. close ( fd ).h> #include <termios . exit (1). COMUNICACAO ¸ ˜ 106 107 108 109 70 tcsetattr ( fd . res . a ` As funcoes cfsetispeed(3) e cfsetospeed(3) permitem que seja utilizada uma ¸˜ taxa de baud rate diferente para a entrada e a sa´da de dados. sizeof ( newtio )). e o ¸ a o a o o ´ n˜ o-mapeamento do carriage return para o caracter de nova linha (pois n˜ o estamos trabalhando a a baseados em linhas. fd = open (DEVICE. TCSANOW.c cflag no Linux.h> #include <unistd . char ∗∗argv) { int fd . Os valores default o est˜ o comentados a direita de cada um.2. if ( fd < 0) { perror ( ”open”).´ CAPITULO 10. Neste exemplo foi utilizada a ı mesma taxa.5 segundos. & oldtio ).h> #include < fcntl . no que diz respeito ao c´ digo. } Nesse exemplo. h> #include <sys/ types . memset (&newtio .h> /∗ Configuracoes de baudrate sao definidas em <asm/termbits. /∗ .c lflag como ¸˜ a 0. struct termios oldtio . exit (0). vale notar que alguns caracteres de controle s˜ o inicializados com 0 mesmo a ap´ s a estrutura ter sido preenchida com 0’s atrav´ s da funcao memset(3). mas sim em caracteres) e da especificacao da vari´ vel newtio. Isto foi feito apenas o e ¸˜ para mostrar no c´ digo a possibilidade de trocar os caracteres de controle. } /∗ Salva a configuracao atual da porta serial e inicia uma nova ∗/ tcgetattr ( fd. o que seria equivalente a passar a constante BAUDRATE juntamente na vari´ vel a newtio.3 Modo n˜ o-canˆ nico (raw) a o A diferenca b´ sica entre o modo canˆ nico e o n˜ o-canˆ nico. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <stdio . al´ m de aguardar a leitura de o e pelo menos 5 caracteres. char buf [255]. 10. O RDWR | O NOCTTY). h> #include < string .

newtio . c iflag = IGNPAR. Abaixo segue um exemplo de c´ digo para usar o modo ass´ncrono para a leitura da porta o ı . exit (0). Al´ m disso. 1 stopbit ) ∗ CLOCAL : Conexao local . } /∗ Seta final de string . c oflag = 0. ∗ CRTSCTS : Controle de fluxo de saida do hardware ∗ CS8 : 8 n1 (8 bit . 255). c cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD. = 5. &newtio). while (1) { res = read ( fd . // timeout entre leituras ( t=VTIME ∗ 0. ´ a configura-se o select(2) para monitorar o descritor da porta serial. TCSANOW. } 10. newtio . COMUNICACAO ¸ ˜ 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 71 ∗ BAUDRATE: Configura o bps rate.4 Modo ass´ncrono ı Este modo e utilizado quando n˜ o deseja-se ter uma chamada read(2) bloqueante. ”ATZ\r”. assim que o select(2) nos informar que existem dados dispon´veis para a leitura. if ( res < 0) { perror ( ”read” ).´ CAPITULO 10. /∗ habilita entrada em modo nao−canonico ∗/ newtio . e poder´ preparar quaisquer buffers e opcoes antes de efetuar a a a ¸˜ leitura de fato. res ). exit (1). Nesse caso. /∗ reseta o dispositivo ( modem) ∗/ if ( write ( fd . o ı tratador do sinal ser´ chamado. dessa e ´ forma. TCSANOW. /∗ Saida em modo ’raw’ ∗/ newtio .2. c lflag = 0. fprintf ( stdout . um tratador para o sinal SIGIO e criado. para poder imprimir o conteudo com printf ∗/ buf[ res ] = 0. c cc [VTIME] newtio . close ( fd ). buf . sem controle do modem ∗ CREAD : Habilita a recepcao de caracteres ∗/ newtio . } /∗ Restaura as configuracoes antigas da porta ∗/ tcsetattr ( fd . ”[%s] (%d)\n” . no parity .1 segs) // bloqueia leitura ate ’ ler 5 caracteres /∗ ’ Limpa’ a linha e ativa as configuracoes para a porta ∗/ tcflush ( fd . buf . &oldtio). avisando-nos assim que ela tiver algum dado para ser lido. tcsetattr ( fd . c cc [VMIN] = 5. TCIFLUSH). 4) < 4) perror ( ” write” ).

exit (1). h> #include < stdlib . sizeof ( newtio )). res . no parity . h> /∗ Configuracoes de baudrate sao definidas em <asm/termbits. ∗ CRTSCTS : Controle de fluxo de saida do hardware ∗ CS8 : 8 n1 (8 bit . h> #include < string . 0. /∗ configura o descritor para operacoes assincronas ∗/ fcntl ( fd .h> #include <unistd . fd = open (DEVICE.h> #include <termios . F SETFL. char ∗∗argv) { int fd . /∗ ∗ BAUDRATE: Configura o bps rate. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 72 #include <stdio .´ CAPITULO 10. O RDWR | O NOCTTY | O NONBLOCK).h> #include <signal . if ( fd < 0) { perror ( ”open”).h> #include <sys/ stat . 1 stopbit ) ∗ CLOCAL : Conexao local . fd set readfds . } int main ( int argc .h> #include < fcntl . sem controle do modem ∗ CREAD : Habilita a recepcao de caracteres ∗/ newtio . } /∗ Instala tratador de sinal para SIGIO ∗/ signal ( SIGIO. c cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD. trata sinal ). char buf [255]. h> #include <sys/ types . memset (&newtio . . struct termios oldtio . /∗ Salva a configuracao atual da porta serial e inicia uma nova ∗/ tcgetattr ( fd. & oldtio ).h> ∗/ #define BAUDRATE B9600 #define DEVICE ”/dev/ttyS0” void trata sinal ( int signum) { printf ( ”agora posso ler da porta \n”). FASYNC). newtio. COMUNICACAO ¸ ˜ serial.

// timeout entre leituras ( t=VTIME ∗ 0.sourceforge. buf .1 segs) // bloqueia leitura ate ’ ler 5 caracteres /∗ ’ Limpa’ a linha e ativa as configuracoes para a porta ∗/ tcflush ( fd . &newtio).´ CAPITULO 10.1 indepen¸˜ ¸ a dente do sistema operacional. TCIFLUSH). c oflag = 0. &readfds )) { fprintf ( stderr . } res = read ( fd . /∗ Saida em modo ’raw’ ∗/ newtio . 4) < 4) perror ( ” write” ). c iflag = IGNPAR. if ( res < 0) { perror ( ”read” ). exit (1). & readfds . fprintf ( stdout . a API da libusb associa um dispositivo aberto a uma interface em espec´fico. COMUNICACAO ¸ ˜ 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 73 newtio . NULL. select ( fd + 1.3 USB O acesso a dispositivos USB pelo Linux pode ser feito atrav´ s da LibUSB 1 . buf . = 5. ”[%s] (%d)\n” . /∗ habilita entrada em modo nao−canonico ∗/ newtio . c lflag = 0. NULL. } /∗ Restaura as configuracoes antigas da porta ∗/ tcsetattr ( fd . close ( fd ). A respeito de dispositivos e interfaces. while (1) { FD SET (fd. Isso significa que caso deseje-se abrir m´ ltiplas interfaces em um disı u positivo. TCSANOW. NULL). res ). } /∗ Seta final de string . a u 1 http://libusb. c cc [VMIN] = 5. } 10. c cc [VTIME] newtio . para poder imprimir o conteudo com printf ∗/ buf[ res ] = 0. &oldtio). exit (1). 255).net/ . exit (0). Ela e uma biblioteca ` e ´ para ser usada por aplicacoes em espaco de usu´ rio para acessar dispositivos USB 1. ”Erro em select ()!\ n” ). &readfds ). TCSANOW. newtio . /∗ reseta o dispositivo ( modem) ∗/ if ( write ( fd . ”ATZ\r”. if (! FD ISSET (fd. tcsetattr ( fd . ele dever´ ser aberto m´ ltiplas vezes para receber um manipulador para cada interface.

struct usb_config_descriptor *config. Ele nos d´ as seguintes caracter´sticas sobre o dispositivo: a a ı struct usb_device_descriptor { u_int8_t bLength. u_int8_t bDeviceClass. um sub-diret´ rio e criado neste diret´ rio. u_int16_t idProduct. e ´ ` ¸˜ A struct usb bus apresenta os seguintes campos: struct usb_bus { struct usb_bus *next. Para cada BUS. Esta informacao n˜ o ´ o ¸˜ a chega a ser util enquanto lida-se com o dispositivo pela libusb. u_int8_t bDeviceSubClass. u_int16_t idVendor. }. • int usb find busses(void): scaneia todos os BUSses USB no sistema. o que ser´ util para as aplicacoes a a ´ ¸˜ ser´ o descriptor. u_int16_t bcdDevice. Os campos next e prev s˜ o usados ´ a para iterar na lista duplamente encadeada que e retornada pela funcao usb get busses(). • struct usb bus *usb get busses(void): retorna a lista dos busses USB encontrados. o campo filename informa qual o arquivo dentro do diret´ rio informado na struct o usb bus est´ associado ao dispositivo atual. *prev.´ CAPITULO 10. COMUNICACAO ¸ ˜ 74 As seguintes funcoes s˜ o usadas para preparar o uso da biblioteca para comunicar com algum ¸˜ a dispositivo: • void usb init(void): inicializa estruturas internas da biblioteca. ´ ¸˜ J´ a struct usb device apresenta informacoes sobre os dispositivos encontrados. O campo dirname e relativo ao diret´ rio na entrada USB do procfs – normalmente local´ o izado em /proc/bus/usb. char filename[PATH_MAX + 1]. struct usb_bus *bus. struct usb_device_descriptor descriptor. /* Darwin support */ }. retornando a quantidade de modificacoes desde a ultima chamada a esta funcao (o total de BUSses adiciona¸˜ ´ ¸˜ dos e removidos). u_int8_t iProduct. void *dev. u_int8_t bDescriptorType. Essa funcao deve ser chamada logo ap´ s usb find busses(). Ela e dea ¸˜ ´ scrita como segue: struct usb_device { struct usb_device *next. Agora. *prev. u_int8_t iManufacturer. sendo que o ´ o dirname indica qual e o sub-diret´ rio associado a um determinado BUS. . char dirname[PATH_MAX + 1]. ¸˜ • int usb find devices(void): scaneia todos os dispositivos em cada BUS. u_int8_t iSerialNumber. u_int16_t bcdUSB. }. u_int8_t bMaxPacketSize0. u_int8_t bDeviceProtocol. u_int8_t bNumConfigurations. struct usb_device *devices. O valor de retorno indica a quantidade o de dispositivos removidos ou adicionados at´ a ultima chamada a funcao. Destes campos.

int interface): libera uma interface previamente requisitada pela usb claim interface(). Esta funcao deve ser chamada antes de realizar qualquer operacao sobre o dispositivo. • int usb bulk read(usb dev handle *dev. int timeout): realiza uma requisicao de escrita interrupt´vel para o endpoint ep. • int usb clear halt(usb dev handle *dev. O valor ep e o encontrado no campo bEndpointAddress do ´ descritor. Feito isso. A biblioteca permite tamb´ m realizar transferˆ ncia de dados sobre interrupt pipes: e e • int usb interrupt write(usb dev handle *dev. Retorna o n´ mero de ¸˜ ı u bytes escritos com sucesso ou um valor < 0 caso haja um erro. int ep. O parˆ metro alternate e o valor especificado no campo bAla ´ ternateSetting do descritor. podem ser usadas as seguintes funcoes: e ¸˜ • int usb bulk write(usb dev handle *dev. O timeout deve ser especificado em milisegundos. Retorna 0 ou um valor < 0 caso ocorra um erro. O parˆ metro configuration e o valor especificado no campo a ´ bConfigurationValue do descritor. • int usb set configuration(usb dev handle *dev. Para tornar a usar o dispositivo. int ep. int alternate): escolhe a configuracao ativa ¸˜ alternada da interface atual. o o ¸˜ dispositivo precisar´ ser renumerado. • int usb resetep(usb dev handle *dev.´ CAPITULO 10. e necess´ rio procur´ -lo novamente a a ´ a a e abrir um novo handle. unsigned int ep): limpa qualquer halt status do endpoint especificado por ep. int ep. int timeout): realiza uma requisicao de leitura interrupt´vel para o endpoint ep. • int usb reset(usb dev handle *dev): reseta o dispositivo especificado. Este valor pode ser recuperado a partir de config→interface→altsetting. char *bytes. enviando um RESET para a porta que ele estiver conectado. int size. Algumas outras funcoes s˜ o providas pela biblioteca. com opcoes para obter strings de ¸˜ a ¸˜ identificacao para dispositivos e realizar transferˆ ncias de controle. • int usb interrupt read(usb dev handle *dev. Vale notar que ap´ s chamar essa funcao. int size. escrevendo size ¸˜ bytes do array bytes para o dispositivo dev. unsigned int ep): reseta todos os estados para o endpoint especificado em ep. Essa funcao deve ser chamada antes de realizar qualquer ¸˜ operacao relacionada a interface requisitada (como usb set altinferface() ou usb bulk write(). COMUNICACAO ¸ ˜ 75 A partir destas informacoes. char *bytes. char *bytes. int configuration): escolhe a configuracao ¸˜ ativa de um dispositivo. Retorna o n´ mero ¸˜ u de bytes lidos ou um valor < 0 caso ocorra um erro. presente na struct usb device. • int usb claim interface(usb dev handle *dev. e poss´vel obter o identificador do dispositivo que deseja-se ¸˜ ´ ı trabalhar. S˜ o elas: ¸˜ e a . • int usb close(usb dev handle *dev): fecha um dispositivo aberto com usb open(). Para realizar transferˆ ncia de dados sobre bulk pipes. Ela ¸˜ ¸˜ retorna um handle para comunicar-se com ele. int timeout): realiza uma requisicao de escrita em volume (bulk write) para o endpoint ep. char *bytes. Essa funcao rtorna o n´ mero de bytes escritos ou um valor < 0 caso ocorra um ¸˜ u erro. int interface): reivindica a interface para o sistema operacional. • int usb set altinterface(usb dev handle *dev. int timeout): realiza uma requisicao de leitura em volume (bulk read) para o endpoint ep. sendo que o handle usado para chamar a usb reset() a n˜ o funcionar´ mais. Retorna o n´ mero de ¸˜ ı u bytes lidos com sucesso ou um valor < 0 caso haja um erro. int ep. ¸˜ ` • int usb release interface(usb dev handle *dev. int size. O parˆ metro interface e o valor especificado no campo bIntera ´ faceNumber do descritor. as seguintes funcoes s˜ o usadas: ¸˜ a • usb dev handle *usb open(struct *usb device dev): abre o dispositivo dev para uso. int size.

e bus¸˜ ı a ´ cado um em especial (como pode ser visto nas linhas 45 e 46).c -o teste_usb -Wall ‘libusb-config --cflags --libs‘ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <stdio . size t buflen): obt´ m o descritor de string especificado pelos parˆ metros index e langid de um disposie a tivo. int size): idem a funcao usb get descriptor(). e este dispositivo ser´ usado a depois para realizar a escrita de um comando e a leitura de uma resposta. char *buf.h> void show info ( usb dev handle ∗handle ) { int i . char *bytes. Retorna o n´ mero de bytes lidos para o a u descritor ou um valor < 0 em caso de erro. int value. int namelen): essa funcao ir´ obter o nome do driver associado a interface especificada pelo parˆ metro inter¸˜ a ` a face e ir´ armazen´ -lo no buffer name de tamanho namelen.´ CAPITULO 10. char buffer [1024]. char *name. A string ser´ retornada em formato Unicode. • int usb get descriptor by endpoint(usb dev handle *dev. i++) { int len = usb get string simple ( handle . de acordo com a especificacao USB. int request. void *buf. buffer [ len ] = ’\0’. O a ¸˜ valor de retorno e o n´ mero de bytes em buf ou < 0 caso haja um erro.h> #include < string . i . u • int usb get descriptor(usb dev handle *dev. int interface. int index. int timeout): realiza uma requisicao de controle para o pipe padr˜ o ¸˜ a de controle em um dispositivo. para cada um. o c´ digo a ı o precisa ser adaptado para lidar com algum outro dispositivo. ´ u • int usb get string simple(usb dev handle *dev. if ( len < 0) break. 1024). COMUNICACAO ¸ ˜ 76 • int usb control msg(usb dev handle *dev. unsigned char index. No entanto. Durante a procura por dispositivos. Para compilar este exemplo. convertendo-o para ASCII. unsigned char type. Essa funcao est´ implemena a ¸˜ a tada apenas para o Linux. int requesttype. u • int usb get string(usb dev handle *dev. . int interface): desconecta o driver de kernel da interface especificada pelo parˆ metro interface. basta rodar: $ gcc teste_usb. int index. int index. Retorna o n´ mero de bytes escritos/lidos ou um valor < 0 caso ocorra um erro. unsigned char index. Aplicacoes usando a libusb a ¸˜ podem ent˜ o realizar a usb claim interface(). int size): obt´ m o descritor para o dispositivo identificado por type e index e do descritor a partir do pipe de controle padr˜ o. O c´ digo abaixo busca todos os dispositivos e. a a O conjunto de funcoes da API permitem que se manipule de forma bastante abstrata os dis¸˜ positivos USB. • int usb get driver np(usb dev handle *dev. char *buf. /∗ mostra ate 3 linhas de informacao sobre o dispositivo ∗/ for ( i = 0. h> #include <usb. i < 3. size t buflen): esta funcao e um wrapper para a usb get string() que retorna a string de descricao especificada ¸˜ ´ ¸˜ pelo index na primeira l´ngua para o descritor. vale lembrar que como os comandos (e os identificadores do dispositivo) s˜ o espec´ficos. buffer . Ela est´ implementada apenas no Linux. unsigned char type. int size. void *buf. obt´ m as suas o e strings de informacao e as imprime na sa´da padr˜ o. • int usb detach kernel driver np(usb dev handle *dev. Essa funcao ı ¸˜ retorna o n´ mero de bytes em buf ou um valor < 0 se houver um erro. int ep. Os parˆ metros s˜ o os de mesmo nome na especificacao a a ¸˜ USB. por´ m o obt´ m ` ¸˜ e e a partir do pipe de controle identificado por ep. int langid.

idVendor == 0xeb6) && (dev−>descriptor. } /∗ Abre a interface representada pelo dispositivo ’ gp32’ ∗/ handle = usb open ( gp32). exit (1). exit (1). struct usb device ∗gp32 = NULL. gp32 = dev. } /∗ ∗ Estamos prontos para fazer leituras e escritas ao device . /∗ Inicializa a biblioteca e procura os devices ∗/ usb init (). ”%s\n”. buffer ). } } } if ( gp32 == NULL) { fprintf ( stderr . usb find devices (). result = usb claim interface ( handle . char ∗∗argv) { struct usb bus ∗ busses . usb find busses (). . COMUNICACAO ¸ ˜ 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 77 printf ( ”%s\n”. busses= usb get busses (). dev=dev−>next) { handle = usb open ( dev ). bus=bus−>next) { for ( dev=bus−>devices. struct usb device ∗dev. int result . usb dev handle ∗handle . usb strerror ()). ˜ ∗ e devem ser consultados na especificacao dos mesmos. for ( bus=busses . if (( dev−>descriptor. } printf ( ”\n”). if ( result < 0) { fprintf ( stderr . 0 x0 ). dev. bus . Neste exemplo. struct usb bus ∗bus. show info ( handle ). } int main ( int argc .´ CAPITULO 10.idProduct == 0x3232)) { printf ( ”Achei dispositivo que procurava\n”). usb close ( handle ). ”Nao encontrei o dispositivo na USB\n”). ∗ Note que os dados a serem escritos aso especificos de cada dispositivo . char buffer [1024].

usb strerror ()). exit (0). sizeof ( buffer ). 0. usb strerror ()). 100000). snprintf ( buffer . 0 x0 ). COMUNICACAO ¸ ˜ 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 78 ∗ estao sendo usados os endpoints 0x03 para escrita e 0x81 para leitura . if ( result < 0) { fprintf ( stderr . 0 x81 . ∗/ memset (buffer . sizeof ( buffer ). if ( result < 0) { fprintf ( stderr . usb close ( handle ). ”%s\n”. result = usb bulk write ( handle . 0. } /∗ libera a interface e encerra o programa ∗/ usb release interface ( handle . } . buffer . buffer . 0 x03 . } /∗ le a resposta ∗/ memset (buffer .´ CAPITULO 10. sizeof ( buffer )). ”comandos especificos ” ). exit (1). result = usb bulk read ( handle . sizeof ( buffer )). exit (1). sizeof ( buffer ). ”%s\n”. 100000).

1 Sinais Timers s˜ o recursos que permitem sinalizar o processo em intervalos de tempo fixos. Alguns dos sinais mais comuns de serem tratados s˜ o: a • SIGKILL: processo recebeu um sinal de kill. ou atrav´ s da recepcao do sinal especificado. ¸˜ • SIGTERM: processo recebeu sinal de t´ rmino. O signal handler e configuu ´ rado para sighandler. signum). Como eles a s˜ o baseados em sinais. O programa declara ´ um handler para quando receber o sinal SIGINT. h> void suicide ( int signum) { printf ( ”Recebi o sinal %d. e Seu uso e bastante simples. a ¸˜ a O seu prot´ tipo e o seguinte: o ´ #include <signal . que pode ser qualquer funcao escrita pelo usu´ rio. h> #include <signal . como pode ser visto no exemplo abaixo. encerrando . para que a acao padr˜ o seja tomada (descrita na man page do signal(7). sighandler t signal ( int signum. e ¸˜ 1 2 3 4 5 6 7 8 9 10 11 #include <stdio . h> typedef void (∗ sighandler t )( int ). e aguarda at´ que seja pressionada alguma tecla e para encerrar normalmente.\ n” . } 79 . esta sess˜ o os apresenta. Esta chamada de sistema ´ instala um novo signal handler para o sinal com o n´ mero signum. sighandler t handler ).h> #include < stdlib . permitindo fazer um programa que lide com a a sinais diversos. exit (1).Cap´tulo 11 ı Timers 11. • SIGINT: interrupcao do teclado (CTRL+C). ou SIG IGN para ig¸˜ a nor´ -lo ou SIG DFL. A chamada de sistema usada para capturar sinais e a signal(2)..

int setitimer ( int which . que pode ser uma das ITIMER REAL. A funcao getitimer(2) preenche a estrutura indicada por value com as configuracoes ¸˜ ¸˜ do timer indicado por wich. e resetam para it interval. char ∗∗argv) { signal ( SIGINT. Quando um timer expira. Os valores que s˜ o usados s˜ o definidos pelas estruturas: a a struct itimerval { struct timeval it interval . it interval e configurado para o valor de ´ reset. e entrega o sinal SIGVTALARM quando expira. const struct itimerval ∗ value . getchar (). Similarmente. long tv usec . ´ O prot´ tipo para uso de timers e o seguinte: o ´ #include <sys/time . exit (0). TIMERS 12 13 14 15 16 17 18 19 80 int main ( int argc . struct itimerval ∗ value ).´ CAPITULO 11. O elemento it value e configurado para a quantidade de tempo restante no timer. ITIMER VIRTUAL ou ITIMER PROF. gerando um sinal. A funcao setitimer(2) configura o timer indicado para o valor em timer. a • ITIMER VIRTUAL: decrementa apenas enquanto o processo est´ executando. /∗ valor atual ∗/ }. suicide ). e entrega o sinal SIGALRM quando expira. Este m´ todo costuma ser usado para fazer profile do e tempo que um processo passou executando tanto em espaco de usu´ rio quanto de kernel. o valor antigo do timer e armazenado ali. um sinal e enviado para o processo. printf ( ”Encerrando normalmente\n”). Os timers dispon´veis s˜ o: ı a • ITIMER REAL: decrementa em tempo real. cada um decrementando em um dom´nio de tempo e e ı diferente. • ITIMER PROF: decrementa quando o processo executa e quando o sistema est´ execua tando no contexto do processo. } 11. Se ovalue e ¸˜ ´ n˜ o-zero. ¸ a O sinal SIGPROF e entreque quando este timer expira. e o timer potencialmente ´ reinicia.2 Utilizando timers O sistema provˆ a cada processo trˆ s timers. /∗ proximo valor ∗/ struct timeval it value . ´ . a ´ e Timers decrementam de it value at´ zero. Um timer que e configurado para um it value zero expira.h> int getitimer ( int which . /∗ micro segundos ∗/ }. struct itimerval ∗ ovalue ). ´ ou zero caso o timer seja desabilitado. struct timeval { /∗ segundos ∗/ long tv sec .

tempo. tv usec = 0. h> #include <sys/time . que executa um timer de 2 em 2 segundos. preparamos um signal handler para SIGALRM ∗/ signal ( SIGALRM. tv sec = 2. } int main ( int argc .´ CAPITULO 11. it interval .h> #include <unistd . /∗ como vamos usar ITIMER REAL. } exit (0). tv sec = 2. tempo. tv usec = 0. while (1) { usleep (100). it value . TIMERS 81 Como exemplo de uso. NULL). char ∗∗argv) { struct itimerval tempo. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <stdio . it interval .h> void timer func ( int signum) { printf ( ” recebi o sinal %d\n”. timer func). } . /∗ especifica o intervalo e seta o timer ∗/ tempo. podemos tomar o programa abaixo. signum). &tempo. h> #include <signal . setitimer ( ITIMER REAL. tempo. it value .

[STE 98] [STE 98a] [The 2003] STEVENS.gnu. R.).2. [KOJ 2000] KOJIMA. part 1. Approved September 15. Boston.. Silver Spring. MySQL http://www. Using the GNU Compiler Collection (GCC). GDB Internals. American National Standards Institute.4. J. MA 02111-1307 USA. The X Window System. 2003. P. P. A. 2001.l..).Suite 330.]: Prentice Hall. USA: IEEE Computer Society Press. Desenvolvimento de Aplicacoes Gr´ ficas para o X Window System. [S. 1109 Spring Street. http://people. J. W. v. IEEE Standards Board. W. [MyS 2003] MySQL AB.]: Prentice Hall. LINUX device drivers.2. dos. M.redhat. The Native POSIX Thread Library for Linux.]: Free Software Foundation. C. includes IEEE Std 1003. [ZEL 2000] ZELLER.l. MA 02111-1307 USA. Approved April 14. J. de. Debugging with DDD.com/documentation/. R. 1994.l. [S. Reference Manual. 59 Temple Place .79–109.Networking APIs: Sockets and XTI.mysql.1-1990). Suite 300. 1993. [GIL 2003] GILMORE. K. Boston. 1986.Interprocess Communication. 1998.1b-1993 (formerly known as IEEE P1003. system application program interface (API) — amendment 1 — realtime extension [C language]. R. [STA 2002] STALLMAN. R. C. A. [RUB 2001] RUBINI. SANTOS. [S. 2003. UNIX Network Programming . (Ed.org/manual/ddd/. ACM Transactions on Graphics. 2002.n. Anais.]. CORBET.l. (Eds. n. UNIX Network Programming . [S. v. A. . 59 Temple Place .Suite 330. ANDRADE. 2003.: s. [S.l. GETTYS.Bibliografia [Ame 94] American National Standards Institute. A.5. IEEE standard for information technology: Portable Operating Sytem Interface (POSIX).l. 1998.). M. 1994.pdf. STEVENS. [S. [SCH 86] SCHEIFLER. Mini-curso apresen¸˜ a tado no Software Livre 2000. xxiii + 590p. 82 .]: Free Software Foundation.com/drepper/nptl-design. http://www. (Ed. p. MD 20910. .]: O’REILLY.. IEEE Std 1003.

Sign up to vote on this title
UsefulNot useful