?? tty_io.c
字號:
{ return ((current->blocked & (1<<(sig-1))) || (current->sigaction[sig-1].sa_handler == SIG_IGN));}static inline int input_available_p(struct tty_struct *tty){ /* Avoid calling TTY_READ_FLUSH unnecessarily. */ if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary)) return 1; /* Shuffle any pending data down the queues. */ TTY_READ_FLUSH(tty); if (tty->link) TTY_WRITE_FLUSH(tty->link); if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary)) return 1; return 0;}static int read_chan(struct tty_struct *tty, struct file *file, unsigned char *buf, unsigned int nr){ struct wait_queue wait = { current, NULL }; int c; unsigned char *b = buf; int minimum, time; int retval = 0; /* Job control check -- must be done at start and after every sleep (POSIX.1 7.1.1.4). */ /* NOTE: not yet done after every sleep pending a thorough check of the logic of this change. -- jlc */ /* don't stop on /dev/console */ if (file->f_inode->i_rdev != CONSOLE_DEV && current->tty == tty->line) { if (tty->pgrp <= 0) printk("read_chan: tty->pgrp <= 0!\n"); else if (current->pgrp != tty->pgrp) { if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp)) return -EIO; kill_pg(current->pgrp, SIGTTIN, 1); return -ERESTARTSYS; } } if (L_ICANON(tty)) { minimum = time = 0; current->timeout = (unsigned long) -1; } else { time = (HZ / 10) * TIME_CHAR(tty); minimum = MIN_CHAR(tty); if (minimum) current->timeout = (unsigned long) -1; else { if (time) { current->timeout = time + jiffies; time = 0; } else current->timeout = 0; minimum = 1; } } add_wait_queue(&tty->secondary.proc_list, &wait); while (1) { /* First test for status change. */ if (tty->packet && tty->link->ctrl_status) { if (b != buf) break; put_fs_byte(tty->link->ctrl_status, b++); tty->link->ctrl_status = 0; break; } /* This statement must be first before checking for input so that any interrupt will set the state back to TASK_RUNNING. */ current->state = TASK_INTERRUPTIBLE; if (!input_available_p(tty)) { if (tty->flags & (1 << TTY_SLAVE_CLOSED)) { retval = -EIO; break; } if (tty_hung_up_p(file)) break; if (!current->timeout) break; if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; break; } if (current->signal & ~current->blocked) { retval = -ERESTARTSYS; break; } schedule(); continue; } current->state = TASK_RUNNING; /* Deal with packet mode. */ if (tty->packet && b == buf) { put_fs_byte(TIOCPKT_DATA, b++); nr--; } while (1) { int eol; cli(); if (EMPTY(&tty->secondary)) { sti(); break; } eol = clear_bit(tty->secondary.tail, &tty->secondary_flags); c = tty->secondary.buf[tty->secondary.tail]; if (!nr) { /* Gobble up an immediately following EOF if there is no more room in buf (this can happen if the user "pushes" some characters using ^D). This prevents the next read() from falsely returning EOF. */ if (eol) { if (c == __DISABLED_CHAR) { tty->canon_data--; INC(tty->secondary.tail); } else { set_bit(tty->secondary.tail, &tty->secondary_flags); } } sti(); break; } INC(tty->secondary.tail); sti(); if (eol) { if (--tty->canon_data < 0) { printk("read_chan: canon_data < 0!\n"); tty->canon_data = 0; } if (c == __DISABLED_CHAR) break; put_fs_byte(c, b++); nr--; break; } put_fs_byte(c, b++); nr--; } /* If there is enough space in the secondary queue now, let the low-level driver know. */ if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW) && clear_bit(TTY_SQ_THROTTLED, &tty->flags)) tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL); if (b - buf >= minimum || !nr) break; if (time) current->timeout = time + jiffies; } remove_wait_queue(&tty->secondary.proc_list, &wait); current->state = TASK_RUNNING; current->timeout = 0; return (b - buf) ? b - buf : retval;}static int write_chan(struct tty_struct * tty, struct file * file, unsigned char * buf, unsigned int nr){ struct wait_queue wait = { current, NULL }; int c; unsigned char *b = buf; int retval = 0; /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) { retval = check_change(tty, tty->line); if (retval) return retval; } add_wait_queue(&tty->write_q.proc_list, &wait); while (1) { current->state = TASK_INTERRUPTIBLE; if (current->signal & ~current->blocked) { retval = -ERESTARTSYS; break; } if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) { retval = -EIO; break; } while (nr > 0) { c = get_fs_byte(b); /* Care is needed here: opost() can abort even if the write_q is not full. */ if (opost(c, tty) < 0) break; b++; nr--; } TTY_WRITE_FLUSH(tty); if (!nr) break; if (EMPTY(&tty->write_q) && !need_resched) continue; if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; break; } schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&tty->write_q.proc_list, &wait); return (b - buf) ? b - buf : retval;}static int tty_read(struct inode * inode, struct file * file, char * buf, int count){ int i, dev; struct tty_struct * tty; dev = file->f_rdev; if (MAJOR(dev) != TTY_MAJOR) { printk("tty_read: bad pseudo-major nr #%d\n", MAJOR(dev)); return -EINVAL; } dev = MINOR(dev); tty = TTY_TABLE(dev); if (!tty || (tty->flags & (1 << TTY_IO_ERROR))) return -EIO; /* This check not only needs to be done before reading, but also whenever read_chan() gets woken up after sleeping, so I've moved it to there. This should only be done for the N_TTY line discipline, anyway. Same goes for write_chan(). -- jlc. */#if 0 if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */ (tty->pgrp > 0) && (current->tty == dev) && (tty->pgrp != current->pgrp)) if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp)) return -EIO; else { (void) kill_pg(current->pgrp, SIGTTIN, 1); return -ERESTARTSYS; }#endif if (ldiscs[tty->disc].read) /* XXX casts are for what kernel-wide prototypes should be. */ i = (ldiscs[tty->disc].read)(tty,file,(unsigned char *)buf,(unsigned int)count); else i = -EIO; if (i > 0) inode->i_atime = CURRENT_TIME; return i;}static int tty_write(struct inode * inode, struct file * file, char * buf, int count){ int dev, i, is_console; struct tty_struct * tty; dev = file->f_rdev; is_console = (inode->i_rdev == CONSOLE_DEV); if (MAJOR(dev) != TTY_MAJOR) { printk("tty_write: pseudo-major != TTY_MAJOR\n"); return -EINVAL; } dev = MINOR(dev); if (is_console && redirect) tty = redirect; else tty = TTY_TABLE(dev); if (!tty || !tty->write || (tty->flags & (1 << TTY_IO_ERROR))) return -EIO;#if 0 if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) && (current->tty == dev) && (tty->pgrp != current->pgrp)) { if (is_orphaned_pgrp(current->pgrp)) return -EIO; if (!is_ignored(SIGTTOU)) { (void) kill_pg(current->pgrp, SIGTTOU, 1); return -ERESTARTSYS; } }#endif if (ldiscs[tty->disc].write) /* XXX casts are for what kernel-wide prototypes should be. */ i = (ldiscs[tty->disc].write)(tty,file,(unsigned char *)buf,(unsigned int)count); else i = -EIO; if (i > 0) inode->i_mtime = CURRENT_TIME; return i;}/* * This is so ripe with races that you should *really* not touch this * unless you know exactly what you are doing. All the changes have to be * made atomically, or there may be incorrect pointers all over the place. */static int init_dev(int dev){ struct tty_struct *tty, *o_tty; struct termios *tp, *o_tp, *ltp, *o_ltp; int retval; int o_dev; o_dev = PTY_OTHER(dev); tty = o_tty = NULL; tp = o_tp = NULL; ltp = o_ltp = NULL;repeat: retval = -EAGAIN; if (IS_A_PTY_MASTER(dev) && tty_table[dev] && tty_table[dev]->count) goto end_init; retval = -ENOMEM; if (!tty_table[dev] && !tty) { if (!(tty = (struct tty_struct*) get_free_page(GFP_KERNEL))) goto end_init; initialize_tty_struct(dev, tty); goto repeat; } if (!tty_termios[dev] && !tp) { tp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!tp) goto end_init; initialize_termios(dev, tp); goto repeat; } if (!termios_locked[dev] && !ltp) { ltp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!ltp) goto end_init; memset(ltp, 0, sizeof(struct termios)); goto repeat; } if (IS_A_PTY(dev)) { if (!tty_table[o_dev] && !o_tty) { o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL); if (!o_tty) goto end_init; initialize_tty_struct(o_dev, o_tty); goto repeat; } if (!tty_termios[o_dev] && !o_tp) { o_tp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!o_tp) goto end_init; initialize_termios(o_dev, o_tp); goto repeat; } if (!termios_locked[o_dev] && !o_ltp) { o_ltp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); if (!o_ltp) goto end_init; memset(o_ltp, 0, sizeof(struct termios)); goto repeat; } } /* Now we have allocated all the structures: update all the pointers.. */ if (!tty_termios[dev]) { tty_termios[dev] = tp; tp = NULL; } if (!tty_table[dev]) { tty->termios = tty_termios[dev]; tty_table[dev] = tty; tty = NULL; } if (!termios_locked[dev]) { termios_locked[dev] = ltp; ltp = NULL; } if (IS_A_PTY(dev)) { if (!tty_termios[o_dev]) { tty_termios[o_dev] = o_tp; o_tp = NULL; } if (!termios_locked[o_dev]) { termios_locked[o_dev] = o_ltp; o_ltp = NULL; } if (!tty_table[o_dev]) { o_tty->termios = tty_termios[o_dev]; tty_table[o_dev] = o_tty; o_tty = NULL; } tty_table[dev]->link = tty_table[o_dev]; tty_table[o_dev]->link = tty_table[dev]; } tty_table[dev]->count++; if (IS_A_PTY_MASTER(dev)) tty_table[o_dev]->count++; retval = 0;end_init: if (tty) free_page((unsigned long) tty); if (o_tty) free_page((unsigned long) o_tty); if (tp) kfree_s(tp, sizeof(struct termios)); if (o_tp) kfree_s(o_tp, sizeof(struct termios)); if (ltp) kfree_s(ltp, sizeof(struct termios)); if (o_ltp) kfree_s(o_ltp, sizeof(struct termios)); return retval;}/* * Even releasing the tty structures is a tricky business.. We have * to be very careful that the structures are all released at the * same time, as interrupts might otherwise get the wrong pointers. */static void release_dev(int dev, struct file * filp){ struct tty_struct *tty, *o_tty; struct termios *tp, *o_tp; struct task_struct **p; tty = tty_table[dev]; tp = tty_termios[dev]; o_tty = NULL; o_tp = NULL; if (!tty) { printk("release_dev: tty_table[%d] was NULL\n", dev); return; } if (!tp) { printk("release_dev: tty_termios[%d] was NULL\n", dev); return; }#ifdef TTY_DEBUG_HANGUP printk("release_dev of tty%d (tty count=%d)...", dev, tty->count);#endif if (IS_A_PTY(dev)) { o_tty = tty_table[PTY_OTHER(dev)]; o_tp = tty_termios[PTY_OTHER(dev)]; if (!o_tty) { printk("release_dev: pty pair(%d) was NULL\n", dev); return; } if (!o_tp) { printk("release_dev: pty pair(%d) termios was NULL\n", dev); return; } if (tty->link != o_tty || o_tty->link != tty) { printk("release_dev: bad pty pointers\n"); return;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -