Estou tentando descobrir como posso fazer loop de maneira confiável em uma leitura em um mestre de pt que possuo.
Eu abro o ptmx, concedo e destranco como de costume:
* ptmx stuff */
/* get the master (ptmx) */
int32_t masterfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
if(masterfd < 0){
perror("open");
exit(EXIT_FAILURE);
};
/* grant access to the slave */
if(grantpt(masterfd) < 0){
perror("grantpt");
exit(EXIT_FAILURE);
};
/* unlock the slave */
if(unlockpt(masterfd) < 0){
perror("unlockpt");
exit(EXIT_FAILURE);
};
comms_in->ptmx = masterfd;
Em seguida, salve o nome do escravo (sim, eu sei que sizeof (char) é sempre 1)
/* get the path to the slave */
char * slavepathPtr;
char * slavePath;
size_t slavepathLen;
if((slavepathPtr = ptsname(masterfd)) == NULL){
perror("ptsname");
exit(EXIT_FAILURE);
}else{
slavepathLen = strlen(slavepathPtr);
slavePath = (char *) malloc(sizeof(char) * (slavepathLen + 1));
strcpy(slavePath, slavepathPtr);
};
Eu então crio um symlink previsivelmente nomeado para o escravo ( /dev/pts/number
) em /dev/custom/predictable
(que foi fornecido como um argumento para este programa usando getopts) e verifico que suas permissões são seguras usando chamadas para access
, lstat
, readlink
, symlink
e confirme se o programa pode continuar a execução, caso contrário ele chama unlink
no symlink e finaliza o encadeamento.
Finalmente, o programa termina neste loop
ssize_t read_result;
ssize_t write_result;
while(1){
if((read_result = read(comms_in->ptmx, ptmxio_read_buffer, sizeof ptmxio_read_buffer)) <= 0){
{ /** calls thread ender routine */
pthread_mutex_lock(&COMMS_MUTEX);
comms_in->thread_statuses[PTMXIO_THREAD] = THREAD_FAILED;
pthread_mutex_unlock(&COMMS_MUTEX);
pthread_cond_signal(&SIG_PROGRAM_FINISHED);
pthread_exit((void *) comms_in);
}
}else if((write_result = write(STDOUT_FILENO, ptmxio_read_buffer, read_result)) != read_result){
{
/** same as above */
}
};
};
No sistema, posso executar este programa e tudo está cheio.
Os blocos de leitura.
Quando o link simbólico pts é aberto com cu
ou picocom
, então os bytes são lidos com sucesso até os limites do buffer no meu final ou no final do kernel, dependendo de quem está abaixo.
O problema surge quando o escravo está fechado.
Neste ponto, a leitura retorna -1
- > EIO
com o texto do erro: Input/output error
e continuará a fazê-lo, consumindo muito tempo de CPU se eu optar por não terminar o encadeamento e o loop.
Quando cu
ou picocom
ou mesmo apenas echo -en "some text" > /dev/pts/number
, a leitura bloqueia novamente, até que os bytes estejam disponíveis. No caso do redirecionamento para o symlink, obviamente, se ele preenche menos que um buffer, o read recebe aquele buffer e continua a retornar -1
- > EIO
novamente.
O que está acontecendo? Eu preciso de um método que não consuma muita CPU, pois isso é executado em um processador de aplicativo incorporado lento e permite-me restabelecer as leituras sem perder bytes.
Eu notei um thread fazendo uma ligação para isso:
ioctl(3, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS, {B38400 opost isig icanon echo ...})
e não pode fazer muito sentido de quais são as 3 opções, pois elas não estão nos meus cabeçalhos do Linux em qualquer lugar. Observe que 3
é comms_in->ptmx
/ masterfd
.
Aqui está um lstat sobre o symlink e algumas informações extras, note que o st_mode é inalterado antes e depois de leituras bem sucedidas e mal-sucedidas.
‘ptmxio_thread’ failed read (-1) on /dev/pts/13 /dev/pts/13: Input/output error
‘ptmxio_thread’ ptsNum (from ioctl) 13
‘ptmxio_thread’ st_dev: 6, st_ino: 451, st_mode: 0000A1FF, st_nlink: 1
‘ptmxio_thread’ st_uid: 000003E8, st_gid: 000003E8, st_rdev: 0, st_size: 11
‘ptmxio_thread’ st_blksize: 4096, st_blocks: 0, st_atime: 1540963806, st_mtime: 1540963798
‘ptmxio_thread’ st_ctime: 1540963798