1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*
* linux/kernel/chr_drv/pty.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
* pty.c
*
* This module exports the following pty function:
*
* int pty_open(struct tty_struct * tty, struct file * filp);
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/string.h>
#include <asm/system.h>
#include <asm/bitops.h>
#define MIN(a,b) ((a) < (b) ? (a) : (b))
static void pty_close(struct tty_struct * tty, struct file * filp)
{
if (!tty)
return;
if (IS_A_PTY_MASTER(tty->line)) {
if (tty->count > 1)
printk("master pty_close: count = %d!!\n", tty->count);
} else {
if (tty->count > 2)
return;
}
wake_up_interruptible(&tty->secondary.proc_list);
wake_up_interruptible(&tty->read_q.proc_list);
wake_up_interruptible(&tty->write_q.proc_list);
if (!tty->link)
return;
wake_up_interruptible(&tty->link->secondary.proc_list);
wake_up_interruptible(&tty->link->read_q.proc_list);
wake_up_interruptible(&tty->link->write_q.proc_list);
if (IS_A_PTY_MASTER(tty->line))
tty_hangup(tty->link);
else {
start_tty(tty);
set_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
}
}
static inline void pty_copy(struct tty_struct * from, struct tty_struct * to)
{
unsigned long count, n;
struct tty_queue *fq, *tq;
if (from->stopped || EMPTY(&from->write_q))
return;
fq = &from->write_q;
tq = &to->read_q;
count = MIN(CHARS(fq), LEFT(tq));
while (count) {
n = MIN(MIN(TTY_BUF_SIZE - fq->tail, TTY_BUF_SIZE - tq->head),
count);
memcpy(&tq->buf[tq->head], &fq->buf[fq->tail], n);
count -= n;
fq->tail = (fq->tail + n) & (TTY_BUF_SIZE - 1);
tq->head = (tq->head + n) & (TTY_BUF_SIZE - 1);
}
TTY_READ_FLUSH(to);
if (LEFT(fq) > WAKEUP_CHARS)
wake_up_interruptible(&fq->proc_list);
if (from->write_data_cnt) {
set_bit(from->line, &tty_check_write);
mark_bh(TTY_BH);
}
}
/*
* This routine gets called when tty_write has put something into
* the write_queue. It copies the input to the output-queue of its
* slave.
*/
static void pty_write(struct tty_struct * tty)
{
if (tty->link)
pty_copy(tty,tty->link);
}
int pty_open(struct tty_struct *tty, struct file * filp)
{
if (!tty || !tty->link)
return -ENODEV;
if (IS_A_PTY_SLAVE(tty->line))
clear_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
tty->write = tty->link->write = pty_write;
tty->close = tty->link->close = pty_close;
wake_up_interruptible(&tty->read_q.proc_list);
if (filp->f_flags & O_NDELAY)
return 0;
while (!tty->link->count && !(current->signal & ~current->blocked))
interruptible_sleep_on(&tty->link->read_q.proc_list);
if (!tty->link->count)
return -ERESTARTSYS;
return 0;
}