[Cbe-oss-dev] [PATCH 2/2] libspe: fix unexpected blocking in spe_get_event
Kazunori Asayama
asayama at sm.sony.co.jp
Tue Mar 28 23:27:40 EST 2006
This patch fixes following problems of libspe v1.0.1.
Two programs to reproduce these problems are also attached.
1. spe_get_event() causes unexpected blocking when:
- size of array of `struct spe_event' is greater than 1,
- there are two or more elements in the array
which have the same values in `events' fields and in `gid' fields, and,
- no event is buffered when the function is called,
and then an event becomes available.
e.g.)
spe_gid_t gid;
struct spe_event events[2];
.......
events[0].gid = gid;
events[0].events = SPE_EVENT_STOP | SPE_EVENT_THREAD_EXIT;
events[1].gid = gid;
events[1].events = SPE_EVENT_STOP | SPE_EVENT_THREAD_EXIT;
spe_get_event(&events, 2, -1);
2. spe_get_event() loses events when:
- two or more types of events are specified in `events' field of
`struct spe_event', and,
- no event is buffered when the function is called,
and then two or more events become available at the almost same time.
e.g.)
- PPU
spe_gid_t gid;
struct spe_event event;
.......
event.gid = gid;
event.events = SPE_EVENT_MAILBOX | SPE_EVENT_STOP | SPE_EVENT_THREAD_EXIT;
spe_get_event(&event, 1, -1);
- SPU
int main()
{
spu_writech(SPU_WrOutIntrMbox, 0);
spu_stop(0x1000);
return 0;
}
--
(ASAYAMA Kazunori
(asayama at sm.sony.co.jp))
t
--
diff -urp libspe-1.0.1.orig/spe.c libspe-1.0.1-a/spe.c
--- libspe-1.0.1.orig/spe.c 2006-03-27 20:23:32.000000000 +0900
+++ libspe-1.0.1-a/spe.c 2006-03-28 12:31:38.000000000 +0900
@@ -1116,6 +1116,21 @@ spe_kill (speid_t speid, int sig)
return rc;
}
+struct poll_helper {
+ int event;
+ struct thread_store *thread;
+ int type;
+ struct pollfd *pollfd;
+};
+
+static int
+qsort_compare_poll_helper(const void *p1, const void *p2)
+{
+ const struct poll_helper *e1 = p1;
+ const struct poll_helper *e2 = p2;
+ return e1->pollfd->fd - e2->pollfd->fd;
+}
+
int
spe_get_event(struct spe_event *pevents, int nevents, int timeout)
{
@@ -1124,15 +1139,10 @@ spe_get_event(struct spe_event *pevents,
int numSPEsToPoll = 0;
int setupSPEs =0;
int pollRet = 0;
+ int lastSPEfd;
struct pollfd *SPEfds;
- struct poll_helper {
- int event;
- struct thread_store *thread;
- int type;
- };
-
struct poll_helper *phelper;
pthread_mutex_lock(&grp_list.mutex);
@@ -1243,6 +1253,7 @@ spe_get_event(struct spe_event *pevents,
phelper[setupSPEs].event=i;
phelper[setupSPEs].thread=thread;
+ phelper[setupSPEs].pollfd=SPEfds + setupSPEs;
phelper[setupSPEs].type=1;
//printf("1\n");
setupSPEs++;
@@ -1256,6 +1267,7 @@ spe_get_event(struct spe_event *pevents,
phelper[setupSPEs].event=i;
phelper[setupSPEs].thread=thread;
+ phelper[setupSPEs].pollfd=SPEfds + setupSPEs;
phelper[setupSPEs].type=2;
//printf("2\n");
@@ -1269,6 +1281,7 @@ spe_get_event(struct spe_event *pevents,
phelper[setupSPEs].event=i;
phelper[setupSPEs].thread=thread;
+ phelper[setupSPEs].pollfd=SPEfds + setupSPEs;
phelper[setupSPEs].type=3;
if (SPEfds[setupSPEs].fd == -1)
fprintf(stderr, "Warning: spe_get_events: attempting "
@@ -1304,32 +1317,42 @@ spe_get_event(struct spe_event *pevents,
return 0;
}
+
+ /* Sort results by fd to make it easy to avoid reading twice from the same fd.
+ There may be more efficient way to do the same thing...
+ */
+ qsort(phelper, setupSPEs, sizeof(*phelper), qsort_compare_poll_helper);
+ lastSPEfd = -1;
for (i=0 ; i < setupSPEs ; i++ )
{
- if (SPEfds[i].revents != 0)
+ if (phelper[i].pollfd->revents != 0 &&
+ lastSPEfd != phelper[i].pollfd->fd &&
+ pevents[phelper[i].event].revents == 0 /* avoid overwriting */)
{
int rc,data;
switch (phelper[i].type) {
case 1:
// Read ibox data if present
- rc = read(SPEfds[i].fd, &data, 4);
+ rc = read(phelper[i].pollfd->fd, &data, 4);
if (rc == 4)
{
pevents[phelper[i].event].data = data;
pevents[phelper[i].event].speid = phelper[i].thread;
pevents[phelper[i].event].revents = SPE_EVENT_MAILBOX;
+ ret_events++;
}
break;
case 2:
// Read pipe data if present
- rc = read(SPEfds[i].fd, &data, 4);
+ rc = read(phelper[i].pollfd->fd, &data, 4);
//pevents[phelper[i].event].revents = pevents[phelper[i].event].revents | data;
pevents[phelper[i].event].revents = data;
pevents[phelper[i].event].speid = phelper[i].thread;
pevents[phelper[i].event].data = phelper[i].thread->ev_data;
+ ret_events++;
phelper[i].thread->ev_data = 0;
phelper[i].thread->event = 0;
@@ -1337,22 +1360,24 @@ spe_get_event(struct spe_event *pevents,
case 3:
// Read tag group data if present
- rc = read(SPEfds[i].fd, &data, 4);
+ rc = read(phelper[i].pollfd->fd, &data, 4);
if (rc == 4)
{
pevents[phelper[i].event].data = data;
pevents[phelper[i].event].speid = phelper[i].thread;
pevents[phelper[i].event].revents = SPE_EVENT_TAG_GROUP;
+ ret_events++;
}
break;
}
+ lastSPEfd = phelper[i].pollfd->fd;
}
}
free(SPEfds);
free(phelper);
//printf("P2\n");
- return pollRet;
+ return ret_events;
}
int
-------------- next part --------------
A non-text attachment was scrubbed...
Name: block.tar
Type: application/octet-stream
Size: 10240 bytes
Desc: not available
URL: <http://lists.ozlabs.org/pipermail/cbe-oss-dev/attachments/20060328/cc227554/attachment.obj>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: overwrite.tar
Type: application/octet-stream
Size: 10240 bytes
Desc: not available
URL: <http://lists.ozlabs.org/pipermail/cbe-oss-dev/attachments/20060328/cc227554/attachment-0001.obj>
More information about the cbe-oss-dev
mailing list