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 |