This is take two of the previous patch which would spin on single CPUs
and fail to free resources.

Regards
-steve

Index: exec/ipc.c
===================================================================
--- exec/ipc.c	(revision 1733)
+++ exec/ipc.c	(working copy)
@@ -116,13 +116,21 @@
 };
 #endif
 
+enum conn_state {
+	CONN_STATE_THREAD_INACTIVE = 0,
+	CONN_STATE_THREAD_ACTIVE = 1,
+	CONN_STATE_THREAD_REQUEST_EXIT = 2,
+	CONN_STATE_THREAD_DESTROYED = 3,
+	CONN_STATE_LIB_EXIT_CALLED = 4,
+	CONN_STATE_DISCONNECT_INACTIVE = 5
+};
+
 struct conn_info {
 	int fd;
 	pthread_t thread;
 	pthread_attr_t thread_attr;
 	unsigned int service;
-	int destroyed;
-	int disconnect_requested;
+	enum conn_state state;
 	int notify_flow_control_enabled;
 	int refcount;
 	key_t shmkey;
@@ -148,44 +156,91 @@
 
 static void ipc_disconnect (struct conn_info *conn_info);
 
+static int ipc_thread_active (void *conn)
+{
+	struct conn_info *conn_info = (struct conn_info *)conn;
+	int retval = 0;
+
+	pthread_mutex_lock (&conn_info->mutex);
+	if (conn_info->state == CONN_STATE_THREAD_ACTIVE) {
+		retval = 1;
+	}
+	pthread_mutex_unlock (&conn_info->mutex);
+	return (retval);
+}
+
+static int ipc_thread_exiting (void *conn)
+{
+	struct conn_info *conn_info = (struct conn_info *)conn;
+	int retval = 1;
+
+	pthread_mutex_lock (&conn_info->mutex);
+	if (conn_info->state == CONN_STATE_THREAD_INACTIVE) {
+		retval = 0;
+	} else
+	if (conn_info->state == CONN_STATE_THREAD_ACTIVE) {
+		retval = 0;
+	}
+	pthread_mutex_unlock (&conn_info->mutex);
+	return (retval);
+}
+
+/*
+ * returns 0 if should be called again, -1 if finished
+ */
 static inline int conn_info_destroy (struct conn_info *conn_info)
 {
 	unsigned int res;
+	void *retval;
 
 	list_del (&conn_info->list);
 	list_init (&conn_info->list);
 
-	if (conn_info->service == SOCKET_SERVICE_INIT) {
+	if (conn_info->state == CONN_STATE_THREAD_REQUEST_EXIT) {
+		res = pthread_join (conn_info->thread, &retval);
+		conn_info->state = CONN_STATE_THREAD_DESTROYED;
+		return (0);
+	}
+
+	if (conn_info->state == CONN_STATE_THREAD_INACTIVE ||
+		conn_info->state == CONN_STATE_DISCONNECT_INACTIVE) {
 		list_del (&conn_info->list);
 		close (conn_info->fd);
 		free (conn_info);
+		return (-1);
+	}
+
+	if (conn_info->state == CONN_STATE_THREAD_ACTIVE) {
+		pthread_kill (conn_info->thread, SIGUSR1);
 		return (0);
 	}
+
 	/*
-	 * Destroy shared memory segment and semaphore
+	 * Retry library exit function if busy
 	 */
-	if (conn_info->destroyed == 0) {
-		openais_conn_refcount_dec (conn_info);
-		shmdt (conn_info->mem);
-		res = shmctl (conn_info->shmid, IPC_RMID, NULL);
-		semctl (conn_info->semid, 0, IPC_RMID);
-		conn_info->destroyed = 1;
+	if (conn_info->state == CONN_STATE_THREAD_DESTROYED) {
+		res = ais_service[conn_info->service]->lib_exit_fn (conn_info);
+		if (res == -1) {
+			return (0);
+		} else {
+			conn_info->state = CONN_STATE_LIB_EXIT_CALLED;
+		}
 	}
 
 	pthread_mutex_lock (&conn_info->mutex);
 	if (conn_info->refcount > 0) {
 		pthread_mutex_unlock (&conn_info->mutex);
-		return (-1);
+		return (0);
 	}
+	list_del (&conn_info->list);
 	pthread_mutex_unlock (&conn_info->mutex);
 
 	/*
-	 * Retry library exit function if busy
+	 * Destroy shared memory segment and semaphore
 	 */
-	res = ais_service[conn_info->service]->lib_exit_fn (conn_info);
-	if (res == -1) {
-		return (-1);
-	}
+	shmdt (conn_info->mem);
+	res = shmctl (conn_info->shmid, IPC_RMID, NULL);
+	semctl (conn_info->semid, 0, IPC_RMID);
 
 	/*
 	 * Free allocated data needed to retry exiting library IPC connection
@@ -194,9 +249,8 @@
 		free (conn_info->private_data);
 	}
 	close (conn_info->fd);
-	list_del (&conn_info->list);
 	free (conn_info);
-	return (0);
+	return (-1);
 }
 
 struct res_overlay {
@@ -250,18 +304,21 @@
 		sop.sem_op = -1;
 		sop.sem_flg = 0;
 retry_semop:
+		if (ipc_thread_active (conn_info) == 0) {
+			openais_conn_refcount_dec (conn_info);
+			pthread_exit (0);
+		}
 		res = semop (conn_info->semid, &sop, 1);
 		if ((res == -1) && (errno == EINTR || errno == EAGAIN)) {
 			goto retry_semop;
 		} else
 		if ((res == -1) && (errno == EINVAL || errno == EIDRM)) {
-			openais_conn_refcount_dec (conn);
-			return (0);
+			openais_conn_refcount_dec (conn_info);
+			pthread_exit (0);
 		}
-		if (conn_info->destroyed || conn_info->disconnect_requested) {
-			break;
-		}
 
+		openais_conn_refcount_inc (conn_info);
+
 		header = (mar_req_header_t *)conn_info->mem->req_buffer;
 
 		send_ok_joined_iovec.iov_base = (char *)header;
@@ -310,9 +367,9 @@
 			openais_response_send (conn_info, &res_overlay, 
 				res_overlay.header.size);
 		}
+		openais_conn_refcount_dec (conn);
 	}
-	openais_conn_refcount_dec (conn);
-	return (NULL);
+	pthread_exit (0);
 }
 
 static int
@@ -455,18 +512,6 @@
 	return (0);
 }
 
-static int poll_handler_connection_destroy(
-	struct conn_info *conn_info)
-{
-	int res;
-	res = conn_info_destroy (conn_info);
-	if (res == -1) {
-		return (0);
-	} else {
-		return (-1);
-	}
-}
-
 static int poll_handler_connection (
 	poll_handle handle,
 	int fd,
@@ -479,11 +524,16 @@
 	char buf;
 
 
+	if (ipc_thread_exiting (conn_info)) {
+		return conn_info_destroy (conn_info);
+	}
+
 	/*
-	 * If an error occurs, try to exit if possible
+	 * If an error occurs, request exit
 	 */
-	if ((conn_info->disconnect_requested) || (revent & (POLLERR|POLLHUP))) {
-		return poll_handler_connection_destroy (conn_info);
+	if (revent & (POLLERR|POLLHUP)) {
+		ipc_disconnect (conn_info);
+		return (0);
 	}
 
 	/*
@@ -509,8 +559,6 @@
 		conn_info->shmkey = req_setup->shmkey;
 		conn_info->semkey = req_setup->semkey;
 		conn_info->service = req_setup->service;
-		conn_info->destroyed = 0;
-		conn_info->disconnect_requested = 0;
 		conn_info->refcount = 0;
 		conn_info->notify_flow_control_enabled = 0;
 		conn_info->setup_bytes_read = 0;
@@ -520,9 +568,13 @@
 		conn_info->mem = shmat (conn_info->shmid, NULL, 0);
 		conn_info->semid = semget (conn_info->semkey, 3, 0600);
 		conn_info->pending_semops = 0;
-		conn_info->refcount = 1;
-		openais_conn_refcount_inc (conn_info);
 
+		/*
+		 * ipc thread is the only reference at startup
+		 */
+		conn_info->refcount = 1; 
+		conn_info->state = CONN_STATE_THREAD_ACTIVE;
+
 		conn_info->private_data = malloc (ais_service[conn_info->service]->private_data_size);
 		memset (conn_info->private_data, 0,
 			ais_service[conn_info->service]->private_data_size);
@@ -539,7 +591,7 @@
 		pthread_attr_setstacksize (&conn_info->thread_attr, 200000);
 		#endif
 
-		pthread_attr_setdetachstate (&conn_info->thread_attr, PTHREAD_CREATE_DETACHED);
+		pthread_attr_setdetachstate (&conn_info->thread_attr, PTHREAD_CREATE_JOINABLE);
 		res = pthread_create (&conn_info->thread,
 			&conn_info->thread_attr,
 			pthread_ipc_consumer,
@@ -554,6 +606,7 @@
 		}
 	} else
 	if (revent & POLLIN) {
+		openais_conn_refcount_inc (conn_info);
 		res = recv (fd, &buf, 1, MSG_NOSIGNAL);
 		if (res == 1) {
 			switch (buf) {
@@ -562,26 +615,29 @@
 				break;
 			case MESSAGE_REQ_CHANGE_EUID:
 				if (priv_change (conn_info) == -1) {
-					return poll_handler_connection_destroy (conn_info);
+					ipc_disconnect (conn_info);
 				}
 				break;
 			default:
 				res = 0;
 				break;
 			}
+			openais_conn_refcount_dec (conn_info);
 		}
 #if defined(OPENAIS_SOLARIS) || defined(OPENAIS_BSD) || defined(OPENAIS_DARWIN)
 		/* On many OS poll never return POLLHUP or POLLERR.
 		 * EOF is detected when recvmsg return 0.
 		 */
 		if (res == 0) {
-			return poll_handler_connection_destroy (conn_info);
+			ipc_disconnect (conn_info);
+			return (0);
 		}
 #endif
 	}
 
+	openais_conn_refcount_inc (conn_info);
 	pthread_mutex_lock (&conn_info->mutex);
-	if ((conn_info->disconnect_requested == 0) && (revent & POLLOUT)) {
+	if ((conn_info->state == CONN_STATE_THREAD_ACTIVE) && (revent & POLLOUT)) {
 		buf = !list_empty (&conn_info->outq_head);
 		for (; conn_info->pending_semops;) {
 			res = send (conn_info->fd, &buf, 1, MSG_NOSIGNAL);
@@ -607,19 +663,25 @@
 		}
 	}
 	pthread_mutex_unlock (&conn_info->mutex);
+	openais_conn_refcount_dec (conn_info);
 
 	return (0);
 }
 
 static void ipc_disconnect (struct conn_info *conn_info)
 {
+	if (conn_info->state == CONN_STATE_THREAD_INACTIVE) {
+		conn_info->state = CONN_STATE_DISCONNECT_INACTIVE;
+		return;
+	}
+	if (conn_info->state != CONN_STATE_THREAD_ACTIVE) {
+		return;
+	}
 	pthread_mutex_lock (&conn_info->mutex);
-	conn_info->disconnect_requested = 1;
+	conn_info->state = CONN_STATE_THREAD_REQUEST_EXIT;
 	pthread_mutex_unlock (&conn_info->mutex);
 
-	poll_dispatch_modify (aisexec_poll_handle,
-		conn_info->fd, POLLOUT|POLLNVAL,
-		poll_handler_connection);
+	pthread_kill (conn_info->thread, SIGUSR1);
 }
 
 static int conn_info_create (int fd)
@@ -634,6 +696,7 @@
 
 	conn_info->fd = fd;
 	conn_info->service = SOCKET_SERVICE_INIT;
+	conn_info->state = CONN_STATE_THREAD_INACTIVE;
 	list_init (&conn_info->outq_head);
 	list_init (&conn_info->list);
 	list_add (&conn_info->list, &conn_info_list_head);
@@ -802,7 +865,6 @@
 		shmdt (conn_info->mem);
 		shmctl (conn_info->shmid, IPC_RMID, NULL);
 		semctl (conn_info->semid, 0, IPC_RMID);
-		conn_info->destroyed = 1;
 	
 		pthread_kill (conn_info->thread, SIGUSR1);
 	}
@@ -1039,12 +1101,9 @@
 	/*
 	 * Exit transmission if the connection is dead
 	 */
-	pthread_mutex_lock (&conn_info->mutex);
-	if (conn_info->destroyed || conn_info->disconnect_requested) {
-		pthread_mutex_unlock (&conn_info->mutex);
+	if (ipc_thread_active (conn) == 0) {
 		return;
 	}
-	pthread_mutex_unlock (&conn_info->mutex);
 
 	bytes_left = shared_mem_dispatch_bytes_left (conn_info);
 	for (i = 0; i < iov_len; i++) {
_______________________________________________
Openais mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/openais

Reply via email to