Changeset View
Changeset View
Standalone View
Standalone View
sys/sys/tty.h
| Show All 30 Lines | |||||
| #ifndef _SYS_TTY_H_ | #ifndef _SYS_TTY_H_ | ||||
| #define _SYS_TTY_H_ | #define _SYS_TTY_H_ | ||||
| #include <sys/param.h> | #include <sys/param.h> | ||||
| #include <sys/queue.h> | #include <sys/queue.h> | ||||
| #include <sys/lock.h> | #include <sys/lock.h> | ||||
| #include <sys/mutex.h> | #include <sys/mutex.h> | ||||
| #include <sys/sx.h> | |||||
| #include <sys/condvar.h> | #include <sys/condvar.h> | ||||
| #include <sys/selinfo.h> | #include <sys/selinfo.h> | ||||
| #include <sys/_termios.h> | #include <sys/_termios.h> | ||||
| #include <sys/ttycom.h> | #include <sys/ttycom.h> | ||||
| #include <sys/ttyqueue.h> | #include <sys/ttyqueue.h> | ||||
| struct cdev; | struct cdev; | ||||
| struct file; | struct file; | ||||
| struct pgrp; | struct pgrp; | ||||
| struct session; | struct session; | ||||
| struct ucred; | struct ucred; | ||||
| struct ttydevsw; | struct ttydevsw; | ||||
| /* | /* | ||||
| * Per-TTY structure, containing buffers, etc. | * Per-TTY structure, containing buffers, etc. | ||||
| * | * | ||||
| * Under the new locking model, the ttylock is mostly internal to ^/sys/kern. | |||||
| * It must be acquired when calling tty_rel_gone(), but for the most part | |||||
| * drivers will not touch it. It is especially wrong for a driver to drop the | |||||
| * tty lock when entered via ttydevsw methods; it is sleepable so that drivers | |||||
| * do not need to drop it, keeping entry to tty methods from userland properly | |||||
| * blocked while the driver is operating. | |||||
| * | |||||
| * The lock that drivers may supply is now called the ttydisc lock, which | |||||
| * replaces most traditional usage of the ttylock in drivers. As the name | |||||
| * implies, it must be held when calling ttydisc_* methods. The exception is | |||||
| * when &Giant is passed to tty_alloc_mutex(); this is currently a special hack | |||||
| * put in place so that syscons can continue operating without the tty layer | |||||
| * attempting to acquire this sx before Giant. syscons will become properly | |||||
| * locked in due time, but this is a more complicated feat. | |||||
| * | |||||
| * List of locks | * List of locks | ||||
| * (t) locked by t_mtx | * (t) locked by ttylock | ||||
| * (d) locked by ttydisc lock | |||||
| * (l) locked by tty_list_sx | * (l) locked by tty_list_sx | ||||
| * (c) const until freeing | * (c) const until freeing | ||||
| * (d+t) both locks must be held to write | |||||
| * | |||||
| * (d*) locking for tf_flags is more complex. It is generally locked by the | |||||
| * ttydisc lock, but both locks must be held to mark some flags so that we | |||||
| * can do some unlocked reads safely with just one or the other. Those flags | |||||
| * are annotated with a (t) to indicate that they require the ttylock as well. | |||||
| */ | */ | ||||
| struct tty { | struct tty { | ||||
| struct mtx *t_mtx; /* TTY lock. */ | struct mtx *t_mtx; /* Deprecated TTY lock (Giant). */ | ||||
| struct mtx t_mtxobj; /* Per-TTY lock (when not borrowing). */ | struct sx t_sxobj; /* TTY lock (when not borrowing). */ | ||||
| struct mtx *t_discmtx; /* TTY discipline lock. */ | |||||
| /* Per-TTY discipline lock (when not borrowing). */ | |||||
| struct mtx t_discmtxobj; | |||||
| TAILQ_ENTRY(tty) t_list; /* (l) TTY list entry. */ | TAILQ_ENTRY(tty) t_list; /* (l) TTY list entry. */ | ||||
| int t_drainwait; /* (t) TIOCDRAIN timeout seconds. */ | int t_drainwait; /* (d) TIOCDRAIN timeout seconds. */ | ||||
| unsigned int t_flags; /* (t) Terminal option flags. */ | unsigned int t_flags; /* (d*) Terminal option flags. */ | ||||
| /* Keep flags in sync with db_show_tty and pstat(8). */ | /* Keep flags in sync with db_show_tty and pstat(8). */ | ||||
| #define TF_NOPREFIX 0x00001 /* Don't prepend "tty" to device name. */ | #define TF_NOPREFIX 0x00001 /* Don't prepend "tty" to device name. */ | ||||
| #define TF_INITLOCK 0x00002 /* Create init/lock state devices. */ | #define TF_INITLOCK 0x00002 /* Create init/lock state devices. */ | ||||
| #define TF_CALLOUT 0x00004 /* Create "cua" devices. */ | #define TF_CALLOUT 0x00004 /* Create "cua" devices. */ | ||||
| #define TF_OPENED_IN 0x00008 /* "tty" node is in use. */ | #define TF_OPENED_IN 0x00008 /* (t) "tty" node is in use. */ | ||||
| #define TF_OPENED_OUT 0x00010 /* "cua" node is in use. */ | #define TF_OPENED_OUT 0x00010 /* (t) "cua" node is in use. */ | ||||
| #define TF_OPENED_CONS 0x00020 /* Device in use as console. */ | #define TF_OPENED_CONS 0x00020 /* (t) Device in use as console. */ | ||||
| #define TF_OPENED (TF_OPENED_IN|TF_OPENED_OUT|TF_OPENED_CONS) | #define TF_OPENED (TF_OPENED_IN|TF_OPENED_OUT|TF_OPENED_CONS) | ||||
| #define TF_GONE 0x00040 /* Device node is gone. */ | #define TF_GONE 0x00040 /* (t) Device node is gone. */ | ||||
| #define TF_OPENCLOSE 0x00080 /* Device is in open()/close(). */ | #define TF_OPENCLOSE 0x00080 /* (t) Device is in open()/close(). */ | ||||
| #define TF_ASYNC 0x00100 /* Asynchronous I/O enabled. */ | #define TF_ASYNC 0x00100 /* (t) Asynchronous I/O enabled. */ | ||||
| #define TF_LITERAL 0x00200 /* Accept the next character literally. */ | #define TF_LITERAL 0x00200 /* Accept the next character literally. */ | ||||
| #define TF_HIWAT_IN 0x00400 /* We've reached the input watermark. */ | #define TF_HIWAT_IN 0x00400 /* We've reached the input watermark. */ | ||||
| #define TF_HIWAT_OUT 0x00800 /* We've reached the output watermark. */ | #define TF_HIWAT_OUT 0x00800 /* We've reached the output watermark. */ | ||||
| #define TF_HIWAT (TF_HIWAT_IN|TF_HIWAT_OUT) | #define TF_HIWAT (TF_HIWAT_IN|TF_HIWAT_OUT) | ||||
| #define TF_STOPPED 0x01000 /* Output flow control - stopped. */ | #define TF_STOPPED 0x01000 /* Output flow control - stopped. */ | ||||
| #define TF_EXCLUDE 0x02000 /* Exclusive access. */ | #define TF_EXCLUDE 0x02000 /* (t) Exclusive access. */ | ||||
| #define TF_BYPASS 0x04000 /* Optimized input path. */ | #define TF_BYPASS 0x04000 /* Optimized input path. */ | ||||
| #define TF_ZOMBIE 0x08000 /* Modem disconnect received. */ | #define TF_ZOMBIE 0x08000 /* Modem disconnect received. */ | ||||
| #define TF_HOOK 0x10000 /* TTY has hook attached. */ | #define TF_HOOK 0x10000 /* (t) TTY has hook attached. */ | ||||
| #define TF_BUSY_IN 0x20000 /* Process busy in read() -- not supported. */ | #define TF_BUSY_IN 0x20000 /* (t) Process busy in read(); not supported. */ | ||||
| #define TF_BUSY_OUT 0x40000 /* Process busy in write(). */ | #define TF_BUSY_OUT 0x40000 /* (Process busy in write(). */ | ||||
| #define TF_BUSY (TF_BUSY_IN|TF_BUSY_OUT) | #define TF_BUSY (TF_BUSY_IN|TF_BUSY_OUT) | ||||
| unsigned int t_revokecnt; /* (t) revoke() count. */ | unsigned int t_revokecnt; /* (d+t) revoke() count. */ | ||||
| /* Buffering mechanisms. */ | /* Buffering mechanisms. */ | ||||
| struct ttyinq t_inq; /* (t) Input queue. */ | struct ttyinq t_inq; /* (d) Input queue. */ | ||||
| size_t t_inlow; /* (t) Input low watermark. */ | size_t t_inlow; /* (d) Input low watermark. */ | ||||
| struct ttyoutq t_outq; /* (t) Output queue. */ | struct ttyoutq t_outq; /* (d) Output queue. */ | ||||
| size_t t_outlow; /* (t) Output low watermark. */ | size_t t_outlow; /* (d) Output low watermark. */ | ||||
| /* Sleeping mechanisms. */ | /* Sleeping mechanisms. */ | ||||
| struct cv t_inwait; /* (t) Input wait queue. */ | struct cv t_inwait; /* (d) Input wait queue. */ | ||||
| struct cv t_outwait; /* (t) Output wait queue. */ | struct cv t_outwait; /* (d) Output wait queue. */ | ||||
| struct cv t_outserwait; /* (t) Serial output wait queue. */ | struct cv t_outserwait; /* (d) Serial output wait queue. */ | ||||
| struct cv t_bgwait; /* (t) Background wait queue. */ | struct cv t_bgwait; /* (d) Background wait queue. */ | ||||
| struct cv t_dcdwait; /* (t) Carrier Detect wait queue. */ | struct cv t_dcdwait; /* (d) Carrier Detect wait queue. */ | ||||
| /* Polling mechanisms. */ | /* Polling mechanisms. */ | ||||
| struct selinfo t_inpoll; /* (t) Input poll queue. */ | struct selinfo t_inpoll; /* (t) Input poll queue. */ | ||||
| struct selinfo t_outpoll; /* (t) Output poll queue. */ | struct selinfo t_outpoll; /* (t) Output poll queue. */ | ||||
| struct sigio *t_sigio; /* (t) Asynchronous I/O. */ | struct sigio *t_sigio; /* (t) Asynchronous I/O. */ | ||||
| struct termios t_termios; /* (t) I/O processing flags. */ | struct termios t_termios; /* (d+t) I/O processing flags. */ | ||||
| struct winsize t_winsize; /* (t) Window size. */ | struct winsize t_winsize; /* (t) Window size. */ | ||||
| unsigned int t_column; /* (t) Current cursor position. */ | unsigned int t_column; /* (d) Current cursor position. */ | ||||
| unsigned int t_writepos; /* (t) Where input was interrupted. */ | unsigned int t_writepos; /* (d) Where input was interrupted. */ | ||||
| int t_compatflags; /* (t) COMPAT_43TTY flags. */ | int t_compatflags; /* (t) COMPAT_43TTY flags. */ | ||||
| /* Init/lock-state devices. */ | /* Init/lock-state devices. */ | ||||
| struct termios t_termios_init_in; /* tty%s.init. */ | struct termios t_termios_init_in; /* tty%s.init. */ | ||||
| struct termios t_termios_lock_in; /* tty%s.lock. */ | struct termios t_termios_lock_in; /* tty%s.lock. */ | ||||
| struct termios t_termios_init_out; /* cua%s.init. */ | struct termios t_termios_init_out; /* cua%s.init. */ | ||||
| struct termios t_termios_lock_out; /* cua%s.lock. */ | struct termios t_termios_lock_out; /* cua%s.lock. */ | ||||
| struct ttydevsw *t_devsw; /* (c) Driver hooks. */ | struct ttydevsw *t_devsw; /* (c) Driver hooks. */ | ||||
| struct ttyhook *t_hook; /* (t) Capture/inject hook. */ | struct ttyhook *t_hook; /* (t) Capture/inject hook. */ | ||||
| /* Process signal delivery. */ | /* Process signal delivery. */ | ||||
| struct pgrp *t_pgrp; /* (t) Foreground process group. */ | struct pgrp *t_pgrp; /* (d+t) Foreground process group. */ | ||||
| struct session *t_session; /* (t) Associated session. */ | struct session *t_session; /* (d+t) Associated session. */ | ||||
| unsigned int t_sessioncnt; /* (t) Backpointing sessions. */ | unsigned int t_sessioncnt; /* (d+t) Backpointing sessions. */ | ||||
| void *t_devswsoftc; /* (c) Soft config, for drivers. */ | void *t_devswsoftc; /* (c) Soft config, for drivers. */ | ||||
| void *t_hooksoftc; /* (t) Soft config, for hooks. */ | void *t_hooksoftc; /* (t) Soft config, for hooks. */ | ||||
| struct cdev *t_dev; /* (c) Primary character device. */ | struct cdev *t_dev; /* (c) Primary character device. */ | ||||
| size_t t_prbufsz; /* (t) SIGINFO buffer size. */ | size_t t_prbufsz; /* (d) SIGINFO buffer size. */ | ||||
| char t_prbuf[]; /* (t) SIGINFO buffer. */ | char t_prbuf[]; /* (d) SIGINFO buffer. */ | ||||
| }; | }; | ||||
| /* | /* | ||||
| * Userland version of struct tty, for sysctl kern.ttys | * Userland version of struct tty, for sysctl kern.ttys | ||||
| */ | */ | ||||
| struct xtty { | struct xtty { | ||||
| size_t xt_size; /* Structure size. */ | size_t xt_size; /* Structure size. */ | ||||
| size_t xt_insize; /* Input queue size. */ | size_t xt_insize; /* Input queue size. */ | ||||
| Show All 13 Lines | |||||
| #ifdef _KERNEL | #ifdef _KERNEL | ||||
| /* Used to distinguish between normal, callout, lock and init devices. */ | /* Used to distinguish between normal, callout, lock and init devices. */ | ||||
| #define TTYUNIT_INIT 0x1 | #define TTYUNIT_INIT 0x1 | ||||
| #define TTYUNIT_LOCK 0x2 | #define TTYUNIT_LOCK 0x2 | ||||
| #define TTYUNIT_CALLOUT 0x4 | #define TTYUNIT_CALLOUT 0x4 | ||||
| /* Allocation and deallocation. */ | /* Allocation and deallocation. */ | ||||
| /* | |||||
| * - tty_alloc: allocate a TTY with internal TTY/discipline locks | |||||
| * - tty_alloc_mutex: allocate a TTY with a given mutex as the ttydisc lock. | |||||
| * The exception is if the mutex specified is Giant, it will be used as | |||||
| * the TTY lock instead and an internal discipline lock will be allocated. | |||||
| */ | |||||
| struct tty *tty_alloc(struct ttydevsw *tsw, void *softc); | struct tty *tty_alloc(struct ttydevsw *tsw, void *softc); | ||||
| struct tty *tty_alloc_mutex(struct ttydevsw *tsw, void *softc, struct mtx *mtx); | struct tty *tty_alloc_mutex(struct ttydevsw *tsw, void *softc, struct mtx *mtx); | ||||
| void tty_rel_pgrp(struct tty *tp, struct pgrp *pgrp); | void tty_rel_pgrp(struct tty *tp, struct pgrp *pgrp); | ||||
| void tty_rel_sess(struct tty *tp, struct session *sess); | void tty_rel_sess(struct tty *tp, struct session *sess); | ||||
| void tty_rel_gone(struct tty *tp); | void tty_rel_gone(struct tty *tp); | ||||
| #define tty_lock(tp) mtx_lock((tp)->t_mtx) | /* | ||||
| #define tty_unlock(tp) mtx_unlock((tp)->t_mtx) | * These will get turned back into macros after the syscons/Giant locking | ||||
| #define tty_lock_owned(tp) mtx_owned((tp)->t_mtx) | * situation is resolved. For now, we have to support both kinds of tty lock | ||||
| #define tty_assert_locked(tp) mtx_assert((tp)->t_mtx, MA_OWNED) | * for this one case. | ||||
| #define tty_getlock(tp) ((tp)->t_mtx) | */ | ||||
| static __inline void | |||||
| _tty_lock(struct tty *tp) | |||||
| { | |||||
| /* XXX Should migrate users to tty_assert_locked! */ | if (tp->t_mtx != NULL) | ||||
| #define tty_lock_assert(tp, ma) mtx_assert((tp)->t_mtx, (ma)) | mtx_lock(tp->t_mtx); | ||||
| else | |||||
| sx_xlock(&tp->t_sxobj); | |||||
| } | |||||
| static __inline void | |||||
| _tty_unlock(struct tty *tp) | |||||
| { | |||||
| if (tp->t_mtx != NULL) | |||||
| mtx_unlock(tp->t_mtx); | |||||
| else | |||||
| sx_xunlock(&tp->t_sxobj); | |||||
| } | |||||
| static __inline int | |||||
| _tty_lock_owned(struct tty *tp) | |||||
| { | |||||
| if (tp->t_mtx != NULL) | |||||
| return (mtx_owned(tp->t_mtx)); | |||||
| else | |||||
| return (sx_xlocked(&tp->t_sxobj)); | |||||
| } | |||||
| #if defined(INVARIANTS) || defined(INVARIANTS_SUPPORT) | |||||
| /* XXX This should go away when the Giant special-case is removed. */ | |||||
| static __inline void | |||||
| tty_assert_locked(struct tty *tp) | |||||
| { | |||||
| if (tp->t_mtx != NULL) | |||||
| mtx_assert(tp->t_mtx, MA_OWNED); | |||||
| else | |||||
| sx_assert(&tp->t_sxobj, SA_XLOCKED); | |||||
| } | |||||
| #else | |||||
| #define tty_assert_locked(tp) | |||||
| #endif /* defined(INVARIANTS) || defined(INVARIANTS_SUPPORT */ | |||||
| #define tty_lock(tp) _tty_lock(tp) | |||||
| #define tty_unlock(tp) _tty_unlock(tp) | |||||
| #define tty_lock_owned(tp) _tty_lock_owned(tp) | |||||
| /* | |||||
| * XXX This one is technically wrong as long as syscons is still Giant-locked. | |||||
| * However, neither the internal tty infrastructure nor syscons will attempt to | |||||
| * tty_getlock, so we leave it as-is. | |||||
| */ | |||||
| #define tty_getlock(tp) (&(tp)->t_sxobj) | |||||
| #define ttydisc_lock(tp) mtx_lock((tp)->t_discmtx) | |||||
| #define ttydisc_unlock(tp) mtx_unlock((tp)->t_discmtx) | |||||
| #define ttydisc_lock_owned(tp) mtx_owned((tp)->t_discmtx) | |||||
| #define ttydisc_assert_locked(tp) mtx_assert((tp)->t_discmtx, MA_OWNED) | |||||
| #define ttydisc_assert_unlocked(tp) mtx_assert((tp)->t_discmtx, MA_NOTOWNED) | |||||
| #define ttydisc_getlock(tp) ((tp)->t_discmtx) | |||||
| /* Internal to tty, preferably... */ | |||||
| #define ttydisc_lock_assert(tp, ma) mtx_assert((tp)->t_discmtx, (ma)) | |||||
| /* Device node creation. */ | /* Device node creation. */ | ||||
| int tty_makedevf(struct tty *tp, struct ucred *cred, int flags, | int tty_makedevf(struct tty *tp, struct ucred *cred, int flags, | ||||
| const char *fmt, ...) __printflike(4, 5); | const char *fmt, ...) __printflike(4, 5); | ||||
| #define TTYMK_CLONING 0x1 | #define TTYMK_CLONING 0x1 | ||||
| #define tty_makedev(tp, cred, fmt, ...) \ | #define tty_makedev(tp, cred, fmt, ...) \ | ||||
| (void )tty_makedevf((tp), (cred), 0, (fmt), ## __VA_ARGS__) | (void )tty_makedevf((tp), (cred), 0, (fmt), ## __VA_ARGS__) | ||||
| #define tty_makealias(tp,fmt,...) \ | #define tty_makealias(tp,fmt,...) \ | ||||
| ▲ Show 20 Lines • Show All 49 Lines • Show Last 20 Lines | |||||