⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tty_io.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 4 页
字号:
{	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 + -