Portada » Informática » Programación de Sistemas UNIX/Linux: Llamadas al Sistema, Procesos y Sockets
Las llamadas al API del sistema actúan como intermediario entre el espacio de usuario y el kernel (que gestiona ficheros, procesos, red y controladores de hardware). La programación que utiliza esta API sigue varios estándares:
Aunque el programador no percibe una diferencia inmediata, una llamada a librería (sección 3) no interacciona directamente con el kernel. En cambio, las llamadas al sistema (sección 2) sí lo hacen mediante una interrupción (trap). Las llamadas a librería requieren la reserva de espacio para los parámetros.
El comando man [seccion] [-k] función muestra las páginas del manual para una función dada. Las secciones 2 y 3 corresponden a las llamadas al kernel y a las librerías, respectivamente. El argumento -k se utiliza para buscar. Dentro del manual, use / para buscar palabras y q para salir.
-1 y establecen la variable errno en caso de error.NULL y no siempre establecen errno.perror(3): Informa del error de la última llamada al sistema que devolvió -1 por convenio al fallar.strace(1): Intercepta las llamadas al SO realizadas por un comando.uname(2): Proporciona información sobre el kernel.sysconf(3): Proporciona información y limitaciones del SO.pathconf(3) / fpathconf(3): Proporciona información y limitaciones de un path.getuid(2) / getgid(2) / geteuid(2) / getegid(2): Obtienen el usuario/grupo real y efectivo del proceso.setuid(2): Modifica el usuario efectivo.getpwnam(3) / getpwuid(3): Proporcionan información del usuario según su nombre o ID.id(1): Muestra información sobre los UID actuales.time(2) / gettimeofday(2) / settimeofday(2): Proporcionan información sobre la hora y fecha del sistema.ctime(3) / gmtime(3) / localtime(3): Proporcionan información formateada sobre la hora y fecha del sistema.strftime(3): Convierte la información de la hora al formato deseado.Desde el punto de vista del usuario, los sistemas de ficheros son colecciones de ficheros y directorios utilizados para guardar y organizar información. Desde la perspectiva del SO, son un conjunto de tablas y estructuras que gestionan dicha información.
Nota: Las llamadas al SO son independientes del sistema de ficheros subyacente.
El sistema ext2 (inspirado en FFS de BSD) se compone de grupos de bloques de datos, que se ubican cerca de sus i-nodos. Los i-nodos, a su vez, están cerca del directorio de i-nodos. Los primeros bloques de una partición EXT2 son:
Cuando un sistema ext2 no se apaga correctamente, el SO debe comprobar la integridad (mediante fsck), una tarea costosa que recorre todos los i-nodos y que a veces resulta irreparable.
Los sistemas modernos utilizan un archivo de bitácora (journal) que evita la corrupción de datos. Los cambios se escriben primero en la bitácora, y en caso de apagado brusco, se puede consultar para recuperar el estado coherente. Los sistemas ext3 y ext4 ya incluyen esta técnica.
Dependiendo del uso, existen tres variantes:
open(2): Abre archivos.umask(2): Establece la máscara de permisos para la apertura de archivos (permisos = mode & (~ umask)).stat(2): Proporciona información sobre archivos (desde el i-nodo). Contiene una serie de macros para el campo st_mode (ej.: S_ISLNK, S_ISREG, S_ISDIR) y para permisos (ej.: S_IRWXU).chmod(2): Modifica los permisos sobre un archivo.access(2): Comprueba los permisos sobre un archivo. Falla si no se tiene alguno de los permisos a comprobar.dup(2): Duplica un descriptor de fichero.write(2) / read(2) / lseek(2): Sirven para escribir, leer y recorrer un fichero.close(2): Cierra y libera un fichero abierto.fsync(2): Sincroniza explícitamente los cambios en un fichero abierto.link(2): Crea un hard link (mismo i-nodo) de un archivo. Solo es válido dentro del mismo sistema de ficheros.symlink(2): Crea un enlace simbólico a un archivo.readlink(2): Lee el contenido de un enlace simbólico.unlink(2): Elimina el archivo del directorio, decrementando el contador de referencias y potencialmente borrándolo.fcntl(2): Realiza operaciones de control sobre un fichero abierto. Se utiliza para crear cerrojos (ver F_GETLK).flock(2): Aplica o elimina un cerrojo (de lectura o escritura) sobre un archivo.opendir(2) / readdir(2) / closedir(2): Para abrir, recorrer y cerrar un directorio.mkdir(2) / rmdir(2): Para crear o eliminar directorios.rename(2): Renombra o mueve un archivo.ls(1): Para consulta general de archivos y directorios (opciones interesantes: -a, -l, -d, -h, -i, -R, -1, -F y --color).ln(1): Para la creación de enlaces simbólicos.Para obtener los números major y minor (a partir de stat), se utilizan las macros MAJOR y MINOR (requiere #include <sys/sysmacros.h>) sobre el campo st_rdev.
Un programa es un conjunto de instrucciones en código máquina y datos, guardados en un ejecutable en disco. Un proceso es una instancia de un programa en ejecución.
El planificador es un algoritmo del kernel que determina el orden de ejecución de los procesos, en función de prioridades estáticas y dinámicas. El SO es expropiativo con los procesos de usuario.
Nota: El planificador realmente maneja hilos (threads). En programas multihilo, las llamadas tienen su equivalente pthread.
fork(2): Duplica un proceso en una relación padre-hijo.exec(3): Ejecuta un programa en el proceso actual, siendo sustituido. El primer argumento es el programa y el último debe ser NULL._exit(2) / exit(3): Terminan un proceso.wait(2): Espera la terminación de algún hijo y libera sus recursos asociados.chrt(1): Permite cambiar un proceso a modo real-time.sched_getscheduler(2) / sched_setscheduler(2): Manipulan o leen el planificador de un proceso (0 para el actual).sched_setparam(2) / sched_getparam(2): Manipulan o leen la prioridad de un proceso (0 para el actual).sched_get_priority_max(2) / sched_get_priority_min(2): Obtienen los límites de la prioridad estática.getpriority(2) / setpriority(2) / nice(1) / renice(1): Consultan y fijan la prioridad de un proceso.getpid(2) / getppid(2) / setpgid(2) / getpgid(2): Consultan el pid o consultan/establecen un gid.setsid(1,2) / getsid(2): Obtienen o establecen una nueva ID de sesión.getcwd(3) / chdir(2): Obtienen el directorio de trabajo, y el segundo lo cambia.getenv(3) / setenv(3): Obtienen/modifican variables de entorno.getrlimit(2) / setrlimit(2): Obtienen o modifican los límites de los recursos del sistema.getrusage(2) / times(2): Obtienen el uso de tiempo del sistema por parte del padre e hijos.system(3): Ejecuta un comando en la shell del sistema, bloqueando el proceso hasta que retorne.ps(1): Proporciona información sobre los procesos (consultar man para STANDARD FORMAT SPECIFIERS).Las señales son interrupciones software asíncronas generadas por procesos. Los procesos que las reciben pueden bloquearlas, ignorarlas, o invocar una rutina de tratamiento por defecto o propia.
La lista completa de señales se encuentra en la sección Standard Signals de man 7 signal. Se recomienda usar variables volatile en las variables modificadas dentro de las rutinas de tratamiento de señales.
kill(1,2) / raise(3) / abort(3): Envían una señal a un proceso, a sí mismo o abortan el proceso (abort).sigemptyset(3) / sigfillset(3) / sigaddset(3) / sigdelset(3) / sigismember(3): Tratan grupos de señales.sigprocmask(2): Bloquea/desbloquea señales en el proceso.sigpending(2): Comprueba las señales pendientes.sigaction(2): Modifica y consulta el manejador para una señal.sigsuspend(2): Espera una señal (y ejecuta el manejador de la misma).sleep(1,3): Espera un tiempo concreto.alarm(2): Lanzará SIGALRM después de una cantidad concreta de segundos.getitimer(2) / setitimer(2): Interactúan con otros temporizadores (SIGVTALRM, SIGPROF).Permiten la comunicación unidireccional entre dos procesos que tienen una relación de parentesco. Funcionan como ficheros (tienen descriptores, operaciones de E/S típicas, heredadas de padres a hijos). La sincronización la realiza el kernel, el acceso es de tipo FIFO y residen en memoria principal.
pipe(2): Crea una tubería sin nombre.Se utilizan entre cualquier proceso, ya que las tuberías sin nombre solo funcionan entre procesos con relación de parentesco. Son un tipo de archivo especial. Funcionan como las tuberías sin nombre, pero se abren con open y solo usan los bloques directos del i-nodo.
mknod(1,2) / mkfifo(1,3): Crean tuberías con nombre.Nota sobre FIFOs: Usar O_NONBLOCK para no bloquearse en el open. Leer de una tubería vacía sin escritor devuelve 0 en read. Escribir en una tubería sin lector devuelve SIGPIPE.
select(2): Multiplexa canales de E/S de forma síncrona, esperando hasta un evento o timeout.La comunicación entre cliente y servidores se denomina socket (enchufe). Permite un intercambio bidireccional. Cada aplicación (proceso) está identificada por un número de puerto. La API se basa en BSD Sockets API.
SIG_PIPE cuando el otro extremo pierde la conexión. Utiliza: connect(2), recv(2), send(2), read(2), write(2).send(2), recv(2), sendto(2), recvfrom(2).Los dominios son familias de protocolos que comparten una forma de direccionamiento (ejemplos: AF_UNIX, AF_INET, AF_INET6). El protocolo suele estar determinado por el tipo de socket.
El concepto Dual Stack permite que el mismo socket gestione los dos tipos de IP (IPv4 e IPv6). Se configura como in6addr_any y se desactiva la opción de socket IPV6_V6ONLY.
inet_ntop(3) / inet_pton(3): Traducen direcciones entre formato texto y formato struct.bind(2): Asocia un socket a una dirección IP y puerto específicos.listen(2): Abre la escucha de un socket a una cantidad determinada de clientes.accept(2): Espera para aceptar una petición de conexión de cliente.connect(2): Crea un nuevo descriptor de fichero para la gestión de la nueva conexión aceptada (en el lado del cliente).send(2) / sendto(2): Sirven para enviar datos por un socket.recv(2) / recvfrom(2): Sirven para recibir datos por un socket.getaddrinfo(3) / getnameinfo(3): Traducen direcciones y hostname desde/hacia la estructura sockaddr correspondiente.