--- linux/kernel/sched.c.orig2 Mon May 10 12:53:58 1999 +++ linux/kernel/sched.c Mon May 10 13:09:27 1999 @@ -903,6 +903,8 @@ CHECK_MAGIC(curr->__magic); #endif p = curr->task; + if (p->state & TASK_EXCLUSIVE) + break; if (p->state & mode) { /* * We can drop the read-lock early if this @@ -917,6 +919,47 @@ } } wq_read_unlock(&q->lock); +out: + return; +} + +void __wake_up_exclusive(wait_queue_head_t *q, unsigned int mode) +{ + unsigned long flags; + struct list_head *tmp, *head; + wait_queue_t *curr; + struct task_struct *p; + + if (!q) + goto out; + + wq_write_lock_irqsave(&q->lock, flags); + +#if WAITQUEUE_DEBUG + CHECK_MAGIC_WQHEAD(q); +#endif + + head = &q->task_list; +#if WAITQUEUE_DEBUG + if (!head->next || !head->prev) + WQ_BUG(); +#endif + tmp = head->prev; + if (tmp != head) { + curr = list_entry(tmp, wait_queue_t, task_list); + +#if WAITQUEUE_DEBUG + CHECK_MAGIC(curr->__magic); +#endif + p = curr->task; + if (p->state & TASK_EXCLUSIVE) { + __remove_wait_queue(q, curr); + wq_write_unlock_irqrestore(&q->lock, flags); + wake_up_process(p); + goto out; + } + } + wq_write_unlock_irqrestore(&q->lock, flags); out: return; } --- linux/include/linux/sched.h.orig2 Mon May 10 12:52:58 1999 +++ linux/include/linux/sched.h Mon May 10 13:14:09 1999 @@ -79,6 +79,7 @@ #define TASK_ZOMBIE 4 #define TASK_STOPPED 8 #define TASK_SWAPPING 16 +#define TASK_EXCLUSIVE 32 /* * Scheduling policies @@ -465,6 +466,7 @@ #define CURRENT_TIME (xtime.tv_sec) extern void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode)); +extern void FASTCALL(__wake_up_exclusive(wait_queue_head_t *q, unsigned int mode)); extern void FASTCALL(sleep_on(wait_queue_head_t *q)); extern long FASTCALL(sleep_on_timeout(wait_queue_head_t *q, signed long timeout)); @@ -636,6 +638,16 @@ wq_write_lock_irqsave(&q->lock, flags); __add_wait_queue(q, wait); + wq_write_unlock_irqrestore(&q->lock, flags); +} + +extern inline void add_wait_queue_exclusive(wait_queue_head_t *q, + wait_queue_t * wait) +{ + unsigned long flags; + + wq_write_lock_irqsave(&q->lock, flags); + __add_wait_queue_tail(q, wait); wq_write_unlock_irqrestore(&q->lock, flags); } --- linux/include/linux/wait.h.orig2 Mon May 10 13:11:46 1999 +++ linux/include/linux/wait.h Mon May 10 13:12:57 1999 @@ -161,6 +161,23 @@ list_add(&new->task_list, &head->task_list); } +/* + * Used for wake-one threads: + */ +extern inline void __add_wait_queue_tail(wait_queue_head_t *head, + wait_queue_t *new) +{ +#if WAITQUEUE_DEBUG + if (!head || !new) + WQ_BUG(); + CHECK_MAGIC_WQHEAD(head); + CHECK_MAGIC(new->__magic); + if (!head->task_list.next || !head->task_list.prev) + WQ_BUG(); +#endif + list_add(&new->task_list, head->task_list.prev); +} + extern inline void __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old) { --- linux/include/net/tcp.h.orig2 Mon May 10 12:46:23 1999 +++ linux/include/net/tcp.h Mon May 10 13:13:37 1999 @@ -512,6 +512,7 @@ long timeout); extern struct sock * tcp_accept(struct sock *sk, int flags); extern unsigned int tcp_poll(struct file * file, struct socket *sock, struct poll_table_struct *wait); +extern void tcp_state_change(struct sock *sk); extern void tcp_write_space(struct sock *sk); extern int tcp_getsockopt(struct sock *sk, int level, --- linux/net/ipv4/tcp_ipv4.c.orig2 Mon May 10 12:41:24 1999 +++ linux/net/ipv4/tcp_ipv4.c Mon May 10 12:47:34 1999 @@ -1864,6 +1864,7 @@ tp->rcv_mss = 536; sk->write_space = tcp_write_space; + sk->state_change = tcp_state_change; /* Init SYN queue. */ tcp_synq_init(tp); --- linux/net/ipv4/tcp.c.orig2 Mon May 10 12:51:42 1999 +++ linux/net/ipv4/tcp.c Mon May 10 13:10:44 1999 @@ -604,6 +604,20 @@ } /* + * Socket state_change callback. + * This is the main point where we do wake-one decisions. + */ +void tcp_state_change(struct sock *sk) +{ + if(!sk->dead) { + if (sk->state == TCP_ESTABLISHED) + __wake_up_exclusive(sk->sleep, TASK_INTERRUPTIBLE); + else + wake_up_interruptible(sk->sleep); + } +} + +/* * Socket write_space callback. * This (or rather the sock_wake_async) should agree with poll. */ @@ -660,7 +674,7 @@ static int wait_for_tcp_connect(struct sock * sk, int flags) { struct task_struct *tsk = current; - struct wait_queue wait = { tsk, NULL }; + DECLARE_WAITQUEUE(wait, tsk); while((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) { if(sk->err) @@ -676,8 +690,8 @@ if(signal_pending(tsk)) return -ERESTARTSYS; - tsk->state = TASK_INTERRUPTIBLE; - add_wait_queue(sk->sleep, &wait); + tsk->state = TASK_EXCLUSIVE; + add_wait_queue_exclusive(sk->sleep, &wait); release_sock(sk); if (((1 << sk->state) & ~(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT)) && @@ -685,7 +699,6 @@ schedule(); tsk->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &wait); lock_sock(sk); } return 0; @@ -703,7 +716,7 @@ { release_sock(sk); if (!tcp_memory_free(sk)) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); sk->socket->flags &= ~SO_NOSPACE; add_wait_queue(sk->sleep, &wait); @@ -1117,7 +1130,7 @@ int len, int nonblock, int flags, int *addr_len) { struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); int copied = 0; u32 peek_seq; volatile u32 *seq; /* So gcc doesn't overoptimise */ @@ -1534,7 +1547,7 @@ if (timeout) { struct task_struct *tsk = current; - struct wait_queue wait = { tsk, NULL }; + DECLARE_WAITQUEUE(wait, current); add_wait_queue(sk->sleep, &wait); release_sock(sk); @@ -1570,7 +1583,7 @@ static struct open_request * wait_for_connect(struct sock * sk, struct open_request **pprev) { - struct wait_queue wait = { current, NULL }; + DECLARE_WAITQUEUE(wait, current); struct open_request *req; add_wait_queue(sk->sleep, &wait);