aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/tty_ldisc.h
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2013-04-16 06:15:50 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-05-20 15:30:32 -0400
commit4898e640caf03fdbaf2122d5a33949bf3e4a5b34 (patch)
tree180f6665f2cc00c5595d7e8329ca05e46cbf67f4 /include/linux/tty_ldisc.h
parent50539dd4f88e8a689a38c94337768fd7ff3fd326 (diff)
tty: Add timed, writer-prioritized rw semaphore
The semantics of a rw semaphore are almost ideally suited for tty line discipline lifetime management; multiple active threads obtain "references" (read locks) while performing i/o to prevent the loss or change of the current line discipline (write lock). Unfortunately, the existing rw_semaphore is ill-suited in other ways; 1) TIOCSETD ioctl (change line discipline) expects to return an error if the line discipline cannot be exclusively locked within 5 secs. Lock wait timeouts are not supported by rwsem. 2) A tty hangup is expected to halt and scrap pending i/o, so exclusive locking must be prioritized. Writer priority is not supported by rwsem. Add ld_semaphore which implements these requirements in a semantically similar way to rw_semaphore. Writer priority is handled by separate wait lists for readers and writers. Pending write waits are priortized before existing read waits and prevent further read locks. Wait timeouts are trivially added, but obviously change the lock semantics as lock attempts can fail (but only due to timeout). This implementation incorporates the write-lock stealing work of Michel Lespinasse <walken@google.com>. Cc: Michel Lespinasse <walken@google.com> Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include/linux/tty_ldisc.h')
-rw-r--r--include/linux/tty_ldisc.h46
1 files changed, 46 insertions, 0 deletions
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index 58390c73df8b..7b24bbd85ea8 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -110,6 +110,52 @@
110#include <linux/wait.h> 110#include <linux/wait.h>
111#include <linux/wait.h> 111#include <linux/wait.h>
112 112
113
114/*
115 * the semaphore definition
116 */
117struct ld_semaphore {
118 long count;
119 raw_spinlock_t wait_lock;
120 unsigned int wait_readers;
121 struct list_head read_wait;
122 struct list_head write_wait;
123#ifdef CONFIG_DEBUG_LOCK_ALLOC
124 struct lockdep_map dep_map;
125#endif
126};
127
128extern void __init_ldsem(struct ld_semaphore *sem, const char *name,
129 struct lock_class_key *key);
130
131#define init_ldsem(sem) \
132do { \
133 static struct lock_class_key __key; \
134 \
135 __init_ldsem((sem), #sem, &__key); \
136} while (0)
137
138
139extern int ldsem_down_read(struct ld_semaphore *sem, long timeout);
140extern int ldsem_down_read_trylock(struct ld_semaphore *sem);
141extern int ldsem_down_write(struct ld_semaphore *sem, long timeout);
142extern int ldsem_down_write_trylock(struct ld_semaphore *sem);
143extern void ldsem_up_read(struct ld_semaphore *sem);
144extern void ldsem_up_write(struct ld_semaphore *sem);
145
146#ifdef CONFIG_DEBUG_LOCK_ALLOC
147extern int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass,
148 long timeout);
149extern int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass,
150 long timeout);
151#else
152# define ldsem_down_read_nested(sem, subclass, timeout) \
153 ldsem_down_read(sem, timeout)
154# define ldsem_down_write_nested(sem, subclass, timeout) \
155 ldsem_down_write(sem, timeout)
156#endif
157
158
113struct tty_ldisc_ops { 159struct tty_ldisc_ops {
114 int magic; 160 int magic;
115 char *name; 161 char *name;