Ir a contenido principal

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. Cierta información de su perfil de developerWorks será mostrada públicamente, pero usted puede editar la información en cualquier momento. Su nombre, apellido (a menos que usted elija ocultarlo) y nombre de usuario acompañarán el contenido que usted publique.

Toda la información enviada es segura.

  • Cerrar [x]

La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

Toda la información enviada es segura.

  • Cerrar [x]

APIs del kernel, Parte 1: Cómo invocar aplicaciones espacio de usuario desde el kernel

Implementación y uso de la API ayudante en modo de usuario

M. Tim Jones, Consultant Engineer, Emulex Corp.
M. Tim Jones
M. Tim Jones es arquitecto de firmware incrustado y es autor de Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming (actualmente en su segunda edición), AI Application Programming (en su segunda edición) y BSD Sockets Programming from a Multilanguage Perspective. Sus antecedentes en la ingeniería abarcan desde el desarrollo de kernels para naves espaciales geosincrónicas hasta la arquitectura de sistemas incrustados y el desarrollo de protocolos de redes. Tim es Consultant Engineer de Emulex Corp. en Longmont, Colorado.

Resumen:  La interfaz® de llamada del sistema Linux permite que las aplicaciones de espacio de usuario invoquen funcionalidad en el kernel, pero ¿qué hay de invocar aplicaciones de espacio de usuario desde el kernel? Explore la API ayudante de usuario, y aprenda a invocar aplicaciones de espacio de usuario y manipular su salida.

Ver más contenido de esta serie

Fecha:  05-05-2010
Nivel:  Intermediaria
Actividad:  4304 vistas
Comentario:  


Conéctese con Tim

Tim es uno de nuestros autores más populares y prolíficos. Explore todos los artículos de Tim en developerWorks. Vea el perfil de Tim y conéctese con él, otros autores y lectores en My developerWorks.

Invocar funciones específicas del kernel (llamadas del sistema) es parte natural del desarrollo aplicaciones en GNU/Linux. ¿Pero qué hay de ir en la dirección contraria, donde el espacio de kernel llama al espacio de usuario? Resulta que hay una cantidad de aplicaciones para esta función que probablemente usted usa todos los días. Por ejemplo, cuando el kernel encuentra un dispositivo para el cual se debe cargar un módulo, ¿cómo ocurre este proceso? La carga del módulo dinámico ocurre desde el kernel a través del proceso de ayuda de usuario.

Comencemos explorando ayuda de usuario, su interfaz de programación de aplicaciones (API), y algunos ejemplos de dónde se usa esta función en el kernel. Luego, usando la API, usted creará una aplicación de muestra para comprender mejor cómo funciona y sus limitaciones.

La API ayudante de usuario

La API ayudante de usuario es una API simple con un conjunto de opciones conocido. Por ejemplo, para crear un proceso desde el espacio de usuario, generalmente usted brinda el nombre del ejecutable, y un conjunto de variables del entorno (consulte la página man para ver el execve). Lo mismo se aplica para crear un proceso desde el kernel. Pero como está iniciando el proceso desde el espacio del kernel, hay unas pocas opciones disponibles.

Versión de kernel

Este artículo explora la API ayudante de usuario desde el kernel 2.6.27.

La tabla 1 muestra el conjunto central de funciones del kernel disponibles en la API ayudante de usuario.


Tabla 1. Funciones centrales de la API ayudante de usuario
Función de la APIDescripción
call_usermodehelper_setup Preparar un controlador para una llamada user-land
call_usermodehelper_setkeys Configurar las claves de sesión para un ayudante
call_usermodehelper_setcleanup Configurar una función de limpieza para el ayudante
call_usermodehelper_stdinpipe Crear unstdincanal para un ayudante
call_usermodehelper_exec Invocar la llamada user-land

En esta tabla se incluyen también unas funciones de simplificación que encapsulan las funciones del kernel en la Tabla 2 (que requieren una única llamada en lugar de múltiples llamadas). Estas funciones de simplificación sirven para la mayoría de los casos, así que le aconsejamos usarlas, de ser posible.


Tabla 2. Simplificaciones de la API ayudante de usuario
Función APIDescripción
call_usermodehelper Hacer una llamada user-land
call_usermodehelper_pipe Hace una llamada user-land con un canalstdin
call_usermodehelper_keys Hacer una llamada user-land con claves de sesión

Primero veamos las funciones centrales, luego exploremos las capacidades que ofrecen las funciones de simplificación. La API central opera usando una referencia de controlador denominada estructura subprocess_info. Esta estructura (que se puede encontrar en ./kernel/kmod.c) agrupa todos los elementos necesarios para una instancia de ayuda de usuario determinada. La referencia de la estructura es devuelta de una llamada a call_usermodehelper_setup. La estructura (y las llamadas subsiguientes) se configure adicionalmente a través de llamadas a call_usermodehelper_setkeys(for credentials storage),call_usermodehelper_setcleanup, and call_usermodehelper_stdinpipe. Finalmente, cuando cla configuración esté completa, puede invocar la aplicación de modo de usuario a través de una llamada a call_usermodehelper_exec.

Exención de responsabilidad

Este método brinda una función necesaria para invocar aplicaciones de espacio de usuario desde el kernel. Aunque hay usos legítimos para esta funcionalidad, se le encarece considerar si se necesitan otras implementaciones. Este es un enfoque, pero hay otros enfoques más adecuados.

Las funciones centrales le dan la mayor cantidad de control, donde las funciones de ayuda hacen la mayor parte del trabajo por usted en una llamada individual. Las llamadas relacionadas con el canal (call_usermodehelper_stdinpipe y la función de ayuda call_usermodehelper_pipe) crean un canal relacionado para que lo utilice el ayudante. Específicamente, se crea un canal (una estructura de archivo en el kernel). El canal puede ser leído por la aplicación de espacio de usuario y puede ser escrito por el lado del kernel. En cuanto a la escritura, core dumps son la única aplicación que puede usar un canal con un ayudante de usuario. En esta aplicación (./fs/exec.c do_coredump()), core dump es escrito a través del canal desde el espacio del kernel al espacio del usuario.

La relación entre estas funciones ysub_processinfojunto a los detalles de la subprocess_info estructura se muestran en la Figura 1.


Figura 1. Relaciones de la API ayudante de usuario
Usermode-helper API relationships

La funciones de simplificación que se ven en la Tabla2 realizan la función call_usermodehelper_setup y la función call_usermodehelper_exec internamente. Las últimas dos llamadas que figuran en la Tabla 2 invocancall_usermodehelper_setkeys y call_usermodehelper_stdinpipe, respectivamente. Puede encontrar la fuente para call_usermodehelper_pipe en ./kernel/kmod.c y para call_usermodehelper y call_usermodhelper_keys en ./include/linux/kmod.h.


¿Para qué invocar una aplicación de espacio de usuario desde el kernel?

Ahora analicemos algunos de los lugares en el kernel donde se utiliza la API ayudante de usuario. La tabla 3 nos ofrece una lista exclusiva de aplicaciones sino que representa una intersección de usos interesantes.


Tabla 3. Aplicaciones de la API ayudante de usuario en el kernel
AplicaciónUbicación de origen
Carga de módulo kernel./kernel/kmod.c
Gestión de energía./kernel/sys.c
Grupos de control./kernel/cgroup.c
Generación de clave de seguridad./security/keys/request_key.c
Entrega de evento kernel./lib/kobject_uevent.c

Una de las aplicaciones más simples de la API ayudante de usuario es cargar módulos kernel desde el espacio de kernel. La función request_module encapsula la funcionalidad de la API ayudante de usuario y provee una interfaz simple. En un modo de uso común, el kernel identifica un dispositivo o servicio y hace una llamada a request_module para que se cargue el módulo. A través de la API ayudante de usuario, el módulo se carga en el kernel vía modprobe(la aplicación invocada en el espacio de usuario vía request_module).

Una aplicación similar a la carga de módulo es hot-plugging de dispositivos (para agregar o quitar dispositivos en tiempo de ejecución). Esta función se implementa con la API ayudante de usuario, invocando la utilidad /sbin/hotplug en espacio de usuario.

Una aplicación interesante de la API ayudante de usuario (via request_module) es la API textsearch (./lib/textsearch.c). Esta aplicación brinda una infraestructura de búsqueda de texto configurable en el kernel. Esta aplicación usa la API ayudante de usuario a través de la carga dinámica de algoritmos como módulos cargables. En la versión 2.6.30 del kernel, se da soporte a tres algoritmos, que incluyen Boyer-Moore (./lib/ts_bm.c), un enfoque de máquina de estados finitos (./lib/ts_fsm.c), y finalmente el algoritmo Knuth-Morris-Pratt (./lib/ts_kmp.c).

La API ayudante de usuario también soporta Linux en un apagado ordenado del sistema. Cuando es necesario apagar el sistema, el kernel invoca el comando/sbin/poweroff en el espacio de usuario para lograrlo. Otras aplicaciones se indican en la Tabla 3, con la ubicación de origen acompañante.


Internas de la API ayudante de usuario

Encontrará el origen y la API para la API ayudante de usuario en kernel/kmod.c (que ejemplifica su uso principal como el cargador de módulo de kernel del espacio de kernel). La implementación utiliza kernel_execve para el trabajo sucio. Observe que kernel_execve es lafunción utilizada para iniciar init el proceso en el tiempo de arranque y no utiliza la API ayudante de usuario.

La implementación de la API ayudante de usuario es bastante simple y sencilla (ver Figura 2). El trabajo del ayudante de usuario comienza con la llamada a call_usermodehelper_exec (que se utiliza para iniciar la aplicación de espacio de usuario desde una estructura subprocess_info preconfigurada). Esta función acepta dos argumentos: la subprocess_info referencia de estructura y un tipo de enumeración (ya sea no esperar, esperar que se inicie el proceso, o esperar que todo el proceso se complete). El subprocess_info(o major dicho el work_struct elemento de esta estructura se coloca en cola en una estructura de trabajo (khelper_wq), que asincrónicamente realize la invocación.


Figura 2. Implementación interna de la API ayudante de usuario

Cuando se coloca un elemento en el khelper_wq, se invoca la función de control para la cola de trabajo (en este caso,__call_usermodehelper), que se ejecuta a través del subproceso khelper. Esta función comienza a sacar de cola la estructura subprocess_info, que contiene toda la información necesaria para la invocación del espacio de usuario. La ruta luego depende de la enumeración de la variable wait. Si el solicitante espera que termine todo el proceso, inclusive la invocación del espacio de usuario (UMH_WAIT_PROC) o no esperar nada (UMH_NO_WAIT), entonces se crea un subproceso de kernel desde la función wait_for_helper. De lo contrario, el solicitante puede simplemente querer esperar que se invoque la aplicación de espacio de usuario (UMH_WAIT_EXEC) pero no que se complete. En este caso, se crea un subproceso de kernel para ____call_usermodehelper().

En el subproceso wait_for_helper, se instala un controlador de señal SIGCHLD, , y se crea otro subproceso de kernel para ____call_usermodehelper. Pero en el subproceso wait_for_helper, se hace una llamada a sys_wait4 para esperar la finalización del subproceso de kernel ____call_usermodehelper(indicado por una señal SIGCHLD). Entonces el subproceso realiza toda limpieza necesaria (ya sea liberando las estructuras para UMH_NO_WAIT O simplemente enviar una notificación de finalización a call_usermodehelper_exec().

La función ____call_usermodehelper es donde ocurre el verdadero trabajo para iniciar la aplicación en el espacio de usuario. Esta función comienza desbloqueando todas las señales y configurando el círculo de clave de sesión. También instala el canal stdin(si se solicita). Luego de un poco más de inicialización, se invoca la aplicación de espacio de usuario a través de una llamada a kernel_execve(fromkernel/syscall.c), que incluye la listapath,argv previamente seleccionada (inclusive el nombre de la aplicación de espacio de usuario), y el entorno. Cuando se completa este proceso, el subproceso sale a través de una llamada a do_exit().

Este proceso también utiliza finalizaciones Linux, que es una operación tipo semáforo. Cuando se invoca la función call_usermodehelper_exec, se declara una finalización. Después de que la estructurasubprocess_infose coloca en el khelper_wq, se hace una llamada a wait_for_completion(utilizando la variable finalización como su único argumento). Observe que esta variable también se almacena en la estructura subprocess_info como el campo complete. Cuando el subproceso secundario desea despertar la función call_usermodehelper_exec, llama al método kernel complete, observando la variable de finalización de la estructura subprocess_info. Esta llamada desbloquea la función para poder continuar. Puede encontrar la implementación de esta API en include/linux/completion.h.

Encontrará más información sobre la API ayudante de usuario siguiendo los enlaces de la secciónRecursos.


Aplicación de muestra

Ahora veamos un uso simple de la API ayudante de usuario. Primero verá la API común, luego aprenderá a simplificar las cosas más usando las funciones del ayudante.

Para esta demostración, desarrollará un módulo de kernel cargable simple que invoca la API. La Lista 1 presenta las funciones del módulo boilerplate, definiendo las funciones de entrada y salida del módulo. Estas dos funciones se invocan en modprobe o insmod del módulo (función de entrada del módulo) y rmmod del módulo (salida del módulo).


Listado 1. Funciones del módulo boilerplate
 #include <linux/module.h> #include
                <linux/init.h> #include <linux/kmod.h> MODULE_LICENSE(
                "GPL" ); static int __init mod_entry_func( void ) { return umh_test(); }
                static void
                __exit mod_exit_func( void ) { return; } module_init( mod_entry_func ); 
                module_exit(
                mod_exit_func );

El uso de la API ayudante de usuario se muestra en el Listado 2, que explorará detalladamente. La función comienza con la declaración de una variedad de variables y estructuras necesarias. Comience con la estructura subprocess_info, que contiene toda la información necesaria para realizar la invocación de espacio del usuario. Esta invocación se inicializa cuando llama call_usermodehelper_setup. Luego defina su lista de argumentos, llamada argv. Esta lista es similar a la lista argv utilizada en programas C comunes y define la aplicación (primer elemento del conjunto) y la lista de argumentos. Se necesita un terminador NULL para indicar el final de la lista. Observe que la variable argc (conteo de argumentos) está implícita, debido a que se desconoce la extensión de la lista argv. En este ejemplo, el nombre de la aplicación es /usr/bin/logger, y su argumento es help!, seguido por su NULL terminador. La siguiente variable requerida es el conjunto de entorno (envp). Este conjunto es una lista de parámetros que definen el entorno de ejecución para la aplicación de espacio de usuario. En este ejemplo, usted define unos cuantos parámetros típicos que se definen para el shell y termina con una entrada de NULL terminador.


Listado 2. Prueba simple de API ayudante en modo de usuario
 static int umh_test( void ) { struct
                subprocess_info *sub_info; char *argv[] = 
                { "/usr/bin/logger", "help!", NULL };
                static char *envp[] = { "HOME=/", "TERM=linux",
                "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL }; sub_info
                    = call_usermodehelper_setup( argv[0], argv, envp, GFP_ATOMIC ); if
                (sub_info == NULL) return -ENOMEM; return 
                call_usermodehelper_exec( sub_info,
                UMH_WAIT_PROC ); }

Luego, haga una llamada a call_usermodehelper_setup para crear su estructura subprocess_info inicializada. Observe que usted utiliza sus variables inicializadas previamente junto a un cuarto parámetro que indica la máscara GFP para la inicialización de la memoria. Interno de la función de configuración, hay una llamada kzalloc(que asigna memoria kernel y la pone en cero). Esta función requiere GFP_ATOMIC o el indicador GFP_KERNEL(donde el primero define que la llamada no debe entrar en espera y el Segundo que la espera es posible). Luego de una prueba rápida de su nueva estructura (concretamente, no es NULL), siga haciendo la llamada usando la función call_usermodehelper_exec. Esta función toma su estructura subprocess_info y una enumeración y define si espera (se describe en la sección internos). ¡Y eso es todo! Cuando el módulo se carga, debe ver el mensaje en su archivo /var/log/messages.

Puede simplificar este proceso aún más usando la función API call_usermodehelper, que realiza las funciones call_usermodehelper_setup y call_usermodehelper_exec juntas. Como se muestra en el Listado 3, esto no solo elimina una función sino que también elimina la necesidad de que el llamador gestione la estructura subprocess_info.


Listado 3. Prueba aún más simple de API ayudante en modo de usuario
 static int umh_test( void ) {
                char *argv[] = { "/usr/bin/logger", "help!", NULL };
                static char *envp[] = {
                "HOME=/", "TERM=linux", "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };
                    return call_usermodehelper ( argv[0], argv, envp, UMH_WAIT_PROC ); }

Observe que en el Listado 3 existen los mismos requisitos para configurar y hacer la llamada (como por ejemplo inicializar los conjuntos argv y envp). La única diferencia es que la función ayudante realiza las funcionessetup y exec.


Seguir adelante

La API ayudante de usuario es un aspecto importante del kernel, dado su variado y amplio uso (desde carga de módulo kernel, hot-plugging de dispositivo, y distribución de evento para udev). Aunque es importante validar aplicaciones genuinas de la API, es un aspecto importante del kernel es un aspecto importante del kernel para comprender y por ende es un agregado útil para su kit de herramientas de kernel de Linux.


Recursos

Aprender

  • Hay poca información sobre la API ayudante de usuario, pero la implementación es bastante clara y simple de seguir. Puede revisar la implementación a través de LXR (el navegador fuente Linux Cross Referencer— para todas las revisiones de fuente). Los dos archivos principales de interés son kmod.c y kmod.h.

  • El sistema de archivo /proc brinda un método de comunicación entre el kernel y el espacio de usuario,— aunque es un sistema de archivos virtual. Puede obtener más información sobre el sistema de archivos /proc en "Accessthe Linux kernel using the /proc filesystem" (developerworks, marzo de 2006).

  • La interfaz de llamada del sistema Linux provee los medios para que las aplicaciones espacio de usuario invoquen funcionalidad de kernel. Para obtener más detalles sobre llamadas del sistema Linux, inclusive cómo agregar nuevas llamadas del sistema, vea "Kernelcommand using system calls" (developerworks, marzo de 2007).

  • Para ejemplificar la API ayudante de usuario, este artículo utiliza módulos de kernel creables para instalar aplicaciones de prueba en el kernel. Para obtener más información sobre los módulos de kernel cargables y su implementación, vea "Anatomy of Linux loadable kernel modules" (developerworks, julio de 2008).

  • Para obtener más información sobre la interfaz de cola de trabajo del kernel 2.6, vea este antiguo artículo de Linux Journal de2003, que ofrece una buena introducción a la API y al funcionamiento de las colas de trabajo del kernel.

  • En la zona Linux de developerWorks, encuentre más recursos para desarrolladores de Linux.

  • Siga actualizado con Eventos técnicos y transmisiones por Internet de developerWorks.

  • Siga developerWorks en Twitter.

Obtener los productos y tecnologías

  • Con Software de prueba de IBM, disponible para descargarlo directamente de developerWorks, arme su próximo proyecto de desarrollo sobre Linux.

Comentar

  • Involúcrese en la comunidad My developerWorks. Conéctese con otros usuarios de developerWork mientras explora los blogs, foros, grupos y wikis creados por desarrolladores.

Sobre el autor

M. Tim Jones

M. Tim Jones es arquitecto de firmware incrustado y es autor de Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming (actualmente en su segunda edición), AI Application Programming (en su segunda edición) y BSD Sockets Programming from a Multilanguage Perspective. Sus antecedentes en la ingeniería abarcan desde el desarrollo de kernels para naves espaciales geosincrónicas hasta la arquitectura de sistemas incrustados y el desarrollo de protocolos de redes. Tim es Consultant Engineer de Emulex Corp. en Longmont, Colorado.

Ayuda para reportar abusos

Reportar abusos

Gracias. Esta entrada ha sido marcada para la atención de un moderador.


Ayuda para reportar abusos

Reportar abusos

Falló el envío del reporte de abusos. Por favor intente después.


developerWorks: Ingresar


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. Cierta información de su perfil será mostrada públicamente, pero usted puede editar la información en cualquier momento. Su nombre, apellido (a menos que usted elija ocultarlo), y nombre de usuario acompañarán el contenido que usted publica.

Elija su nombre de usuario

La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. Cierta información de su perfil de developerWorks será mostrada públicamente, pero usted puede editar la información en cualquier momento. Su nombre, apellido (a menos que usted elija ocultarlo) y nombre de usuario acompañarán el contenido que usted publique.

(Debe ser entre 3 – 31 caracteres.)


Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Califique este artículo

Comentario

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=Linux
ArticleID=487270
ArticleTitle=APIs del kernel, Parte 1: Cómo invocar aplicaciones espacio de usuario desde el kernel
publish-date=05052010
author1-email=mtj@mtjones.com
author1-email-cc=

Etiquétalo Etiquetas

Help
Utilice el campo de búsqueda para encontrar todo tipo de contenido en My developerWorks con esa etiqueta.

Utilice el deslizador para controlar cuántas etiquetas deben mostrarse.

Las etiquetas populares muestran las etiquetas más difundidas en esta zona particular de contenido (por ejemplo: Java, Linux, WebSphere).

Mis Etiquetas muestra sus etiquetas en esta zona particular de contenido (por ejemplo: Java, Linux, WebSphere).

Utilice el campo de búsqueda para encontrar todo tipo de contenido en My developerWorks con esa etiqueta. Las etiquetas populares muestran las etiquetas más difundidas en esta zona particular de contenido (por ejemplo: Java, Linux, WebSphere). Mis Etiquetas muestra sus etiquetas en esta zona particular de contenido (por ejemplo: Java, Linux, WebSphere).