Ir al contenido principal

El sistema operativo OpenVOS proporciona una interfaz de programación de aplicaciones (API) de alto nivel que, en general, facilita la programación del sistema. Pero a veces, se vuelve demasiado fácil - porque una simple llamada de subrutina a una rutina s$... puede esconder mucha complejidad.

Este es el primero de una serie irregular de posts para llamar su atención sobre tales escollos para que puedan evitarlos en sus diseños de aplicación.

Los males de los mensajes de la línea 25

La capacidad de escribir un mensaje en la línea 25 (o lo que sea el fondo) de una terminal permite a un usuario (o a un programa en ejecución) notificar a otros usuarios de condiciones inusuales. La interfaz de la línea de comandos es el comando send_message. El comando y los programas de usuario invocan en última instancia la subrutina de la API s$send_message. Los argumentos de esta llamada proporcionan el nombre_de_usuario de un receptor, el nombre_de_módulo de destino donde ese usuario podría estar conectado, el texto de notificación y algunos indicadores para modificar aspectos de la operación. A los llamantes privilegiados se les permite especificar el nombre del remitente; de lo contrario, se utiliza por defecto el nombre_de_usuario del proceso de envío.

Hasta ahora parece sencillo. Como la operación requiere el acceso al terminal de otro usuario, el kernel envía la solicitud en una cola de servidor para el proceso TheOverseer en el módulo objetivo. Normalmente, el proceso de envío espera entonces el estado de la entrega del mensaje, pero puede optar por no esperar esta respuesta.

El proceso de Overser para cualquier módulo lleva un registro de todos los procesos de inicio de sesión y el dispositivo terminal utilizado por esos procesos. Cuando recibe una solicitud de envío de un mensaje, busca en su lista de procesos y dispositivos, y para cada nombre_usuario de proceso que coincide con el argumento nombre_receptor, adjunta un puerto al dispositivo terminal del proceso, abre el puerto, escribe el mensaje en la línea de notificación, cierra el puerto y lo desconecta. Si varios procesos coinciden con el argumento nombre_receptor, este ciclo de adjuntar/abrir/escribir/cerrar/desenganchar se repite para cada uno.

Bien, esto es un poco más complicado de lo que hablamos al principio. Explorando mas a fondo, encontramos que cualquier modulo dado en el sistema puede estar hospedando procesos de ingreso donde la terminal real es un dispositivo en otro sistema/modulo que ha usado Open StrataLink (OSL) para ingresar a traves de la red (con el comando login -module). Ahora la aparentemente simple operacion de adjuntar/abrir/escribir/cerrar/desplegar en esa terminal tiene que involucrar procesos OSL y llamadas de procedimientos remotos de red al modulo remoto, y es mucho mas costoso que el manejo en el modulo.

La ampliación de los efectos se produce cuando el nombre de usuario del receptor se especifica como un nombre de estrella que puede coincidir con varios o todos los usuarios de inicio de sesión. Y se amplía aún más si el módulo de destino también se especifica como un nombre de estrella. El peor caso sería enviar el mensaje al usuario "*.*" (todos los usuarios, todos los grupos) en el módulo "*" (todos los módulos del sistema actual).

Implementación

s$expand_module_starname(target_module) =>  module_list;

foreach module_name in module_list
   send_overseer_request(module_name, send_message_request_data)
   The message is sent via a server queue and OSL to TheOverseer process
   on that module.

   TheOverseer  process on each receiving module then does:
   foreach terminal_process in TheOverseer’s list of
      login processes and sub-processes;

      if (terminal_process user_name matches receiver star name)
         if (messages_queued_for_device < 5)
            queue it for the login device
         else
            reject the request (e$too_many_terminal_messages)
   Simultáneamente, use hasta 10 puertos a la vez para enviar cualquier cola
        mensajes a las terminales;
   Para cada mensaje para cada terminal
      Adjuntar el puerto...
      Puerto abierto
      s$control(...MENSAJE DEL SISTEMA DE ESCRITURA...)
      Cerrar el puerto
      Desprender el puerto

Este procesamiento se hace en modo no_espera_para cada terminal de modo que
Los retrasos (como las solicitudes de E/S a través de la red) sólo afectan a la
procesamiento de mensajes para esa terminal.   

Si algún mensaje no puede ser entregado en 300 segundos, es desechado.

Cuando una aplicación utiliza este mecanismo para informar de errores, y se produce una avalancha de errores, la aplicación puede quedar fácilmente atascada en la información, alternando entre esperar a que se procesen otros mensajes e inundar los terminales de usuario con mensajes que llegan demasiado rápido para ser comprendidos.

Evasión

Ahora que sabes lo que pasa entre bastidores, la guía que puedo darte es:

  • Elabora cuidadosamente los nombres de las estrellas para los nombres de los usuarios y los nombres de los módulos para asegurarte de que llegas sólo a los usuarios que deben recibir el mensaje y no a otros. Por ejemplo, John_Doe.* o *.Operations o John_Doe.SysAdmin.
  • Considere la posibilidad de establecer una lista de usuarios no titulares para notificar y enviar cada notificación por separado.
  • Ponga el detalle de los mensajes de error en otro lugar (un registro de errores, por ejemplo) y utilice s$send_message para alertar sólo de la presencia de errores.
  • Limitar la frecuencia de las notificaciones a algo razonable (tal vez no más de una vez por minuto).
  • Suprima cualquier mensaje que sea igual al último enviado. El nuevo sólo se superpondría al anterior.

Si tiene alguna otra sugerencia, por favor, publique sus comentarios para que otros los vean.