Port serial hang saat close()

Saya mengembangkan modul kernel sederhana ini, yang mengemulasi port serial dengan menggunakan antrian FIFO dan pengatur waktu (baca dari perangkat keras : keluar dari antrian, tulis ke perangkat keras : masukkan ke dalam antrian).
Kode sumber ditampilkan berikutnya.

  #include <linux/kernel.h>
  #include <linux/errno.h>
  #include <linux/init.h>
  #include <linux/slab.h>
  #include <linux/tty.h>
  #include <linux/tty_flip.h>
  #include <linux/serial.h>
  #include <linux/serial_core.h>
  #include <linux/module.h>


  #define TINY_SERIAL_DEBUG
  #define pr_fmt(fmt) "tiny_serial: " fmt

  #if defined(TINY_SERIAL_DEBUG)
  #define DBG(fmt, ...)  printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
  #else 
  #define DBG(fmt, ...)  no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)   
  #endif

  #define DRIVER_AUTHOR "Me Me <[email protected]>"
  #define DRIVER_DESC "Tiny serial driver"

  /* Module information */
  MODULE_AUTHOR( DRIVER_AUTHOR );
  MODULE_DESCRIPTION( DRIVER_DESC );
  MODULE_LICENSE("GPL");

  #define DELAY_TIME        100// HZ * 2    /* 2 seconds per character */
  #define TINY_DATA_CHARACTER    't'

  #define TINY_SERIAL_MAJOR    240 //240    /* experimental range */
  #define TINY_SERIAL_MINORS    1 //1    /* only have one minor */
  #define UART_NR            1    /* only use one port */

  #define TINY_SERIAL_NAME    "ttytiny"

  #define MY_NAME            TINY_SERIAL_NAME

  #define BUF_SIZE 4096

  static char buf[BUF_SIZE];
  static char *read_ptr;
  static char *write_ptr;

  static struct timer_list *timer;


  static void serial_out(char data) 
  {
      *write_ptr = data;
      write_ptr++;
      if (write_ptr >= buf + BUF_SIZE)
          write_ptr = buf;
  }

  static void serial_in(char *data)
  {
      if (read_ptr == NULL) {
          DBG("pointer is null !\n");
      }

      if (read_ptr && (read_ptr != write_ptr)) {
          *data = *read_ptr;
            read_ptr++;
         if(read_ptr >= buf + BUF_SIZE)
              read_ptr = buf;
      }
  }


  static void tiny_stop_tx(struct uart_port *port)
  {
      DBG("tiny_stop_tx()\n");
  }

  static void tiny_stop_rx(struct uart_port *port)
  {
      DBG("tiny_stop_rx()\n");
  }

  static void tiny_enable_ms(struct uart_port *port)
  {
      DBG("tiny_enable_ms()\n");
  }

  static void tiny_rx_chars(struct uart_port *port, int size)
  {
      int i = 0;
      char byte;
      char flag;
      struct tty_port *tty = &port->state->port;

      if (size <= 0) {
          return;
      }

      while (size--) {
         serial_in(&byte);
         DBG("read: 0x%2x\n", byte);
         flag = TTY_NORMAL;
         port->icount.rx++;

         if (uart_handle_sysrq_char(port, byte)) {
             DBG("found ignore char !\n");
             goto ignore_char;
         }

         uart_insert_char(port, 0, 0, byte, flag);

 ignore_char:
         i ++;
     }

     tty_flip_buffer_push(tty);
     DBG("push to user space !\n");
 }

 static int tiny_tx_chars(struct uart_port *port)
 {
     struct circ_buf *xmit = &port->state->xmit;
     int count;

     DBG("tiny_tx_chars()\n"); 

     if (port->x_char) {
         DBG("wrote 0x%2x\r\n", port->x_char);
         port->icount.tx++;
         port->x_char = 0;
         return 0;
     }
     if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
         tiny_stop_tx(port);
         return 0;
     }

     count = port->fifosize >> 1;

     do {
         DBG("wrote 0x%2x\r\n", xmit->buf[xmit->tail]);
         serial_out(xmit->buf[xmit->tail]);
         xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
         port->icount.tx++;
         if (uart_circ_empty(xmit))
             break;
     } while (--count > 0);

     if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
         uart_write_wakeup(port);

     if (uart_circ_empty(xmit))
         tiny_stop_tx(port);

     return ((port->fifosize >> 1) - count + 1);
 }

 static void tiny_start_tx(struct uart_port *port)
{
     DBG("tiny_start_tx()\n");
 }

 static void tiny_timer(unsigned long data)
 {
     struct uart_port *port;
     struct tty_port *tport;
     int ret = 0;

     DBG("tiny_timer()\n"); 
     port = (struct uart_port *)data;
     if (!port)
         return;
     if (!port->state)
         return;
     tport = &port->state->port;

     /* resubmit the timer again */
     timer->expires = jiffies + DELAY_TIME;
     add_timer(timer);

     /* see if we have any data to transmit */
     ret = tiny_tx_chars(port);
     tiny_rx_chars(port, ret);
}

 static unsigned int tiny_tx_empty(struct uart_port *port)
 {
     DBG("tiny_tx_empty()\n");
     return 0;
 }

 static unsigned int tiny_get_mctrl(struct uart_port *port)
 {
    DBG("tiny_get_mctrl()\n");
     return 0;
 }

 static void tiny_set_mctrl(struct uart_port *port, unsigned int mctrl)
 {
     DBG("tiny_set_mctrl()\n"); 
 }

 static void tiny_break_ctl(struct uart_port *port, int break_state)
 {
     DBG("tiny_set_mctrl()\n"); 
 }

 static void tiny_set_termios(struct uart_port *port,
                  struct ktermios *new, struct ktermios *old)
 {
     int baud, quot, cflag = new->c_cflag;

     DBG("tiny_set_termios()\n"); 

     /* get the byte size */
     switch (cflag & CSIZE) {
     case CS5:
         DBG(" - data bits = 5\n");
         break;
     case CS6:
         DBG(" - data bits = 6\n");
         break;
     case CS7:
         DBG(" - data bits = 7\n");
         break;
     default: // CS8
         DBG(" - data bits = 8\n");
         break;
     }

     /* determine the parity */
     if (cflag & PARENB)
         if (cflag & PARODD)
             DBG(" - parity = odd\n");
         else
             DBG(" - parity = even\n");
     else
         DBG(" - parity = none\n");

     /* figure out the stop bits requested */
     if (cflag & CSTOPB)
         DBG(" - stop bits = 2\n");
     else
         DBG(" - stop bits = 1\n");

     /* figure out the flow control settings */
     if (cflag & CRTSCTS)
         DBG(" - RTS/CTS is enabled\n");
     else
         DBG(" - RTS/CTS is disabled\n");

     /* Set baud rate */
     baud = uart_get_baud_rate(port, new, old, 9600, 115200);
     quot = uart_get_divisor(port, baud);


 }

 static int tiny_startup(struct uart_port *port)
 {
     /* this is the first time this port is opened */
     /* do any hardware initialization needed here */

     DBG("tiny_startup()\n");

     /* create our timer and submit it */
     if (!timer) {
         timer = kmalloc(sizeof(*timer), GFP_KERNEL);
         if (!timer)
             return -ENOMEM;
         init_timer(timer);
     }
     timer->data = (unsigned long)port;
     timer->expires = jiffies + DELAY_TIME;
     timer->function = tiny_timer;
     add_timer(timer);
     return 0;
 }

 static void tiny_shutdown(struct uart_port *port)
 {
     /* The port is being closed by the last user. */
     /* Do any hardware specific stuff here */

     DBG("tiny_shutdown()\n");

     /* shut down our timer */
     del_timer(timer);
 }

 static const char *tiny_type(struct uart_port *port)
 {
     DBG("tiny_type()\n");
     return "tinytty";
 }

 static void tiny_release_port(struct uart_port *port)
 {
     DBG("tiny_release_port()\n");
 }

 static int tiny_request_port(struct uart_port *port)
 {
     DBG("tiny_request_port()\n");
    return 0;
 }

 static void tiny_config_port(struct uart_port *port, int flags)
 {
     DBG("tiny_config_port()\n");
 }

 static int tiny_verify_port(struct uart_port *port, struct serial_struct *ser)
 {
     DBG("tiny_verify_port()\n");
     return 0;
 }

 static struct uart_ops tiny_ops = {
     .tx_empty    = tiny_tx_empty,
     .set_mctrl    = tiny_set_mctrl,
     .get_mctrl    = tiny_get_mctrl,
     .stop_tx    = tiny_stop_tx,
     .start_tx    = tiny_start_tx,
     .stop_rx    = tiny_stop_rx,
     .enable_ms    = tiny_enable_ms,
     .break_ctl    = tiny_break_ctl,
     .startup    = tiny_startup,
     .shutdown    = tiny_shutdown,
     .set_termios    = tiny_set_termios,
     .type        = tiny_type,
     .release_port    = tiny_release_port,
     .request_port    = tiny_request_port,
     .config_port    = tiny_config_port,
     .verify_port    = tiny_verify_port,
 };

 static struct uart_port tiny_port = {
     .ops        = &tiny_ops,
     .line       = 0,
     .type       = 104,
     .iotype     = SERIAL_IO_PORT,
     .fifosize   = 128,
     .flags      = ASYNC_BOOT_AUTOCONF,
     .irq        = 0,
 };

 static struct uart_driver tiny_reg = {
     .owner        = THIS_MODULE,
     .driver_name    = TINY_SERIAL_NAME,
     .dev_name    = TINY_SERIAL_NAME,
     .major        = TINY_SERIAL_MAJOR,
     .minor        = TINY_SERIAL_MINORS,
     .nr        = UART_NR,
 };

 static int __init tiny_init(void)
 {
     int result;

     DBG(KERN_INFO "Tiny serial driver loaded\n");

     result = uart_register_driver(&tiny_reg);
     if (result) {
         DBG("tiny_init() error!\n");
         return result;
     }

     result = uart_add_one_port(&tiny_reg, &tiny_port);
     if (result) {
         DBG("uart_add_one_port() error!\n");
         uart_unregister_driver(&tiny_reg);
     }

     read_ptr = buf;
     write_ptr = buf;

     return result;
 }

 module_init(tiny_init);

Lalu, saya menulis aplikasi pengujian sederhana yang mengonfigurasi pengaturan port (baud rate, parity, stop bits, dll) dan memulai transaksi tulis + baca, membaca string yang ditulis sebelumnya.
Kode sumber ditampilkan berikutnya.

  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h> 
  #include <strings.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  #include <unistd.h>
  #include <termios.h>
  #include <sys/stat.h>

  #include <sys/select.h>
  #include <sys/time.h>

  #define PAR_NONE   0
  #define PAR_EVEN   1
  #define PAR_ODD    2

  #define DATA_8BIT  1
  #define DATA_7BIT  2

  #define STOP_1BIT  1
  #define STOP_2BIT  2


  struct tiny_op {
      int max_fd;
      int fd;
      fd_set rfds;
      fd_set wfds;
      fd_set efds;
      struct timeval r_timeout;
      struct timeval w_timeout; 
  };

  static struct tiny_op tops;


  static void set_termios(struct termios *termios, int baudrate, int parity, int bits, int stop) 
  {
      termios->c_cflag |= CLOCAL | CREAD;

      termios->c_cflag &= ~CSIZE;
      switch (bits) {
          case DATA_7BIT:
              termios->c_cflag |= CS7;
              break;

          case DATA_8BIT:
              termios->c_cflag |= CS8; 
              break;

          default:

              termios->c_cflag |= CS8;
              break;
      }

      switch (parity) {
          case PAR_NONE:
              termios->c_cflag &= ~PARENB;
              termios->c_cflag &= ~PARODD;
              break;

          case PAR_EVEN:
              termios->c_cflag |= PARENB;
              termios->c_cflag &= ~PARODD;
              break;

          case PAR_ODD:
              termios->c_cflag |= PARENB;
              termios->c_cflag |= PARODD;
              break;

          default:
              termios->c_cflag &= ~PARENB;
              termios->c_cflag &= ~PARODD;
              break;
      }

      switch (stop) {
          case STOP_1BIT:
              termios->c_cflag &= ~CSTOPB;
              break;

          case STOP_2BIT:
              termios->c_cflag |= CSTOPB;
              break;

          default:
              termios->c_cflag &= ~CSTOPB;
              break;
      }

      termios->c_iflag |= INPCK | ISTRIP;
      termios->c_lflag = 0;
      termios->c_oflag = 0;

      termios->c_cc[VTIME] = 5;
      termios->c_cc[VMIN]  = 0;

      cfsetspeed(termios, baudrate);
 }


 static int tiny_write(struct tiny_op *op, char *buff, int size)
 {
     int ret = -1;
     int len = 0;

     op->w_timeout.tv_sec  = 5;
     op->w_timeout.tv_usec = 0;

     ret = select(op->max_fd, NULL, &op->wfds, &op->efds, &op->w_timeout);
     if (ret < 0) {
         printf("[TINY SERIAL] Select fallita (write) !\n");
         return -1;
     } if (0 == ret) {
         printf("[TINY SERIAL] Select time-out (write) !\n");
     } else {
             if (FD_ISSET(op->fd, &op->efds)) {
             printf("[TINY SERIAL] Attenzione: errore in scrittura!\n");
             return -1;
         }

         if (FD_ISSET(op->fd, &op->wfds)) {
             printf("[TINY SERIAL] Scrittura pronta, procedo !\n");
             len = write(op->fd, (const void *)buff, size);

             if (len == size) {
                 printf("[TINY SERIAL] Scrittura completata!\n");
             } else {
                 printf("[TINY SERIAL] Scrittura parzialmente completata, scritti : = %d\n", len);
             }
        }
     }

     return 0;
 }


 static int tiny_read(struct tiny_op *op, char *buff, int size)
 {
     int ret = -1;
     int len = 0;

     op->r_timeout.tv_sec = 5;
     op->r_timeout.tv_usec = 0;

     ret = select(op->max_fd, &op->rfds, NULL, &op->efds, &op->r_timeout);
     if (ret < 0) {
         printf("[TINY SERIAL] Select fallita (read) !\n");
         return -1;
     } if (0 == ret) {
         printf("[TINY SERIAL] Select time-out (read)!\n");
     } else {
         if (FD_ISSET(op->fd, &op->efds)) {
             printf("[TINY SERIAL] Attenzione: errore in lettura!\n");
             return -1;
         }

         if (FD_ISSET(op->fd, &op->rfds)) {
             printf("[TINY SERIAL] Dati da leggere disponibili!\n");

             len = read(op->fd, (void *)buff, size);
             printf("[TINY SERIAL] Lettura da seriale: %s, len: %d\n", buff, len);
         }
     }

     return 0;
 }


 int main(int argc, char **argv)
 {
     int fd = -1, ret = -1;
     struct termios oldtio, newtio;

     char *str = {"Hello world!!\0"};
     char buff[strlen(str)];

     if(argc == 1){

       printf("[TINY DRIVER] Inserisci il device seriale da testare.\n");
       return -1;
     }

     char * device = argv[1];
     struct stat file_infos;

     if(strlen(device) == 0){
        printf("[TINY DRIVER] Seleziona un device corretto.\n");
        return -1;
     }

     printf("[TINY DRIVER] Hai selezionato il device: %s\n", device);

     if(stat(device, &file_infos) < 0){
        printf("[TINY DRIVER] Attenzione: errore nell'accesso al device selezionato: %s, riprova con un altro dispositivo.\n", device);
        return -1;
     }

     bzero((void *)&oldtio, sizeof(oldtio));
     bzero((void *)&newtio, sizeof(newtio)); 

     fd = open(device, O_RDWR | O_NONBLOCK | O_SYNC);
     if (fd == -1) {
         printf("[TINY SERIAL] failed to open /dev/ttytiny0 !\n");
         return -1;
     }

     printf("[TINY SERIAL] succeed to open /dev/ttytiny0 !\n");

     ret = tcgetattr(fd, &oldtio);
     if (ret != 0) {
         printf("[TINY SERIAL] failed to get attr !\n");
         close(fd);
         return -1;
     }

     set_termios(&newtio, B38400, PAR_EVEN, DATA_8BIT, STOP_2BIT);

     tcflush(fd, TCIOFLUSH);

     ret = tcsetattr(fd, TCSANOW, &newtio);
     if (ret != 0) {
         printf("[TINY SERIAL] failed to set termios !\n");
         close(fd);
         return -1;
     }

     tops.fd = fd;

     tops.max_fd = tops.fd + 1;

     FD_ZERO(&tops.rfds);
     FD_ZERO(&tops.wfds);
     FD_ZERO(&tops.efds);

     FD_SET(tops.fd, &tops.rfds);
     FD_SET(tops.fd, &tops.wfds);
     FD_SET(tops.fd, &tops.efds);

     if (tiny_write(&tops, str, strlen(str)) != 0) {
         close(fd);
         return -1;
     }

     if (tiny_read(&tops, buff, sizeof(buff)) != 0) {
         close(fd);
         return -1;
     }

     ret = tcsetattr(fd, TCSANOW, &oldtio);
     if (ret != 0) {
         printf("[TINY SERIAL] Errore nel reset delle impostazioni.\n");
     }else{
         printf("[TINY SERIAL] Impostazioni resettate correttamente.\n");
     }

     ret = tcflush(fd, TCIOFLUSH);

     if(ret != 0){
        printf("[TINY SERIAL] Errore nel flushing dei dati (finale) !\n");
     }else{
        printf("[TINY SERIAL] Dati flushati correttamente!\n");
     }

     //Program hangs on this call
     ret = close(fd);

     if (ret != 0) {   
         printf("[TINY SERIAL] Errore nella Chiusura del file !\n");
         return -1;
     }else{
         printf("[TINY SERIAL] Chiusura del file avvenuta correttamente !\n");
     }

     return 0;
 }

Masalah saya adalah: aplikasi pengujian berfungsi dengan baik (saya dapat menulis dan membaca string saya sendiri) hingga mencapai close(2): hang selamanya, tanpa mencapai akhir program (saya harus menutupnya dengan CTRL+C, dan kemudian menutup dengan benar saat modul kernel memanggil fungsi tiny_shutdown()).
Saya juga mencoba menulis program sederhana untuk membuka dan menutup perangkat /dev/ttytiny0, tetapi hasilnya sama (walaupun saya perhatikan, jika saya menghapus close(2) operasi, program masih hang tanpa berhenti, tetapi kali ini saya tidak bisa (jangan ditutup dengan CTRL+C).
Tautan/referensi apa pun ke buku atau materi tentang subjek ini akan sangat dihargai.
Terima kasih sebelumnya!

Edit : Di sini laporkan pesan log kernel (saat menjalankan aplikasi pengujian)

[  446.862221] tiny_ser: module verification failed: signature and/or required key missing - tainting kernel
[  446.864143] tiny_serial: 6Tiny serial driver loaded
[  486.715801] tiny_serial: tiny_startup()
[  486.715812] tiny_serial: tiny_set_termios()
[  486.715814] tiny_serial:  - data bits = 8
[  486.715816] tiny_serial:  - parity = none
[  486.715818] tiny_serial:  - stop bits = 1
[  486.715820] tiny_serial:  - RTS/CTS is disabled
[  486.715824] tiny_serial: tiny_set_mctrl()
[  486.715853] tiny_serial: tiny_set_termios()
[  486.715856] tiny_serial:  - data bits = 8
[  486.715857] tiny_serial:  - parity = even
[  486.715859] tiny_serial:  - stop bits = 2
[  486.715861] tiny_serial:  - RTS/CTS is disabled
[  486.715943] tiny_serial: tiny_start_tx()
[  487.116105] tiny_serial: tiny_timer()
[  487.116171] tiny_serial: tiny_tx_chars()
[  487.116183] tiny_serial: wrote 0x42
[  487.116189] tiny_serial: wrote 0x75
[  487.116196] tiny_serial: wrote 0x6f
[  487.116202] tiny_serial: wrote 0x6e
[  487.116208] tiny_serial: wrote 0x61
[  487.116214] tiny_serial: wrote 0x73
[  487.116220] tiny_serial: wrote 0x65
[  487.116226] tiny_serial: wrote 0x72
[  487.116232] tiny_serial: wrote 0x61
[  487.116238] tiny_serial: wrote 0x20
[  487.116245] tiny_serial: wrote 0x64
[  487.116251] tiny_serial: wrote 0x72
[  487.116257] tiny_serial: wrote 0x69
[  487.116263] tiny_serial: wrote 0x76
[  487.116269] tiny_serial: wrote 0x65
[  487.116275] tiny_serial: wrote 0x72
[  487.116281] tiny_serial: wrote 0x21
[  487.116287] tiny_serial: wrote 0x21
[  487.116295] tiny_serial: tiny_stop_tx()
[  487.116303] tiny_serial: read: 0x42
[  487.116312] tiny_serial: read: 0x75
[  487.116318] tiny_serial: read: 0x6f
[  487.116324] tiny_serial: read: 0x6e
[  487.116330] tiny_serial: read: 0x61
[  487.116337] tiny_serial: read: 0x73
[  487.116343] tiny_serial: read: 0x65
[  487.116349] tiny_serial: read: 0x72
[  487.116355] tiny_serial: read: 0x61
[  487.116361] tiny_serial: read: 0x20
[  487.116367] tiny_serial: read: 0x64
[  487.116373] tiny_serial: read: 0x72
[  487.116379] tiny_serial: read: 0x69
[  487.116385] tiny_serial: read: 0x76
[  487.116391] tiny_serial: read: 0x65
[  487.116397] tiny_serial: read: 0x72
[  487.116403] tiny_serial: read: 0x21
[  487.116409] tiny_serial: read: 0x21
[  487.116444] tiny_serial: push to user space !
[  487.116565] tiny_serial: tiny_start_tx()
[  487.116709] tiny_serial: tiny_set_termios()
[  487.116713] tiny_serial:  - data bits = 8
[  487.116715] tiny_serial:  - parity = none
[  487.116717] tiny_serial:  - stop bits = 1
[  487.116719] tiny_serial:  - RTS/CTS is disabled
[  487.116746] tiny_serial: tiny_tx_empty()
[  487.516021] tiny_serial: tiny_timer()
[  487.516094] tiny_serial: tiny_tx_chars()
[  487.516104] tiny_serial: tiny_stop_tx()
[  487.915917] tiny_serial: tiny_timer()
[  487.915960] tiny_serial: tiny_tx_chars()
[  487.915971] tiny_serial: tiny_stop_tx()
[  505.910955] tiny_serial: tiny_timer()
[  505.910968] tiny_serial: tiny_tx_chars()
[  505.910971] tiny_serial: tiny_stop_tx()
[  506.455320] tiny_serial: tiny_timer()
[  506.455332] tiny_serial: tiny_tx_chars()
[  506.455335] tiny_serial: tiny_stop_tx()
[  506.855344] tiny_serial: tiny_timer()
[  506.855428] tiny_serial: tiny_tx_chars()
[  506.855437] tiny_serial: tiny_stop_tx()
[  507.255499] tiny_serial: tiny_timer()
[  507.255563] tiny_serial: tiny_tx_chars()
[  507.255572] tiny_serial: tiny_stop_tx()
[  507.655342] tiny_serial: tiny_timer()
[  507.655401] tiny_serial: tiny_tx_chars()
[  507.655411] tiny_serial: tiny_stop_tx()
[  507.755090] tiny_serial: tiny_stop_rx()
[  507.755100] tiny_serial: tiny_tx_empty()
[  507.755103] tiny_serial: tiny_set_mctrl()
[  507.755105] tiny_serial: tiny_shutdown()
[  507.755108] tiny_serial: tiny_shutdown() - after del_timer()

Perhatikan bahwa urutan tiny_stop_rx() - tiny_tx_empty() - tiny_set_mctrl() - tiny_shutdown() dipanggil ketika saya menghentikan eksekusi aplikasi pengujian dengan CTRL+C.
Pesan berulang lainnya (urutan tiny_timer() - tiny_tx_chars() - tiny_stop_tx()) dihasilkan oleh pengatur waktu yang memeriksa apakah ada sesuatu yang harus dikirim (tetapi antriannya kosong, sehingga tertidur lagi).
Tentu saja, log aplikasi pengujian menunjukkan perilaku yang benar, hingga mencapai tutup() fungsi.


person aldoalpha    schedule 01.07.2018    source sumber
comment
Bolehkah menunjukkan log yang ditulis oleh pengemudi saat digunakan oleh program pengujian?   -  person alk    schedule 01.07.2018
comment
Tentu, saya menambahkannya ke pertanyaan.   -  person aldoalpha    schedule 01.07.2018
comment
Jadi apakah pengemudi berhenti masuk setelah close() mulai memblokir? Jika ya, yang mana entri terakhir?   -  person alk    schedule 01.07.2018
comment
Maukah Anda juga meletakkan pernyataan log lain tepat setelah del_timer() dan menguji ulang?   -  person alk    schedule 01.07.2018
comment
Pengemudi terus masuk bahkan setelah aplikasi pengujian memanggil fungsi tutup. Itu terus mencatat urutan tiny_timer() - tiny_tx_chars() - tiny_stop_tx() sampai saya menutup paksa dengan CTRL+C. Pada saat itu, seperti yang Anda lihat dari log, menurut saya urutan tiny_stop_rx() - tiny_tx_empty() - tiny_set_mctrl() - tiny_shutdown() dipanggil. Perhatikan juga bahwa saya menambahkan titik log tepat setelah panggilan del_timer(), dan itu ditampilkan dengan benar.   -  person aldoalpha    schedule 01.07.2018
comment
P.S: Anda akan melihat beberapa 'lubang' di pesan log dengan melihat nilai numerik di sebelah kiri: itu hanyalah pengulangan urutan tiny_timer() - tiny_tx_chars() - tiny_stop_tx(), saya menghapus beberapa pesan log karena batas karakter SO.   -  person aldoalpha    schedule 01.07.2018
comment
Juga: Saya menggunakan dmesg | grep tiny › log.txt untuk mengumpulkan log kernel yang terkait dengan modul kernel.   -  person aldoalpha    schedule 01.07.2018
comment
Tidak yakin apakah ini membantu, tapi dari kernel.org/doc/Documentation/serial/driver kita pelajari: tx_empty(port) Fungsi ini menguji apakah fifo pemancar dan shifter untuk port yang dijelaskan oleh 'port' kosong. [..] Jika port tidak mendukung operasi ini, maka port tersebut akan mengembalikan TIOCSER_TEMT.   -  person alk    schedule 01.07.2018
comment
Saya merasa hal di atas mungkin penting, bagi saya sepertinya kernel berusaha mati-matian untuk melakukan rx, apa yang tidak ada dan hanya sinyal yang Anda berikan Ctrl-C yang meringankannya.   -  person alk    schedule 01.07.2018
comment
Implementasi Anda mengembalikan 0 dari tx_empty() yang artinya tidak kosong.   -  person alk    schedule 01.07.2018
comment
Mengerti maksudnya. Saya akan mencoba mengubah perilaku itu, saya akan melaporkan perubahan apa pun: terima kasih!   -  person aldoalpha    schedule 01.07.2018
comment
Memecahkan itu. Saya menambahkan beberapa baris yang memeriksa apakah buffer kosong atau tidak, dan kemudian mengembalikan nilai yang sesuai berdasarkan itu. Hal yang dipelajari: selalu periksa dokumentasinya terlebih dahulu! Terima kasih banyak.   -  person aldoalpha    schedule 01.07.2018
comment
Terima kasih kembali. Dan sebuah kasus yang sungguh menarik. Pemblokiran close() jarang terjadi ...   -  person alk    schedule 01.07.2018


Jawaban (1)


Implementasi Anda mengembalikan 0 dari tx_empty() yang berarti "tidak kosong".

Dari kernel.org/doc/Documentation/serial/driver:

tx_empty(port)

Fungsi ini menguji apakah fifo pemancar dan shifter untuk port yang dijelaskan oleh 'port' kosong. Jika kosong, fungsi ini harus mengembalikan TIOCSER_TEMT, jika tidak, mengembalikan 0. Jika port tidak mendukung operasi ini, maka port harus mengembalikan TIOCSER_TEMT.

person alk    schedule 01.07.2018