Passa al contenuto principale

Il sistema operativo OpenVOS fornisce una Application Programming Interface (API) di alto livello che nel complesso rende facile la programmazione del sistema. Ma a volte diventa troppo facile - perché una semplice chiamata di subroutine ad una routine s$... potrebbe nascondere molta complessità.

Questo è il primo di una serie irregolare di post per richiamare la vostra attenzione su tali insidie in modo da poterle evitare nei vostri progetti di applicazione.

Il male dei messaggi della 25a linea

La possibilità di scrivere un messaggio sulla venticinquesima riga (o qualunque sia il fondo) di un terminale permette ad un utente (o ad un programma in esecuzione) di notificare ad altri utenti condizioni insolite. L'interfaccia a riga di comando è il comando send_message. Il comando e i programmi utente alla fine richiamano la subroutine API s$send_message. Gli argomenti di questa chiamata forniscono il nome_utente di un destinatario, il nome_modulo_di destinazione dove quell'utente potrebbe essere connesso, il testo di notifica e alcuni flag per modificare aspetti dell'operazione. I chiamanti privilegiati sono autorizzati a specificare il nome del mittente, altrimenti il nome_utente del processo di invio è quello predefinito.

Finora sembra semplice. Poiché l'operazione richiede l'accesso al terminale di proprietà di un altro utente, il kernel invia la richiesta su una coda di server per il processo TheOverseer sul modulo di destinazione. Normalmente, il processo di invio attende poi lo stato di consegna del messaggio, ma può scegliere di non aspettare questa risposta.

Il processoOverseer per qualsiasi modulo tiene traccia di tutti i processi di login e del dispositivo terminale utilizzato da tali processi. Quando riceve una richiesta di invio di un messaggio, cerca la sua lista di processi e dispositivi, e per ogni nome_utente del processo che corrisponde all'argomento nome_ricevitore, attacca una porta al dispositivo terminale del processo, apre la porta, scrive il messaggio sulla linea di notifica, chiude la porta e stacca la porta. Se più processi corrispondono all'argomento receiver_name, questo ciclo di allega/apri/scrive/chiude/stacca viene ripetuto per ognuno di essi.

Ok - questo è un po' più complicato di quanto abbiamo detto la prima volta. Esplorandolo ulteriormente, scopriamo che qualsiasi modulo del sistema può ospitare processi di login in cui il vero terminale è un dispositivo su un altro sistema/modulo che ha usato Open StrataLink (OSL) per effettuare il login attraverso la rete (con il comando login -modulo). Ora l'operazione apparentemente semplice di collegare/aprire/scrivere/scrivere/chiudere/scaricare su quel terminale deve coinvolgere i processi OSL e le chiamate di procedura remota di rete al modulo remoto, ed è molto più costosa della gestione dei moduli.

L'ingrandimento degli effetti avviene quando il nome_utente del destinatario viene specificato come nome_stella che potrebbe corrispondere a più o a tutti gli utenti di login. E viene ulteriormente ingrandito se anche il modulo di destinazione viene specificato come nome a stella. Il caso peggiore sarebbe quello di inviare il messaggio all'utente "*.*". (tutti gli utenti, tutti i gruppi) sul modulo "*" (tutti i moduli del sistema attuale).

Implementazione

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)
   Contemporaneamente, utilizzare fino a 10 porte alla volta per inviare le eventuali code
        messaggi ai terminali;
   Per ogni messaggio per ogni terminale
      Attaccare la porta
      Porta aperta
      s$control(...WRITE_SYSTEM_MESSAGE...)
      Chiudere il porto
      Staccare la porta

Questa elaborazione viene effettuata in modalità no_wait_mode per ogni terminale in modo che
i ritardi (come le richieste di I/O in tutta la rete) riguardano solo il
l'elaborazione dei messaggi per quel terminale.   

Se un messaggio non può essere consegnato in 300 secondi, viene scaricato.

Quando un'applicazione utilizza questo meccanismo per segnalare gli errori e si verifica una marea di errori, l'applicazione può facilmente impantanarsi nella segnalazione, alternando l'attesa dell'elaborazione di altri messaggi e inondando i terminali degli utenti con messaggi che arrivano troppo velocemente per essere compresi.

Evitare

Ora che sapete cosa succede dietro le quinte, la guida che posso darvi è:

  • Create con cura i nomi delle stelle per i nomi degli utenti e i nomi dei moduli per assicurarvi di raggiungere solo gli utenti che devono ricevere il messaggio e nessun altro. Per esempio, John_Doe.* o *.Operations o John_Doe.SysAdmin.
  • Considerare la possibilità di implementare un elenco di utenti senza nome da notificare e inviare ogni notifica separatamente.
  • Mettere il dettaglio dei messaggi di errore altrove (un registro degli errori, per esempio) e utilizzare s$send_message per avvertire solo la presenza di errori.
  • Limitare la frequenza delle notifiche a qualcosa di ragionevole (magari non più di una volta al minuto).
  • Sopprimere qualsiasi messaggio che sia lo stesso dell'ultimo inviato. Il nuovo si sovrapporrebbe al precedente.

Se avete altri suggerimenti, vi preghiamo di inviare i vostri commenti per farli vedere agli altri.

© 2024 Stratus Technologies.