ソースを参照

- io_wait fixes:
- use the correct flags fo sigio_rt's sigio_band
- call handle_io for POLLERR & POLLHUP even if not specified among
the watched events
- tcp: - handle POLLERR & POLLHUP (same way as POLLIN)

Andrei Pelinescu-Onciul 18 年 前
コミット
503bc281c1
2 ファイル変更35 行追加17 行削除
  1. 29 16
      io_wait.h
  2. 6 1
      tcp_main.c

+ 29 - 16
io_wait.h

@@ -478,7 +478,7 @@ again_devpoll:
 check_io_again:
 		while(e->type && ((n=poll(&pf, 1, 0))>0) && 
 				(handle_io(e, pf.revents, idx)>0) &&
-				(pf.revents & e->events));
+				(pf.revents & (e->events|POLLERR|POLLHUP)));
 		if (unlikely(e->type && (n==-1))){
 			if (errno==EINTR) goto check_io_again;
 			LOG(L_ERR, "ERROR: io_watch_add: check_io poll: %s [%d]\n",
@@ -891,8 +891,8 @@ again:
 				 *  IO and the fd is still watched for the triggering event */
 				while(fm->type && 
 						(handle_io(fm, h->fd_array[r].revents, r) > 0) &&
-						repeat &&
-						(fm->events & h->fd_array[r].revents) );
+						repeat && ((fm->events|POLLERR|POLLHUP) &
+													h->fd_array[r].revents));
 			}
 		}
 error:
@@ -974,13 +974,14 @@ again:
 		}
 #endif
 		for (r=0; r<n; r++){
-			revents= (POLLIN & (!(h->ep_array[r].events & EPOLLIN)-1)) |
+			revents= (POLLIN & (!(h->ep_array[r].events & (EPOLLIN|EPOLLPRI))
+						-1)) |
 					 (POLLOUT & (!(h->ep_array[r].events & EPOLLOUT)-1)) |
 					 (POLLERR & (!(h->ep_array[r].events & EPOLLERR)-1)) |
 					 (POLLHUP & (!(h->ep_array[r].events & EPOLLHUP)-1));
 			if (likely(revents)){
 				fm=(struct fd_map*)h->ep_array[r].data.ptr;
-				while(fm->type && (fm->events & revents) && 
+				while(fm->type && ((fm->events|POLLERR|POLLHUP) & revents) && 
 						(handle_io(fm, revents, -1)>0) && repeat);
 			}else{
 				LOG(L_ERR, "ERROR:io_wait_loop_epoll: unexpected event %x"
@@ -1122,6 +1123,17 @@ again:
 			if (fm->type)
 				handle_io(fm, POLLIN|POLLOUT, -1);
 		}else{
+			/* si_code contains the SIGPOLL reason: POLL_IN, POLL_OUT,
+			 *  POLL_MSG, POLL_ERR, POLL_PRI or POLL_HUP
+			 * and si_band the translated poll event bitmap:
+			 *  POLLIN|POLLRDNORM  (=POLL_IN),
+			 *  POLLOUT|POLLWRNORM|POLLWRBAND (=POLL_OUT),
+			 *  POLLIN|POLLRDNORM|POLLMSG (=POLL_MSG),
+			 *  POLLERR (=POLL_ERR),
+			 *  POLLPRI|POLLRDBAND (=POLL_PRI),
+			 *  POLLHUP|POLLERR (=POLL_HUP) 
+			 *  [linux 2.6.22 fs/fcntl.c:447]
+			 */
 #ifdef EXTRA_DEBUG
 			DBG("io_wait_loop_sigio_rt: siginfo: signal=%d (%d),"
 					" si_code=%d, si_band=0x%x,"
@@ -1131,23 +1143,24 @@ again:
 					sigio_fd);
 #endif
 			/* on some errors (e.g. when receving TCP RST), sigio_band will
-			 * be set to 0x08 (undocumented, no corresp. POLL_xx), so better
-			 * catch all events --andrei */
-			if (likely(sigio_band)/*&(POLL_IN|POLL_ERR|POLL_HUP)*/){
+			 * be set to 0x08 (POLLERR) or 0x18 (POLLERR|POLLHUP - on stream
+			 *  unix socket close) , so better catch all events --andrei */
+			if (likely(sigio_band)){
 				fm=get_fd_map(h, sigio_fd);
-				revents=(POLLIN & (!(sigio_band & POLL_IN)-1)) |
-						(POLLOUT & (!(sigio_band & POLL_OUT)-1)) |
-						(POLLERR & (!(sigio_band & POLL_ERR)-1)) |
-						(POLLHUP & (!(sigio_band & POLL_HUP)-1));
+				revents=sigio_band;
+				/* fix revents==POLLPRI case */
+				revents |= (!(revents & POLLPRI)-1) & POLLIN;
 				/* we can have queued signals generated by fds not watched
 			 	 * any more, or by fds in transition, to a child 
 				 * => ignore them */
-				if (fm->type && (fm->events & revents))
+				if (fm->type && ((fm->events|POLLERR|POLLHUP) & revents))
 					handle_io(fm, revents, -1);
 				else
-					LOG(L_ERR, "WARNING: io_wait_loop_sigio_rt: ignoring event"
-							" %x on fd %d (fm->fd=%d, fm->data=%p)\n",
-							sigio_band, sigio_fd, fm->fd, fm->data);
+					DBG("WARNING: io_wait_loop_sigio_rt: ignoring event"
+							" %x on fd %d, watching for %x, si_code=%x "
+							"(fm->type=%d, fm->fd=%d, fm->data=%p)\n",
+							sigio_band, sigio_fd, fm->events, siginfo.si_code,
+							fm->type, fm->fd, fm->data);
 			}else{
 				LOG(L_ERR, "ERROR: io_wait_loop_sigio_rt: unexpected event"
 							" on fd %d: %x\n", sigio_fd, sigio_band);

+ 6 - 1
tcp_main.c

@@ -2523,8 +2523,13 @@ inline static int handle_tcpconn_ev(struct tcp_connection* tcpconn, short ev,
 					goto error;
 			}
 		}
+		ev&=~POLLOUT; /* clear POLLOUT */
 	}
-	if (likely((ev & POLLIN) && !(tcpconn->flags & F_CONN_REMOVED))){
+	if (likely(ev && !(tcpconn->flags & F_CONN_REMOVED))){
+		/* if still some other IO event (POLLIN|POLLHUP|POLLERR) and
+		 * connection is still watched in tcp_main for reads, send it to a
+		 * child and stop watching it for input (but continue watching for
+		 *  writes if needed): */
 		if (unlikely(tcpconn->flags & F_CONN_WRITE_W)){
 			if (unlikely(io_watch_chg(&io_h, tcpconn->s, POLLOUT, fd_i)==-1))
 				goto error;