[PATCH] : ir258_wait_event_fixes-2.diff

From: Jean Tourrilhes (jt@bougret.hpl.hp.com)
Date: Thu Apr 18 2002 - 21:29:39 EST


ir258_wait_event_fixes-2.diff :
-----------------------------
                <Following patch from Martin Diehl, mangled by me>
        o [FEATURE] Replace interruptible_sleep_on() with wait_event().
                Most races were taken care off, but cleaner anyway

--------------------------------------------

diff -u -p linux/net/irda/ircomm/ircomm_tty.d7.c linux/net/irda/ircomm/ircomm_tty.c
--- linux/net/irda/ircomm/ircomm_tty.d7.c Wed Apr 10 16:44:12 2002
+++ linux/net/irda/ircomm/ircomm_tty.c Wed Apr 10 16:44:40 2002
@@ -453,8 +453,21 @@ static int ircomm_tty_open(struct tty_st
          */
         if (tty_hung_up_p(filp) ||
             (self->flags & ASYNC_CLOSING)) {
- if (self->flags & ASYNC_CLOSING)
- interruptible_sleep_on(&self->close_wait);
+
+ /* Hm, why are we blocking on ASYNC_CLOSING if we
+ * do return -EAGAIN/-ERESTARTSYS below anyway?
+ * IMHO it's either not needed in the first place
+ * or for some reason we need to make sure the async
+ * closing has been finished - if so, wouldn't we
+ * probably better sleep uninterruptible?
+ */
+
+ if (wait_event_interruptible(self->close_wait, !(self->flags&ASYNC_CLOSING))) {
+ WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
+ __FUNCTION__);
+ return -ERESTARTSYS;
+ }
+
                 /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
 #ifdef SERIAL_DO_RESTART
                 return ((self->flags & ASYNC_HUP_NOTIFY) ?
diff -u -p linux/net/irda/af_irda.d7.c linux/net/irda/af_irda.c
--- linux/net/irda/af_irda.d7.c Wed Apr 10 16:44:21 2002
+++ linux/net/irda/af_irda.c Fri Apr 12 16:25:19 2002
@@ -568,15 +568,17 @@ static int irda_find_lsap_sel(struct ird
         if(self->iriap == NULL)
                 return -ENOMEM;
 
- /* Treat unexpected signals as disconnect */
+ /* Treat unexpected wakeup as disconnect */
         self->errno = -EHOSTUNREACH;
 
         /* Query remote LM-IAS */
         iriap_getvaluebyclass_request(self->iriap, self->saddr, self->daddr,
                                       name, "IrDA:TinyTP:LsapSel");
- /* Wait for answer (if not already failed) */
- if(self->iriap != NULL)
- interruptible_sleep_on(&self->query_wait);
+
+ /* Wait for answer, if not yet finished (or failed) */
+ if (wait_event_interruptible(self->query_wait, (self->iriap==NULL)))
+ /* Treat signals as disconnect */
+ return -EHOSTUNREACH;
 
         /* Check what happened */
         if (self->errno)
@@ -877,16 +879,47 @@ static int irda_accept(struct socket *so
          * The read queue this time is holding sockets ready to use
          * hooked into the SABM we saved
          */
- do {
- if ((skb = skb_dequeue(&sk->receive_queue)) == NULL) {
- if (flags & O_NONBLOCK)
- return -EWOULDBLOCK;
 
- interruptible_sleep_on(sk->sleep);
- if (signal_pending(current))
- return -ERESTARTSYS;
+ /*
+ * We can perform the accept only if there is incomming data
+ * on the listening socket.
+ * So, we will block the caller until we receive any data.
+ * If the caller was waiting on select() or poll() before
+ * calling us, the data is waiting for us ;-)
+ * Jean II
+ */
+ skb = skb_dequeue(&sk->receive_queue);
+ if (skb == NULL) {
+ int ret = 0;
+ DECLARE_WAITQUEUE(waitq, current);
+
+ /* Non blocking operation */
+ if (flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+
+ /* The following code is a cut'n'paste of the
+ * wait_event_interruptible() macro.
+ * We don't us the macro because the condition has
+ * side effects : we want to make sure that only one
+ * skb get dequeued - Jean II */
+ add_wait_queue(sk->sleep, &waitq);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ skb = skb_dequeue(&sk->receive_queue);
+ if (skb != NULL)
+ break;
+ if (!signal_pending(current)) {
+ schedule();
+ continue;
+ }
+ ret = -ERESTARTSYS;
+ break;
                 }
- } while (skb == NULL);
+ current->state = TASK_RUNNING;
+ remove_wait_queue(sk->sleep, &waitq);
+ if(ret)
+ return -ERESTARTSYS;
+ }
 
          newsk = newsock->sk;
         newsk->state = TCP_ESTABLISHED;
@@ -1024,19 +1057,9 @@ static int irda_connect(struct socket *s
         if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK))
                 return -EINPROGRESS;
 
- /* Here, there is a race condition : the state may change between
- * our test and the sleep, via irda_connect_confirm().
- * The way to workaround that is to sleep with a timeout, so that
- * we don't sleep forever and check the state when waking up.
- * 50ms is plenty good enough, because the LAP is already connected.
- * Jean II */
- while (sk->state == TCP_SYN_SENT) {
- interruptible_sleep_on_timeout(sk->sleep, HZ/20);
- if (signal_pending(current)) {
- return -ERESTARTSYS;
- }
- }
-
+ if (wait_event_interruptible(*(sk->sleep), (sk->state!=TCP_SYN_SENT)))
+ return -ERESTARTSYS;
+
         if (sk->state != TCP_ESTABLISHED) {
                 sock->state = SS_UNCONNECTED;
                 return sock_error(sk); /* Always set at this point */
@@ -1280,17 +1303,14 @@ static int irda_sendmsg(struct socket *s
         ASSERT(self != NULL, return -1;);
 
         /* Check if IrTTP is wants us to slow down */
- while (self->tx_flow == FLOW_STOP) {
- IRDA_DEBUG(2, __FUNCTION__ "(), IrTTP is busy, going to sleep!\n");
- interruptible_sleep_on(sk->sleep);
-
- /* Check if we are still connected */
- if (sk->state != TCP_ESTABLISHED)
- return -ENOTCONN;
- /* Handle signals */
- if (signal_pending(current))
- return -ERESTARTSYS;
- }
+
+ if (wait_event_interruptible(*(sk->sleep),
+ (self->tx_flow != FLOW_STOP || sk->state != TCP_ESTABLISHED)))
+ return -ERESTARTSYS;
+
+ /* Check if we are still connected */
+ if (sk->state != TCP_ESTABLISHED)
+ return -ENOTCONN;
 
         /* Check that we don't send out to big frames */
         if (len > self->max_data_size) {
@@ -1382,14 +1402,23 @@ static int irda_recvmsg_dgram(struct soc
  *
  * Sleep until data has arrive. But check for races..
  *
+ * The caller is expected to deal with the situation when we return
+ * due to pending signals. And even if not, the peeked skb might have
+ * been already dequeued due to concurrent operation.
+ * Currently irda_recvmsg_stream() is the only caller and is ok.
+ * Return 0 if condition packet has arrived, -ERESTARTSYS if signal_pending()
+ * Only used once in irda_recvmsg_stream() -> inline
  */
-static void irda_data_wait(struct sock *sk)
+static inline int irda_data_wait(struct sock *sk)
 {
+ int ret = 0;
         if (!skb_peek(&sk->receive_queue)) {
                 set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
- interruptible_sleep_on(sk->sleep);
+ __wait_event_interruptible(*(sk->sleep),
+ (skb_peek(&sk->receive_queue)!=NULL), ret);
                 clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags);
         }
+ return(ret);
 }
 
 /*
@@ -1444,8 +1473,8 @@ static int irda_recvmsg_stream(struct so
 
                         if (noblock)
                                 return -EAGAIN;
- irda_data_wait(sk);
- if (signal_pending(current))
+ /* Wait process until data arrives */
+ if (irda_data_wait(sk))
                                 return -ERESTARTSYS;
                         continue;
                 }
@@ -2281,7 +2310,12 @@ bed:
                 self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
                                          irda_getvalue_confirm);
 
- /* Treat unexpected signals as disconnect */
+ if (self->iriap == NULL) {
+ kfree(ias_opt);
+ return -ENOMEM;
+ }
+
+ /* Treat unexpected wakeup as disconnect */
                 self->errno = -EHOSTUNREACH;
 
                 /* Query remote LM-IAS */
@@ -2289,9 +2323,17 @@ bed:
                                               self->saddr, daddr,
                                               ias_opt->irda_class_name,
                                               ias_opt->irda_attrib_name);
- /* Wait for answer (if not already failed) */
- if(self->iriap != NULL)
- interruptible_sleep_on(&self->query_wait);
+
+ /* Wait for answer, if not yet finished (or failed) */
+ if (wait_event_interruptible(self->query_wait,
+ (self->iriap == NULL))) {
+ /* pending request uses copy of ias_opt-content
+ * we can free it regardless! */
+ kfree(ias_opt);
+ /* Treat signals as disconnect */
+ return -EHOSTUNREACH;
+ }
+
                 /* Check what happened */
                 if (self->errno)
                 {
@@ -2348,12 +2390,14 @@ bed:
                 irlmp_update_client(self->ckey, self->mask,
                                     irda_selective_discovery_indication,
                                     NULL, (void *) self);
-
+
                 /* Do some discovery (and also return cached results) */
                 irlmp_discovery_request(self->nslots);
-
+
                 /* Wait until a node is discovered */
                 if (!self->cachediscovery) {
+ int ret = 0;
+
                         IRDA_DEBUG(1, __FUNCTION__
                                    "(), nothing discovered yet, going to sleep...\n");
 
@@ -2362,9 +2406,12 @@ bed:
                         self->watchdog.data = (unsigned long) self;
                         self->watchdog.expires = jiffies + (val * HZ/1000);
                         add_timer(&(self->watchdog));
+ self->errno = 0;
 
                         /* Wait for IR-LMP to call us back */
- interruptible_sleep_on(&self->query_wait);
+ __wait_event_interruptible(self->query_wait,
+ (self->cachediscovery!=NULL || self->errno==-ETIME),
+ ret);
 
                         /* If watchdog is still activated, kill it! */
                         if(timer_pending(&(self->watchdog)))
@@ -2372,6 +2419,9 @@ bed:
 
                         IRDA_DEBUG(1, __FUNCTION__
                                    "(), ...waking up !\n");
+
+ if (ret != 0)
+ return ret;
                 }
                 else
                         IRDA_DEBUG(1, __FUNCTION__
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Tue Apr 23 2002 - 22:00:23 EST