How can terminal emulator read from ptm device while it missing read function? There is a PTY driver: https://github.com/torvalds/linux/blob/master/drivers/tty/pty.c. I see pty_write function, but can't see something like pty_read() function. As I understand, there's no need of read function for pty slave because it is a TTY device which has its own read buffer. So the corresponding method for reading in tty line discipline: https://github.com/torvalds/linux/blob/master/drivers/tty/n_tty.c#L2132.
But what about a master device? How can terminal emulator read from this device while it is not even a generic tty device?
tty_ldisc_init()-- which is really trivial to see for anyone looking it up in the source. If you don't believe it, trace a Linux kernel with a remote debugger. Also, it would be pretty obvious that the "line discipline" abstraction is handling both reading and writing -- have you read the comment above thepty_write()function you mention in your Q? – Jul 13 '19 at 12:32tty_ldisc_init()), what I don't understand is that this function saying:ldisc setup for new tty. What is meant here by tty? Pty slave or Pty master? – TwITe Jul 13 '19 at 12:41struct tty_structeach pointing to another via their->linkfield. The hack is pretty easy to follow -- unless you come with pre-conceived notions about the abstractions used. Linux was never based on SysV, never used STREAMS and modular/stackable line disciplines. The "line discipline" in linux is simply a struct with callbacks, referenced from thestruct tty_ldiscabstraction. – Jul 13 '19 at 12:43alloc_tty_struct()->tty_ldisc_init()will be called separately for both the slave and the master. Each one will have their separate line discipline, both using the same callbacks ("ops"). – Jul 13 '19 at 12:48o_tty = alloc_tty_struct(driver->other, idx)and this really makes sense. But what I don't understand is why we needptmx_openfunction then? Why it calls alloc_tty_struct() again? – TwITe Jul 13 '19 at 15:54pty_common_install()is called from the slave pty? There's even a comment about it ;-) As toptmx_open(), it's theopencallback from the/dev/pts/ptmxor/dev/ptmxfile ops table. There should be a way to open the master pty, right? FreeBSD hasposix_openpt()as a separate system call, Linux is not already there. There is still a device multiplexer living in the filesystem. – Jul 13 '19 at 16:24- What is the point of calling
– TwITe Jul 13 '19 at 18:05tty_init_dev()with ptm_driver and an index of pts file? It is inptmx_open()function. First we get pts pts device index:index = devpts_new_index(fsi)here: https://github.com/torvalds/linux/blob/master/drivers/tty/pty.c#L836 and then pass it totty = tty_init_dev(ptm_driver, index)tty_init_dev()function. Here: https://github.com/torvalds/linux/blob/master/drivers/tty/tty_io.c#L1333 we gettty_structfor ptm device. And then method callstty_driver_install_tty(), which callsinstall()method of current driver (ptm driver). Theinstall()method in fops maps to thepty_unix98_install, which will alloctty_structfor the other part of tty/pty device.So that means that
– TwITe Jul 13 '19 at 18:08install()method of pts device never be called, butinstall()method of ptm device will be called? Am I get it right?receive_buf()to process data? I have looked at thepty_write()function and this function just callstty_insert_flip_string_fixed_flag()method, which will just save data into the flip buffer structure. But I can't see any processing of this data? So, where's processing by ldisc is performing? – TwITe Jul 13 '19 at 19:39It looks weird because driver doesn't know anything about ldisc. Btw is here meant pty master/pty slave driver by low-level driver or something else?
– TwITe Jul 13 '19 at 19:42pty_write()->tty_flip_buffer_push()->tty_schedule_flip()->flush_to_ldisc()->receive_buf()(it is the method in tty_buffer.c file) ->port->client_ops->receive_buf. This method was set whileptmx_openwas called in the methodtty_init_dev()->tty_driver_install_tty()->driver->ops->installwhich maps to the methodpty_unix98_install()->pty_common_install(). This method does the following: – TwITe Jul 14 '19 at 08:53tty_port_init():port->client_ops = &default_client_ops;default_client_ops is the following const structure:
static const struct tty_port_client_operations default_client_ops = { .receive_buf = tty_port_default_receive_buf, .write_wakeup = tty_port_default_wakeup, };So we return to the
– TwITe Jul 14 '19 at 08:53port->client_ops->receive_bufcall and we know thattty_port_default_receive_bufwill be called. Now this method callstty_ldisc_receive_buf. That's all :)