1、tty_write函数源码:
static ssize_t tty_write(struct file * file, const char * buf, size_t count,
loff_t *ppos)}
调用do_tty_write函数,在此函数中调用线路规程中的write函数,此函数源码如下:
2、do_tty_write函数源码:
/*
* Split writes up in sane blocksizes to avoid
* denial-of-service type attacks
*/
static inline ssize_t do_tty_write(
ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
struct tty_struct *tty,
struct file *file,
const unsigned char *buf,
size_t count)
{
ssize_t ret = 0, written = 0;
if (file->f_flags & O_NONBLOCK) {
if (down_trylock(&tty->atomic_write))
return -EAGAIN;
}
else {
if (down_interruptible(&tty->atomic_write))
return -ERESTARTSYS;
}
if ( test_bit(TTY_NO_WRITE_SPLIT, &tty->flags) ) {
lock_kernel();
written = write(tty, file, buf, count);
unlock_kernel();
} else {
for (;;) {
unsigned long size = MAX(PAGE_SIZE*2,16384);
if (size > count)
size = count;
lock_kernel();
ret = write(tty, file, buf, size);
unlock_kernel();
此函数是作为参数传进来的,现在进行调用。调用的实际是:
struct tty_ldisc tty_ldisc_N_TTY = {
TTY_LDISC_MAGIC, /* magic */
"n_tty", /* name */
0, /* num */
0, /* flags */
n_tty_open, /* open */
n_tty_close, /* close */
n_tty_flush_buffer, /* flush_buffer */
n_tty_chars_in_buffer, /* chars_in_buffer */
read_chan, /* read */
write_chan, /* write */
n_tty_ioctl, /* ioctl */
n_tty_set_termios, /* set_termios */
normal_poll, /* poll */
n_tty_receive_buf, /* receive_buf */
n_tty_receive_room, /* receive_room */
n_tty_write_wakeup /* write_wakeup */
};
源码如下:
static ssize_t write_chan(struct tty_struct * tty, struct file * file,
const unsigned char * buf, size_t nr)
{
const unsigned char *b = buf;
DECLARE_WAITQUEUE(wait, current);
int c;
ssize_t retval = 0;
/* Job control check -- must be done at start (POSIX.1 7.1.1.4). */
if (L_TOSTOP(tty) &&
file->f_dentry->d_inode->i_rdev != CONSOLE_DEV &&
file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) {
retval = tty_check_change(tty);
if (retval)
return retval;
}
add_wait_queue(&tty->write_wait, &wait); 等待队列
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
}
if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) {
retval = -EIO;
break;
}
if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) {
while (nr > 0) {
ssize_t num = opost_block(tty, b, nr);
if (num < 0) {
if (num == -EAGAIN)
break;
retval = num;
goto break_out;
}
b += num;
nr -= num;
if (nr == 0)
break;
get_user(c, b);得到用户空间要写入的数据。
if (opost(c, tty) < 0)
break;
b++; nr--;
}
if (tty->driver.flush_chars)
tty->driver.flush_chars(tty);
} else {
c = tty->driver.write(tty, 1, b, nr);
调用具体tty_driver结构体中的flush_chars函数或者write函数。
if (c < 0) {
retval = c;
goto break_out;
}
b += c;
nr -= c;
}
if (!nr)
break;
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
break;
}
schedule();
}
break_out:
current->state = TASK_RUNNING;
remove_wait_queue(&tty->write_wait, &wait);
return (b - buf) ? b - buf : retval;
}
无法写入时,要睡眠等待。
if (ret <= 0)
break;
written += ret;
buf += ret;
count -= ret;
if (!count)
break;
ret = -ERESTARTSYS;
if (signal_pending(current))
break;
if (current->need_resched)
schedule();
}
}
if (written) {
file->f_dentry->d_inode->i_mtime = CURRENT_TIME;
ret = written;
}
up(&tty->atomic_write);
return ret;
}