[Cbe-oss-dev] [PATCH 2/3] libspe2: (take2) Fix blocking in spe_in_mbox_write w/ SPE_MBOX_ANY_NONBLOCKING
Kazunori Asayama
asayama at sm.sony.co.jp
Mon Apr 16 17:58:37 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 use
appropriate blocking-mode for write() according to behavior flag,
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,6 +45,7 @@ static const struct fd_attr spe_fd_attr[
[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_NB] = { .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
@@ -61,84 +61,51 @@ int _base_spe_in_mbox_write(spe_context_
int count,
int behavior_flag)
{
- int rc, ret;
- int written, items;
- unsigned int * ptr;
+ int rc;
+ int total;
- 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;
+ total = rc = 0;
+ while (total < 4*count) {
+ rc = write(open_if_closed(spectx,FD_WBOX, 0),
+ (const char *)mbox_data + total, 4*count - total);
+ if (rc == -1) {
+ break;
}
- items = rc/4;
- count -= items;
- written += items;
- ptr += items;
+ total += rc;
}
- rc = written;
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;
+ total = rc = write(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;
+ rc = write(open_if_closed(spectx,FD_WBOX_NB, 0), mbox_data, 4*count);
+ if (rc == -1 && errno == EAGAIN) {
+ rc = 0;
+ errno = 0;
}
- _base_spe_context_unlock(spectx, FD_WBOX);
- rc = written;
+ total = rc;
break;
default:
errno = EINVAL;
- rc = -1;
+ return -1;
}
- return rc;
+ if (rc == -1) {
+ errno = EIO;
+ return -1;
+ }
+
+ return total / 4;
}
int _base_spe_in_mbox_status(spe_context_ptr_t spectx)
Index: libspe2-public/spebase/spebase.h
===================================================================
--- libspe2-public.orig/spebase/spebase.h
+++ libspe2-public/spebase/spebase.h
@@ -39,7 +39,20 @@ extern "C"
#endif
/** NOTE: NUM_MBOX_FDS must always be the last element in the enumeration */
-enum fd_name { FD_MBOX, FD_MBOX_STAT, FD_IBOX, FD_IBOX_STAT, FD_WBOX, FD_WBOX_STAT, FD_SIG1, FD_SIG2, FD_MFC, FD_MSS, NUM_MBOX_FDS };
+enum fd_name {
+ FD_MBOX,
+ FD_MBOX_STAT,
+ FD_IBOX,
+ FD_IBOX_STAT,
+ FD_WBOX,
+ FD_WBOX_NB,
+ FD_WBOX_STAT,
+ FD_SIG1,
+ FD_SIG2,
+ FD_MFC,
+ FD_MSS,
+ NUM_MBOX_FDS
+};
/*
* "Private" structure -- do no use, if you want to achieve binary compatibility
More information about the cbe-oss-dev
mailing list