码迷,mamicode.com
首页 > 其他好文 > 详细

tty

时间:2018-06-25 22:49:20      阅读:394      评论:0      收藏:0      [点我收藏+]

标签:long   can   sys   call   ble   path   hup   disabled   nbsp   

char *fgets(char *restrict s, int n, FILE *restrict f)
{
    char *p = s;
    unsigned char *z;
    size_t k;
    int c;

    FLOCK(f);

    if (n--<=1) {
        f->mode |= f->mode-1;
        FUNLOCK(f);
        if (n) return 0;
        *s = 0;
        return s;
    }

    while (n) {
        z = memchr(f->rpos, \n, f->rend - f->rpos);
        k = z ? z - f->rpos + 1 : f->rend - f->rpos;
        k = MIN(k, n);
        memcpy(p, f->rpos, k);
        f->rpos += k;
        p += k;
        n -= k;
        if (z || !n) break;
        if ((c = getc_unlocked(f)) < 0) {
            if (p==s || !feof(f)) s = 0;
            break;
        }
        n--;
        if ((*p++ = c) == \n) break;
    }
    if (s) *p = 0;

    FUNLOCK(f);

    return s;
}


#define getc_unlocked(f) \
    ( ((f)->rpos < (f)->rend) ? *(f)->rpos++ : __uflow((f)) )


/* This function assumes it will never be called if there is already
 * data buffered for reading. */

int __uflow(FILE *f)
{
    unsigned char c;
    if (!__toread(f) && f->read(f, &c, 1)==1) return c;
    return EOF;
}
static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
              char *fp, int count)
{
    struct n_tty_data *ldata = tty->disc_data;
    bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty));

    if (ldata->real_raw)
        n_tty_receive_buf_real_raw(tty, cp, fp, count);
    else if (ldata->raw || (L_EXTPROC(tty) && !preops))
        n_tty_receive_buf_raw(tty, cp, fp, count);
    else if (tty->closing && !L_EXTPROC(tty))
        n_tty_receive_buf_closing(tty, cp, fp, count);
    else {
        if (ldata->lnext) {
            char flag = TTY_NORMAL;

            if (fp)
                flag = *fp++;
            n_tty_receive_char_lnext(tty, *cp++, flag);
            count--;
        }

        if (!preops && !I_PARMRK(tty))
            n_tty_receive_buf_fast(tty, cp, fp, count);
        else
            n_tty_receive_buf_standard(tty, cp, fp, count);

        flush_echoes(tty);
        if (tty->ops->flush_chars)
            tty->ops->flush_chars(tty);
    }

    if (ldata->icanon && !L_EXTPROC(tty))
        return;

    /* publish read_head to consumer */
    smp_store_release(&ldata->commit_head, ldata->read_head);

//只要不为0 说明读的比不上写的
//生产者 消费者
    if (read_cnt(ldata)) {
        kill_fasync(&tty->fasync, SIGIO, POLL_IN);
        wake_up_interruptible_poll(&tty->read_wait, EPOLLIN);
    }
}


static void
n_tty_receive_buf_fast(struct tty_struct *tty, const unsigned char *cp,
               char *fp, int count)
{
    struct n_tty_data *ldata = tty->disc_data;
    char flag = TTY_NORMAL;

    while (count--) {
        if (fp)
            flag = *fp++;
        if (likely(flag == TTY_NORMAL)) {
            unsigned char c = *cp++;

            if (!test_bit(c, ldata->char_map))
                n_tty_receive_char_fast(tty, c);
            else if (n_tty_receive_char_special(tty, c) && count) {
                if (fp)
                    flag = *fp++;
                n_tty_receive_char_lnext(tty, *cp++, flag);
                count--;
            }
        } else
            n_tty_receive_char_flagged(tty, *cp++, flag);
    }
}


static inline void
n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c)
{
    struct n_tty_data *ldata = tty->disc_data;

    if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) {
        start_tty(tty);
        process_echoes(tty);
    }
    //走这个if
    if (L_ECHO(tty)) {
        finish_erasing(ldata);
        /* Record the column of first canon char. */
        if (ldata->canon_head == ldata->read_head)
            echo_set_canon_col(ldata);
        echo_char(c, tty);
        commit_echoes(tty);
    }
    put_tty_queue(c, ldata);
}

/**
 *    put_tty_queue        -    add character to tty
 *    @c: character
 *    @ldata: n_tty data
 *
 *    Add a character to the tty read_buf queue.
 *
 *    n_tty_receive_buf()/producer path:
 *        caller holds non-exclusive termios_rwsem
 */

static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
{
    *read_buf_addr(ldata, ldata->read_head) = c;
    ldata->read_head++;
}


//循环取
static inline unsigned char *read_buf_addr(struct n_tty_data *ldata, size_t i)
{
    return &ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)];
}


//是否是真正的消费者?

static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
             unsigned char __user *buf, size_t nr)
{
    struct n_tty_data *ldata = tty->disc_data;
    unsigned char __user *b = buf;
    DEFINE_WAIT_FUNC(wait, woken_wake_function);
    int c;
    int minimum, time;
    ssize_t retval = 0;
    long timeout;
    int packet;
    size_t tail;

    c = job_control(tty, file);
    if (c < 0)
        return c;

    /*
     *    Internal serialization of reads.
     */
    if (file->f_flags & O_NONBLOCK) {
        if (!mutex_trylock(&ldata->atomic_read_lock))
            return -EAGAIN;
    } else {
        if (mutex_lock_interruptible(&ldata->atomic_read_lock))
            return -ERESTARTSYS;
    }

    down_read(&tty->termios_rwsem);

    minimum = time = 0;
    timeout = MAX_SCHEDULE_TIMEOUT;
    if (!ldata->icanon) {
        minimum = MIN_CHAR(tty);
        if (minimum) {
            time = (HZ / 10) * TIME_CHAR(tty);
        } else {
            timeout = (HZ / 10) * TIME_CHAR(tty);
            minimum = 1;
        }
    }

    packet = tty->packet;
    tail = ldata->read_tail;

    add_wait_queue(&tty->read_wait, &wait);
    while (nr) {
        /* First test for status change. */
        if (packet && tty->link->ctrl_status) {
            unsigned char cs;
            if (b != buf)
                break;
            spin_lock_irq(&tty->link->ctrl_lock);
            cs = tty->link->ctrl_status;
            tty->link->ctrl_status = 0;
            spin_unlock_irq(&tty->link->ctrl_lock);
            if (put_user(cs, b)) {
                retval = -EFAULT;
                break;
            }
            b++;
            nr--;
            break;
        }

        if (!input_available_p(tty, 0)) {
            up_read(&tty->termios_rwsem);
            tty_buffer_flush_work(tty->port);
            down_read(&tty->termios_rwsem);
            if (!input_available_p(tty, 0)) {
                if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
                    retval = -EIO;
                    break;
                }
                if (tty_hung_up_p(file))
                    break;
                /*
                 * Abort readers for ttys which never actually
                 * get hung up.  See __tty_hangup().
                 */
                if (test_bit(TTY_HUPPING, &tty->flags))
                    break;
                if (!timeout)
                    break;
                if (file->f_flags & O_NONBLOCK) {
                    retval = -EAGAIN;
                    break;
                }
                if (signal_pending(current)) {
                    retval = -ERESTARTSYS;
                    break;
                }
                up_read(&tty->termios_rwsem);

                timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
                        timeout);

                down_read(&tty->termios_rwsem);
                continue;
            }
        }

        if (ldata->icanon && !L_EXTPROC(tty)) {
            retval = canon_copy_from_read_buf(tty, &b, &nr);
            if (retval)
                break;
        } else {
            int uncopied;

            /* Deal with packet mode. */
            if (packet && b == buf) {
                if (put_user(TIOCPKT_DATA, b)) {
                    retval = -EFAULT;
                    break;
                }
                b++;
                nr--;
            }

            uncopied = copy_from_read_buf(tty, &b, &nr);
            uncopied += copy_from_read_buf(tty, &b, &nr);
            if (uncopied) {
                retval = -EFAULT;
                break;
            }
        }

        n_tty_check_unthrottle(tty);

        if (b - buf >= minimum)
            break;
        if (time)
            timeout = time;
    }
    if (tail != ldata->read_tail)
        n_tty_kick_worker(tty);
    up_read(&tty->termios_rwsem);

    remove_wait_queue(&tty->read_wait, &wait);
    mutex_unlock(&ldata->atomic_read_lock);

    if (b - buf)
        retval = b - buf;

    return retval;
}



/**
 *    canon_copy_from_read_buf    -    copy read data in canonical mode
 *    @tty: terminal device
 *    @b: user data
 *    @nr: size of data
 *
 *    Helper function for n_tty_read.  It is only called when ICANON is on;
 *    it copies one line of input up to and including the line-delimiting
 *    character into the user-space buffer.
 *
 *    NB: When termios is changed from non-canonical to canonical mode and
 *    the read buffer contains data, n_tty_set_termios() simulates an EOF
 *    push (as if C-d were input) _without_ the DISABLED_CHAR in the buffer.
 *    This causes data already processed as input to be immediately available
 *    as input although a newline has not been received.
 *
 *    Called under the atomic_read_lock mutex
 *
 *    n_tty_read()/consumer path:
 *        caller holds non-exclusive termios_rwsem
 *        read_tail published
 */

static int canon_copy_from_read_buf(struct tty_struct *tty,
                    unsigned char __user **b,
                    size_t *nr)
{
    struct n_tty_data *ldata = tty->disc_data;
    size_t n, size, more, c;
    size_t eol;
    size_t tail;
    int ret, found = 0;

    /* N.B. avoid overrun if nr == 0 */
    if (!*nr)
        return 0;

    n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);

    tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
    size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);

    n_tty_trace("%s: nr:%zu tail:%zu n:%zu size:%zu\n",
            __func__, *nr, tail, n, size);

    eol = find_next_bit(ldata->read_flags, size, tail);
    more = n - (size - tail);
    if (eol == N_TTY_BUF_SIZE && more) {
        /* scan wrapped without finding set bit */
        eol = find_next_bit(ldata->read_flags, more, 0);
        found = eol != more;
    } else
        found = eol != size;

    n = eol - tail;
    if (n > N_TTY_BUF_SIZE)
        n += N_TTY_BUF_SIZE;
    c = n + found;

    if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) {
        c = min(*nr, c);
        n = c;
    }

    n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n",
            __func__, eol, found, n, c, tail, more);

    ret = tty_copy_to_user(tty, *b, tail, n);
    if (ret)
        return -EFAULT;
    *b += n;
    *nr -= n;

    if (found)
        clear_bit(eol, ldata->read_flags);
    smp_store_release(&ldata->read_tail, ldata->read_tail + c);

    if (found) {
        if (!ldata->push)
            ldata->line_start = ldata->read_tail;
        else
            ldata->push = 0;
        tty_audit_push();
    }
    return 0;
}

 

tty

标签:long   can   sys   call   ble   path   hup   disabled   nbsp   

原文地址:https://www.cnblogs.com/fluray/p/9226444.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!