Hi,
I think there is a problem in calling external programs from plugins. If such a program takes some while for execution (even in background) it gets inherited all file descriptors of VDR. This prevents vdr from zapping to another channel or even from restarting properly. You will see messages like:
ERROR: /dev/dvb/adapter0/dvr0: Device or resource busy or ERROR (svdrp.c,84): Address already in use
Reason: By default unix inherits all file descriptors to child processes when calling exec*(...) or system(...). You can avoid this by setting FD_CLOEXEC on all file descriptors that should not be inherited.
Patch: --- dvbdevice.c~ 2007-12-10 15:19:51.116943936 +0100 +++ dvbdevice.c 2007-12-10 15:19:51.120944682 +0100 @@ -63,6 +63,7 @@ int fd = open(FileName, Mode); if (fd < 0 && ReportError) LOG_ERROR_STR(FileName); + fcntl(fd, F_SETFD, FD_CLOEXEC); return fd; }
--- svdrp.c~ 2007-12-10 15:20:12.476929058 +0100 +++ svdrp.c 2007-12-10 15:20:12.480929804 +0100 @@ -91,7 +91,7 @@ LOG_ERROR; return false; } - oldflags |= O_NONBLOCK; + oldflags |= O_NONBLOCK|FD_CLOEXEC; if (fcntl(sock, F_SETFL, oldflags) < 0) { LOG_ERROR; return false;
Comments, ideas? I would be happy to see this little patch applied to 1.4 and 1.5 trunks of VDR.
Deti
Klaus Schmidinger wrote:
Doesn't SystemExec() (see tools.c) take care of this?
Yes you are right - it takes care internally but not for plugins like dvdswitch etc. In order to fix this problem you could patch every single plugin or just set the right file descriptor flag once. I think the latter does not cause any interference and should solves some issues.
Deti
I demand that Deti Fliegl may or may not have written...
In VDR all file descriptors seem to be allocated at startup. IMHO it is not very likely that a race condition could happen.
From open(2):
O_CLOEXEC (Since Linux 2.6.23) Enable the close-on-exec flag for the new file descriptor. Specifying this flag permits a program to avoid an additional fcntl(2) F_SETFD operation to set the FD_CLOEXEC flag. Addi- tionally, use of this flag is essential in some multithreaded programs since using a separate fcntl(2) F_SETFD operation to set the FD_CLOEXEC flag does not suffice to avoid race condi- tions where one thread opens a file descriptor at the same time as another thread does a fork(2) plus execve(2).
No use *now*, I know - too many people not yet using a new-enough kernel...
On 12/10/07 21:07, Deti Fliegl wrote:
Plugins can call SystemExec() just as well when the want to execute an external program.
IMHO it is no feasible solution to expect every file handle to be opened with FD_CLOEXEC. Even if VDR itself would do this, there could still be plugins that don't.
I'd say if some plugin wants to run an external program, it needs to take care by itself that all unneeded file handles are closed. That's what SystemExec() is for.
Klaus
Klaus Schmidinger wrote:
Plugins can call SystemExec() just as well when the want to execute an external program.
Yes, but would you point every single developer on this issue?
It is enough to let VDR set this flag on its own file handles - the main problem is that while an external script/program is running and because of inherited DVB handles - zapping is blocked - a restart of VDR is impossible.
Whatever - if you don't see the point I cannot help.
Deti
On 12/11/2007 08:39 AM, Deti Fliegl wrote:
Why is this suddenly such a big problem? If a plugin wants to run an external program it can simply use SystemExec().
Besides, as Darren Salt pointed out, this flag is apparently only available in the very latest kernel version, which I'm pretty sure is not that widely in use yet.
Klaus
I demand that Klaus Schmidinger may or may not have written...
[snip; FD_CLOEXEC]
Er, no: FD_CLOEXEC has been available for years (see fcntl(2)). You're confusing it with O_CLOEXEC, which is new.