Problems with reads in no-wait RPC calls
Posted: Sun Nov 04, 2007 1:06 am
I've run into weird problem with calling RPCs in no-wait mode. The concept of the code in question is very simple:
1. RPC function is called to send filled buffer from IOP side to EE side. If buffer is not yet filled, it waits till it's done (semaphore). If the required data lies outside of the buffered area, it invalidates the buffer and reads the required data into it alone. Misses happen very rarely, because the stream lies usually in one file and is read continously. It's always called synchronously (WAIT = 0, 'wait' mode). Always waiting for the dma transfer to finish before returning. Always checking if dma transfer was properly queued.
2. RPC function is called to fill the buffer with data (based on current buffer pos + buffer size). It's called asynchronously (WAIT = 1, 'no-wait' mode) while the previous buffer is processed on EE side.
It's not the most efficient solution, but for the purpose it was done, it is more than enough.
If the buffer fill function is called synchronously, everything is ok. The problems begin when I'm calling it asynchronously. I'm sure, the semaphores work as they should (see further, but I also implemented my own, simple, two state semaphores). The problem is, that if I read in the asynchronously called function more than 1024 bytes at once... then somehow the buffer is not sent properly by the first function (it seems, the read command reads wrong data, although file is properly opened, lseek is properly done and read returns proper amount of bytes read). It doesn't happen often, but always seem to be related to the fact that functions are called to close to each other (very rarely processing on EE side is finished much quicker than usually, and read/send buffer is called in a short time). This problem persists even if I read into separate buffer and do not make any additional changes (so the first function always misses the buffer, thus making in fact all the real reads synchronous).
If I read entire size in 1024B chunks, it works ok. Anything more results in problems from time to time. The semaphores work fine (send buffer is postopned as it should if at buffer fill something like waitthread is done; everything works fine if I'm doing it the other way). The results are better if I place some code between first (synchronous) and second (asynchronous) function call (it can be even nopdelay(); ), but it doesn't solve the problem (it's just less frequent). The same, when I place such delay after second function call (then get buffer call never happens before buffer is fully filled).
Memory is properly aligned, checked static/volatile qualifiers, tried reading/writing to uncached space, made many, many other things... but wasn't able to solve this to work with no-wait mode. It doesn't mean I didn't solve this (that's why I'm sure of all the code).
I've solved it by making just a simple reorganization. I'm making the second RPC call synchronously, then on IOP side I'm checking if the thread for fill buffer function is created. If it's not, I'm just creating it... if it is, I'm just waking it up. Returning immediately from the RPC server thread. Just as in this code.
(returns null pointer, but at this time, there is 0 byte long receive buffer at EE side, so it's not a mistake... I tried of course sending something usefull here for tests).
It works almost just as calling it in no-wait mode. This is in fact more efficient than the no-wait solution (not very much, but still, so it' a better solution anyway). Now everything works fine, so problem solved, but it bothers me a little bit. What may be the reasons that making more than 1024 bytes reads in asynchronously called function leads to some problems?
BTW. I'm using host: (ps2link), same happens using fakehost (redirecting to hdd). Didn't try it with anything else.
1. RPC function is called to send filled buffer from IOP side to EE side. If buffer is not yet filled, it waits till it's done (semaphore). If the required data lies outside of the buffered area, it invalidates the buffer and reads the required data into it alone. Misses happen very rarely, because the stream lies usually in one file and is read continously. It's always called synchronously (WAIT = 0, 'wait' mode). Always waiting for the dma transfer to finish before returning. Always checking if dma transfer was properly queued.
2. RPC function is called to fill the buffer with data (based on current buffer pos + buffer size). It's called asynchronously (WAIT = 1, 'no-wait' mode) while the previous buffer is processed on EE side.
It's not the most efficient solution, but for the purpose it was done, it is more than enough.
If the buffer fill function is called synchronously, everything is ok. The problems begin when I'm calling it asynchronously. I'm sure, the semaphores work as they should (see further, but I also implemented my own, simple, two state semaphores). The problem is, that if I read in the asynchronously called function more than 1024 bytes at once... then somehow the buffer is not sent properly by the first function (it seems, the read command reads wrong data, although file is properly opened, lseek is properly done and read returns proper amount of bytes read). It doesn't happen often, but always seem to be related to the fact that functions are called to close to each other (very rarely processing on EE side is finished much quicker than usually, and read/send buffer is called in a short time). This problem persists even if I read into separate buffer and do not make any additional changes (so the first function always misses the buffer, thus making in fact all the real reads synchronous).
If I read entire size in 1024B chunks, it works ok. Anything more results in problems from time to time. The semaphores work fine (send buffer is postopned as it should if at buffer fill something like waitthread is done; everything works fine if I'm doing it the other way). The results are better if I place some code between first (synchronous) and second (asynchronous) function call (it can be even nopdelay(); ), but it doesn't solve the problem (it's just less frequent). The same, when I place such delay after second function call (then get buffer call never happens before buffer is fully filled).
Memory is properly aligned, checked static/volatile qualifiers, tried reading/writing to uncached space, made many, many other things... but wasn't able to solve this to work with no-wait mode. It doesn't mean I didn't solve this (that's why I'm sure of all the code).
I've solved it by making just a simple reorganization. I'm making the second RPC call synchronously, then on IOP side I'm checking if the thread for fill buffer function is created. If it's not, I'm just creating it... if it is, I'm just waking it up. Returning immediately from the RPC server thread. Just as in this code.
Code: Select all
void readAheadThread()
{
while (1)
{
temp_readbufahead_RPC();
SleepThread();
}
ExitDeleteThread();
}
part of RPC server thread
[...]
case TEMP_READBUFFAHEAD:
if (readAheadThreadId == 0)
{
struct _iop_thread param;
param.attr = 0x02000000;
param.thread = (void*)readAheadThread;
param.priority = 39;
param.stacksize = 0x800;
param.option = 0;
readAheadThreadId = CreateThread(¶m);
if (readAheadThreadId > 0)
{
StartThread(readAheadThreadId,0);
}
} else
{
WakeupThread(readAheadThreadId);
}
return NULL;
[...]
It works almost just as calling it in no-wait mode. This is in fact more efficient than the no-wait solution (not very much, but still, so it' a better solution anyway). Now everything works fine, so problem solved, but it bothers me a little bit. What may be the reasons that making more than 1024 bytes reads in asynchronously called function leads to some problems?
BTW. I'm using host: (ps2link), same happens using fakehost (redirecting to hdd). Didn't try it with anything else.