Hi,
I'm facing a deadlock situation, when the below code is modified to ignore the "r == 0" cases (= original code in vdr-xine-0.7.2):
int cXineLib::xread(int f, void *b, int n) { bool atEOF = false;
int t = 0;
while (t < n) { void (* const sigPipeHandler)(int) = ::signal(SIGPIPE, SIG_IGN);
errno = 0; int r = ::read(f, ((char *)b) + t, n - t); int myErrno = errno;
::signal(SIGPIPE, sigPipeHandler);
if (r < 0 || (r == 0 && atEOF)) { if (EAGAIN == myErrno) continue;
fprintf(stderr, "lib::read(%d) failed (atEOF: %d) %d: ", n, atEOF, myErrno); errno = myErrno; perror("");
disconnect();
return r; } else if (r == 0) { cPoller Poller(f); atEOF = Poller.Poll(0); fprintf(stderr, "--- lib read 0, atEOF %d\n", atEOF); } else atEOF = false;
t += r; }
return t; }
Some more information: - Filedescriptor "f" represents a FIFO, which is opend for reading and should be in blocking mode by design. - As this function is called by different threads (synchronized outside via mutex), I save and restore the handler for signal SIGPIPE, as I don't want any of VDR's signal handlers to be triggered.
The read() should block until data is available and typically return the number of bytes read, which should be greater than zero. But there are some cases, where read() returns zero: a) the writing side of the FIFO was closed. b) a signal caused the block to break.
The original code simply ignores the result of zero, as for case a) a different function (xwrite), which should be called by a different thread, should see a SIGPIPE and initiate the disconnect(). Case b) should simply go on with reading the remaining data. But this leads to a deadlock situation where the read() never returns anything != 0 and therefore the original loop spins forever. This is most likely to trigger if you move cutting marks (on my machine it only triggers when xine uses -V xshm and when moving cutting marks in HDTV recordings).
The new code above tries to detect case a) by asking a cPoller, whether data is available on file descriptor f, after the read returned 0.
Let's assume, the Poll() returns true, because data is available: atEOF is set pessimistically but the next read() should return anything > 0, which resets atEOF. The loop continues.
When the Poll() returns false as there is no further data available, the next read() should block. The loop continues.
But the Poll() might return true in an error condition (e. g. the writing side of the FIFO was closed). Then the next read() is expected to return anything <= 0. The loop terminates and a disconnect() happens.
The strange thing is now, that a disconnect() happens occationally when moving cutting marks.
Any help appreciated! Thanks!
Bye.
On Friday 25 March 2005 00:18, Reinhard Nissl wrote:
Hi,
I'm facing a deadlock situation, when the below code is modified to ignore the "r == 0" cases (= original code in vdr-xine-0.7.2):
r==0 means that there is no data available. Are you sure you want to block in xread until data is available?
If you want to ignore the r==0 cases, why don't you simply open the file in blocking mode (remove O_NONBLOCK from xineLib.c:2160) ?
If you want to wait for data (and keep the non-blocking) you should wait some time (200ms or so). If you are not sure about the cPoller, use the select function with a timeout. Then you get exact error codes and all that.
Kind regards, Stefan
Hi,
Stefan Taferner wrote:
I'm facing a deadlock situation, when the below code is modified to ignore the "r == 0" cases (= original code in vdr-xine-0.7.2):
r==0 means that there is no data available. Are you sure you want to block in xread until data is available?
Yes, because there is nothing else to do at that point in time.
This function is used to retrieve the result of a "remote procedure call" (e. g. in execFuncGetPTS()).
If you want to ignore the r==0 cases, why don't you simply open the file in blocking mode (remove O_NONBLOCK from xineLib.c:2160) ?
O_NONBLOCK is just used to be able to open the FIFO while xine still needs to connect to the FIFO. After opening the FIFOs, O_NONBLOCK is removed in lines 2164 and 2165.
But the FIFO used in the above example (fd_result) has never been opended nonblocking (see line 2162).
If you want to wait for data (and keep the non-blocking) you should wait some time (200ms or so). If you are not sure about the cPoller, use the select function with a timeout. Then you get exact error codes and all that.
All I'd like to do is to block until the requested data is ready and "r == 0" should just indicate that the FIFO was closed by xine.
But for any reason, "r == 0" happens still without the FIFO beeing closed. Can someone tell me, how to handle this situation properly?
Bye.
On Friday 25 March 2005 09:38, Reinhard Nissl wrote:
Hi,
Stefan Taferner wrote:
I'm facing a deadlock situation, when the below code is modified to ignore the "r == 0" cases (= original code in vdr-xine-0.7.2):
r==0 means that there is no data available. Are you sure you want to block in xread until data is available?
Yes, because there is nothing else to do at that point in time.
Ok.
[...]
If you want to wait for data (and keep the non-blocking) you should wait some time (200ms or so). If you are not sure about the cPoller, use the select function with a timeout. Then you get exact error codes and all that.
All I'd like to do is to block until the requested data is ready and "r == 0" should just indicate that the FIFO was closed by xine.
But for any reason, "r == 0" happens still without the FIFO beeing closed. Can someone tell me, how to handle this situation properly?
The read manpage says: On success, the number of bytes read is returned (zero indicates end of file). But you probably already know that.
Here is my version of xread, taken from vdr-xine-0.7.2 with modifications. But it is an untested version of code I wrote at work (still have no vdr at hands).
int cXineRemote::xread(int f, void *b, int n) { int t = 0; void (* const sigPipeHandler)(int) = ::signal(SIGPIPE, SIG_IGN);
while (t < n) {
int r = ::read(f, ((char *)b) + t, n - t);
if (r < 0) { fprintf(stderr, "::read(%d) failed %d: ", n, errno); perror("");
disconnect();
t = -1; break; } else if (r == 0) { // fprintf( stderr, "::read zero bytes\n"); fd_set fds; FD_ZERO(&fds); FD_SET(f, &fds); struct timeval tmout; tmout.tv_sec = 3600; tmout.tv_usec = 0; int rc = select(f+1, &fds, 0, 0, &tmout); fprintf(stderr, "::select returned %d\n", rc); } else t += r; }
::signal(SIGPIPE, sigPipeHandler); return t; }
--Stefan
Hi,
Stefan Taferner wrote:
If you want to wait for data (and keep the non-blocking) you should wait some time (200ms or so). If you are not sure about the cPoller, use the select function with a timeout. Then you get exact error codes and all that.
All I'd like to do is to block until the requested data is ready and "r == 0" should just indicate that the FIFO was closed by xine.
But for any reason, "r == 0" happens still without the FIFO beeing closed. Can someone tell me, how to handle this situation properly?
The read manpage says: On success, the number of bytes read is returned (zero indicates end of file). But you probably already know that.
Sure.
Here is my version of xread, taken from vdr-xine-0.7.2 with modifications. But it is an untested version of code I wrote at work (still have no vdr at hands).
Sorry, makes no difference.
But I think, that maybe the problem has to do with still images, which are sent while moving cut marks, as it only happens when moving cut marks.
Some days ago I've already discovered that VDR doesn't call StillImage() with a single I-frame. It may contain some remainder of the previous B-frame and may be too short, as the remainder of the I-frame is in the PES packet which contains the start of the next B-frame.
At the moment, it looks like xine disconnects for some reason (maybe it sees an end of stream in the garbage). I'll have to make sure first, that only correct data is sent to xine. And then it may simply be enough to disconnect in the case "r == 0".
Thank you very much for your help!
Bye.