Просмотр исходного кода

Fix for bug 1023.
Fixes a problem where the dispatcher can lose track of available
events if it gets SA_ERR_TRY_AGAIN from the exec.


git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@883 fd59a12c-fef9-0310-b244-a6a79926bd2f

Mark Haverkamp 20 лет назад
Родитель
Сommit
b95a7a623d
1 измененных файлов с 69 добавлено и 38 удалено
  1. 69 38
      lib/evt.c

+ 69 - 38
lib/evt.c

@@ -113,6 +113,10 @@ struct handle_list {
  * ei_dispatch_mutex:	mutex for dispatch fd
  * ei_response_mutex:	mutex for response fd
  * ei_channel_list:		list of associated channels (struct handle_list)
+ * ei_data_available:	Indicates that there is a pending event message though
+ * 						there may not be a poll event.  This can happen
+ * 						when we get a SA_AIS_ERR_TRY_AGAIN when asking for an
+ * 						event.
  *
  */
 struct event_instance {
@@ -126,6 +130,7 @@ struct event_instance {
 	pthread_mutex_t			ei_dispatch_mutex;
 	pthread_mutex_t			ei_response_mutex;
 	struct list_head 		ei_channel_list;
+	int						ei_data_available;
 };
 
 
@@ -592,20 +597,11 @@ saEvtDispatch(
 
 		error = saPollRetry(&ufds, 1, timeout);
 		if (error != SA_AIS_OK) {
-			goto dispatch_unlock;
+			goto dispatch_put;
 		}
 
 		pthread_mutex_lock(&evti->ei_dispatch_mutex);
 
-		/*
-		 * Check the poll data in case the fd status has changed
-		 * since taking the lock
-		 */
-		error = saPollRetry(&ufds, 1, 0);
-		if (error != SA_AIS_OK) {
-			goto dispatch_unlock;
-		}
-
 		/*
 		 * Handle has been finalized in another thread
 		 */
@@ -614,41 +610,64 @@ saEvtDispatch(
 			goto dispatch_unlock;
 		}
 
-		if ((ufds.revents & (POLLERR|POLLHUP|POLLNVAL)) != 0) {
-			error = SA_AIS_ERR_BAD_HANDLE;
-			goto dispatch_unlock;
-		}
-
- 		dispatch_avail = ufds.revents & POLLIN;
-		if (dispatch_avail == 0 && 
-				(dispatchFlags == SA_DISPATCH_ALL || 
-				 dispatchFlags == SA_DISPATCH_ONE)) {
-			pthread_mutex_unlock(&evti->ei_dispatch_mutex);
-			break; /* exit do while cont is 1 loop */
-		} else if (dispatch_avail == 0) {
-			pthread_mutex_unlock(&evti->ei_dispatch_mutex);
-			continue; /* next poll */
-		}
-
- 		if (ufds.revents & POLLIN) {
- 			error = saRecvRetry (evti->ei_dispatch_fd, &dispatch_data.header,
- 				sizeof (struct res_header), MSG_WAITALL | MSG_NOSIGNAL);
-
+		/*
+		 * If we know that we have an event waiting, we can skip the
+		 * polling and just ask for it.
+		 */
+		if (!evti->ei_data_available) {
+			/*
+			 * Check the poll data in case the fd status has changed
+			 * since taking the lock
+			 */
+			error = saPollRetry(&ufds, 1, 0);
 			if (error != SA_AIS_OK) {
 				goto dispatch_unlock;
 			}
- 			if (dispatch_data.header.size > sizeof (struct res_header)) {
- 				error = saRecvRetry (evti->ei_dispatch_fd, &dispatch_data.data,
- 					dispatch_data.header.size - sizeof (struct res_header),
-  					MSG_WAITALL | MSG_NOSIGNAL);
+
+			if ((ufds.revents & (POLLERR|POLLHUP|POLLNVAL)) != 0) {
+				error = SA_AIS_ERR_BAD_HANDLE;
+				goto dispatch_unlock;
+			}
+
+			dispatch_avail = ufds.revents & POLLIN;
+			if (dispatch_avail == 0 &&
+					(dispatchFlags == SA_DISPATCH_ALL ||
+					 dispatchFlags == SA_DISPATCH_ONE)) {
+				pthread_mutex_unlock(&evti->ei_dispatch_mutex);
+				break; /* exit do while cont is 1 loop */
+			} else if (dispatch_avail == 0) {
+				pthread_mutex_unlock(&evti->ei_dispatch_mutex);
+				continue; /* next poll */
+			}
+
+			if (ufds.revents & POLLIN) {
+				error = saRecvRetry (evti->ei_dispatch_fd, &dispatch_data.header,
+					sizeof (struct res_header), MSG_WAITALL | MSG_NOSIGNAL);
+
 				if (error != SA_AIS_OK) {
 					goto dispatch_unlock;
 				}
-			} 
+				if (dispatch_data.header.size > sizeof (struct res_header)) {
+					error = saRecvRetry (evti->ei_dispatch_fd, &dispatch_data.data,
+						dispatch_data.header.size - sizeof (struct res_header),
+						MSG_WAITALL | MSG_NOSIGNAL);
+					if (error != SA_AIS_OK) {
+						goto dispatch_unlock;
+					}
+				}
+			} else {
+				pthread_mutex_unlock(&evti->ei_dispatch_mutex);
+				continue;
+			}
 		} else {
- 			pthread_mutex_unlock(&evti->ei_dispatch_mutex);
- 			continue;
+			/*
+			 * We know that we have an event available from before.
+			 * Fake up a header message and the switch statement will
+			 * take care of the rest.
+			 */
+			dispatch_data.header.id = MESSAGE_RES_EVT_AVAILABLE;
 		}
+
 		/*
 		 * Make copy of callbacks, message data, unlock instance, 
 		 * and call callback. A risk of this dispatch method is that 
@@ -665,6 +684,7 @@ saEvtDispatch(
 		switch (dispatch_data.header.id) {
 
 		case MESSAGE_RES_EVT_AVAILABLE:
+			evti->ei_data_available = 0;
 			/*
 			 * There are events available.  Send a request for one and then
 			 * dispatch it.
@@ -701,8 +721,19 @@ saEvtDispatch(
 
 			if (evt->led_head.error != SA_AIS_OK) {
 				error = evt->led_head.error;
-				printf("MESSAGE_RES_EVT_AVAILABLE: Error returned: %d\n", 
+
+				/*
+				 * If we get a try again response, we've lost the poll event
+				 * so we have a data available flag so that we know that there
+				 * really is an event waiting the next time dispatch gets
+				 * called.
+				 */
+				if (error == SA_AIS_ERR_TRY_AGAIN) {
+					evti->ei_data_available = 1;
+				} else {
+					printf("MESSAGE_RES_EVT_AVAILABLE: Error returned: %d\n",
 						error);
+				}
 				break;
 			}