2010-08-15 14 views
8

Avere più di un processo letto da un dispositivo seriale (/ dev/ttyXX) fa in modo che entrambi i processi non possano ottenere tutti i dati - i dati saranno suddivisi tra loro in qualche modo. Mi piacerebbe scrivere un programma che legge da un dispositivo seriale, crea diverse coppie pty master/slave e quindi permette ai programmi che sono stati fatti leggere dal dispositivo seriale di leggere invece dai pty in modo che tutti i processi di lettura ricevano i dati dal dispositivo seriale e fare in modo che i pty si comportino come il dispositivo seriale nel senso che quando iniziano a leggere dalla pty ricevono solo i dati più recenti. In altre parole, non riceverai alcun dato che è stato scritto prima di iniziare a leggere (è mia esperienza che questo è come funzionano i dispositivi/dev/ttyXX, o almeno l'anemometro RS-232 da cui sto leggendo). I pipe nominati possono imitare queste semantiche intrappolando SIGPIPE per determinare che non ci sono lettori e quindi possiamo scegliere di non scrivere su quella particolare named pipe. Tuttavia, alcuni binari che sono stati scritti per utilizzare i terminali potrebbero non riuscire quando si parla alle pipe denominate, poiché i controlli per isatty() e la condizione di errno su chiamate come tcsetattr() possono causare condizioni di errore. La chiave qui è quella di poter usare i binari esistenti scritti per un terminale.Come posso rilevare quando qualcuno apre il lato slave di un pty (pseudo-terminale) in Linux?

Quindi, se riesco a rilevare quando il lato slave del pty è aperto per la lettura, questo dovrebbe darmi all'incirca la stessa semantica di SIGPIPE nel caso della pipe nominata. Ho notato che HP-UX ha TIOCTRAP come un comando ioctl() che sembra fare esattamente quello che voglio, ma purtroppo non è disponibile su Linux.

Ho letto i riferimenti per giorni e il numero di opzioni per questo tipo di cose è sconcertante. La risposta potrebbe trovarsi nelle impostazioni del terminale, comportamento di blocco/non blocco, impostazione delle dimensioni del buffer da qualche parte, condizioni segnalate dal sondaggio()/select() o qualche combinazione. Non riesco a trovare nulla, però. Mi chiedo se sia possibile che ho bisogno di scrivere il mio driver di periferica, ma sembra che dovrei essere in grado di farlo senza andare così lontano.

Quindi, per chiarimenti:
- La domanda è: come posso rilevare quando qualcuno apre il lato slave di un pty (pseudo-terminale) in Linux?
- Voglio un lettore che apra il lato slave del pty per ricevere i dati scritti rigorosamente dopo che il lettore apre il pty (se il mio processo di scrittura multipla scrive dati per un po 'di tempo prima che il lettore apra il lato slave, i dati verranno bufferizzati e alla fine lo scrittore bloccherà e il lettore schiavo, al momento dell'apertura, immediatamente ottenere tutti i dati nel buffer - questo non è auspicabile in quanto lo voglio per ottenere solo i dati generati in prossimità temporale immediato)
- e mosto essere un PTY, non una named pipe, socket, ecc, come isatty() e tcsetattr(), ecc bisogno di essere OK in modo che i binari esistenti funzionano

risposta

9

Il motivo non è possibile trovare questo è perché non c'è documentati interfaccia specifica per permetterlo. Tuttavia, c'è un trucco che ti permette di farlo. Dopo aver aperto il master pseudo-terminale (ipotizzato qui per essere descrittore di file ptm), si apre e si chiude immediatamente lato slave:

close(open(ptsname(ptm), O_RDWR | O_NOCTTY)); 

Questo imposta il flag HUP sul master tty. A questo punto è polling bandiera HUP regolarmente con poll() (ad esempio, ogni volta che i dati è disponibile in dall'origine dati):

struct pollfd pfd = { .fd = ptm, .events = POLLHUP }; 
poll(&pfd, 1, 10 /* or other small timeout */); 

if (!(pfd.revents & POLLHUP)) 
{ 
    /* There is now a reader on the slave side */ 
} 

Se il lettore va mai via, POLLHUP verrà impostato di nuovo.

Nel tuo caso, probabilmente non hanno nemmeno bisogno di ricordare da un ciclo al successivo se un determinato Pty dispone di un lettore - solo bloccare sul read() della sorgente di dati, poi, quando i dati sono disponibili, allo stesso tempo poll() tutti i tuoi master tty e invia i dati a tutti quelli che non hanno il set POLLHUP.

+0

Grazie per la spiegazione. Avevo trovato questo trucco nel codice sorgente in "socat", ma non mi ero reso conto che dovevo aprire e poi chiudere il lato slave. Anche dopo aver capito il trucco, avevo ancora alcuni episodi di strappare i capelli perché stavo usando openpty() invece di aprire esplicitamente/dev/ptmx che mi ha dato un fd separato, aperto per i pts e quindi non ho potuto ottenere una condizione HUP inizialmente. Chiamare openpty() e quindi chiudere lo slave fd restituito da esso è sufficiente. Grazie ancora per la risposta. Come sei venuto a conoscenza della funzionalità non documentata? –

+0

Penso di averlo appena trovato tramite post (s) su usenet. Questa domanda dovrebbe renderlo più google-able per le persone in futuro, però! – caf

3

Aggiungere un orologio inotify sullo slave pty e sondare quello. È possibile ottenere un evento inotify all'apertura. È quindi possibile eseguire il polling sul descrittore di file inotify e sul descrittore del file pty principale. È possibile ottenere un evento inotify per open (IN_OPEN). Questo sbloccherà il sondaggio quando viene aperto il lato slave.

Problemi correlati