[Cbe-oss-dev] [PATCH 2/3] libspe2: Fix blocking in spe_in_mbox_write w/ SPE_MBOX_ANY_NONBLOCKING

Kazunori Asayama asayama at sm.sony.co.jp
Fri Apr 13 14:23:05 EST 2007


The current implementation of spe_in_mbox_write in libspe2 has
possibility to be blocked even if SPE_MBOX_ANY_NONBLOCKING is passed
as behavior flag, when another thread calls spe_in_mbox_write with
SPE_MBOX_ALL_BLOCKING at the same time (*see the scenario below).

To solve this problem essentially and simply, I propose to wait for
the wbox FD by select() and perform non-blocking write(), instead of
checking the "wbox_stat" node.

Here is a patch to implement this solution.

----
(*) One possible scenario:

  1. Thread A calls _base_spe_in_mbox_write() with SPE_MBOX_ALL_BLOCKING
     behavior flag.
  2. Thread A calls and returns from open_if_closed() in
     _base_spe_in_mbox_write().
  3. Another thread B calls _base_spe_in_mbox_write() with
     SPE_MBOX_ANY_NONBLOCKING behavior flag.
  4. Thread B checks available space by reading
     FD_WBOX_STAT.
  5. Thread B decides to write to FD_WBOX.
  6. Thread A fills all available space of FD_WBOX by calling write().
  7. Thread B is blocked at write() system call !
----

Signed-off-by: Kazunori Asayama <asayama at sm.sony.co.jp>

Index: libspe2-public/spebase/create.c
===================================================================
--- libspe2-public.orig/spebase/create.c
+++ libspe2-public/spebase/create.c
@@ -45,7 +45,7 @@ static const struct fd_attr spe_fd_attr[
 	[FD_MBOX_STAT]	= { .name = "mbox_stat", .mode = O_RDONLY, },
 	[FD_IBOX]	= { .name = "ibox",      .mode = O_RDONLY, },
 	[FD_IBOX_STAT]	= { .name = "ibox_stat", .mode = O_RDONLY, },
-	[FD_WBOX]	= { .name = "wbox",      .mode = O_WRONLY, },
+	[FD_WBOX]	= { .name = "wbox",      .mode = O_WRONLY | O_NONBLOCK, },
 	[FD_WBOX_STAT]	= { .name = "wbox_stat", .mode = O_RDONLY, },
 	[FD_SIG1]	= { .name = "signal1",   .mode = O_RDWR, },
 	[FD_SIG2]	= { .name = "signal2",   .mode = O_RDWR, },
Index: libspe2-public/spebase/mbox.c
===================================================================
--- libspe2-public.orig/spebase/mbox.c
+++ libspe2-public/spebase/mbox.c
@@ -21,6 +21,7 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <sys/select.h>
 
 #include "create.h"
 #include "mbox.h"
@@ -31,6 +32,71 @@
  */
 
 
+static int write_immediate(int fd, const void *buf, size_t count)
+{
+	size_t total = 0;
+
+	while (total < count) {
+		/* Non-blocking mode is asssumed. */
+		int rc = write(fd, (const char *)buf + total, count - total);
+		if (rc == -1) {
+			if (errno == EAGAIN) {
+				break;
+			}
+			else {
+				return -1;
+			}
+		}
+		else if (rc == 0) {
+			break;
+		}
+		total += rc;
+	}
+
+	return total;
+}
+
+static int write_any(int fd, const void *buf, size_t count)
+{
+	while (count > 0) {
+		int rc;
+		fd_set fds;
+
+		FD_ZERO(&fds);
+		FD_SET(fd, &fds);
+
+		rc = select(fd + 1, NULL, &fds, NULL, NULL);
+		if (rc == -1) {
+			return -1;
+		}
+		else if (rc > 0) {
+			rc = write_immediate(fd, buf, count);
+			if (rc) return rc;
+		}
+	}
+
+	return 0;
+}
+
+static int write_all(int fd, const void *buf, size_t count)
+{
+	size_t total = 0;
+
+	while (total < count) {
+		int rc = write_any(fd, (const char *)buf + total, count - total);
+		if (rc == -1) {
+			return -1;
+		}
+		else if (rc == 0) {
+			break;
+		}
+		total += rc;
+	}
+
+	return total;
+}
+
+
 int _base_spe_out_mbox_read(spe_context_ptr_t spectx, 
                         unsigned int mbox_data[], 
                         int count)
@@ -54,84 +120,37 @@ int _base_spe_in_mbox_write(spe_context_
                         int count, 
                         int behavior_flag)
 {
-	int rc, ret;
-	int written, items;
-	unsigned int * ptr;
+	int rc;
 
-	ptr = mbox_data;
+	if (mbox_data == NULL || count < 1){
+		errno = EINVAL;
+		return -1;
+	}
 
 	switch (behavior_flag) {
 	case SPE_MBOX_ALL_BLOCKING: // write all, even if blocking
-		rc = 0;
-		written = 0;
-		while (count > 0) {
-			rc = write(open_if_closed(spectx,FD_WBOX, 0), ptr, 4*count);
-			DEBUG_PRINTF("%s write rc: %d\n", __FUNCTION__, rc);
-			if (rc == -1) {// something else went wrong
-				errno = EIO;
-				break; 
-			}
-			items   = rc/4; 
-			count   -= items;
-			written += items;
-			ptr     += items;
-		}
-		rc = written;
+		rc = write_all(open_if_closed(spectx,FD_WBOX, 0), mbox_data, 4*count);
 		break;
 
 	case  SPE_MBOX_ANY_BLOCKING: // write at least one, even if blocking
-		rc = 0;
-		written = 0;
-		_base_spe_context_lock(spectx, FD_WBOX);
-		while (count > 0) {
-			rc = write(open_if_closed(spectx,FD_WBOX, 1), ptr, 4*count);
-			DEBUG_PRINTF("%s write rc: %d\n", __FUNCTION__, rc);
-			if (rc == -1) {// something else went wrong
-				errno = EIO;
-				break; 
-			}
-			items   = rc/4; 
-			count   -= items;
-			written += items;
-			ptr     += items;
-			rc = read(open_if_closed(spectx,FD_WBOX_STAT, 0), &ret, 4);
-			DEBUG_PRINTF("%s stat ret: %d\n", __FUNCTION__, ret);
-			if (ret == 0) break; // no more space
-
-		}
-		_base_spe_context_unlock(spectx, FD_WBOX);
-		rc = written;
+		rc = write_any(open_if_closed(spectx,FD_WBOX, 0), mbox_data, 4*count);
 		break;
 
 	case  SPE_MBOX_ANY_NONBLOCKING: // only write, if non blocking
-		rc = 0;
-		written = 0;
-		_base_spe_context_lock(spectx, FD_WBOX);
-		while (count > 0) {
-			rc = read(open_if_closed(spectx,FD_WBOX_STAT, 0), &ret, 4*count);
-			DEBUG_PRINTF("%s stat ret: %d\n", __FUNCTION__, ret);
-			if (ret == 0) break; // no more space
-			rc = write(open_if_closed(spectx,FD_WBOX, 1), ptr, 4);
-			DEBUG_PRINTF("%s write rc: %d\n", __FUNCTION__, rc);
-			if (rc == -1) {// something else went wrong
-				errno = EIO;
-				break; 
-			}
-			items   = rc/4; 
-			count   -= items;
-			written += items;
-			ptr     += items;
-		}
-		_base_spe_context_unlock(spectx, FD_WBOX);
-		rc = written;
+		rc = write_immediate(open_if_closed(spectx,FD_WBOX, 0), mbox_data, 4*count);
 		break;
 
 	default:
 		errno = EINVAL;
-		rc = -1;
+		return -1;
 	}
 
-	return rc;
+	if (rc == -1) {
+		errno = EIO;
+		return -1;
+	}
+
+	return rc / 4;
 }
 
 int _base_spe_in_mbox_status(spe_context_ptr_t spectx)



More information about the cbe-oss-dev mailing list