标签: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; }
标签:long can sys call ble path hup disabled nbsp
原文地址:https://www.cnblogs.com/fluray/p/9226444.html