[mythtv] [patch] channelbase cleanup

Daniel Thor Kristjansson danielk at mrl.nyu.edu
Wed Dec 29 19:19:14 UTC 2004


This patch cleans up the handling of errors encountered when executing 
an external channel changing program or script. I've also added some 
code to timeout if this program does not exit within 30 seconds. However 
I've left in the "&" in the execution of the script because this 
function is not called in a separate thread and could possibly take a 
very long time when changing the channel involves moving a dish. But if 
we address this problem in the future, this timeout handling would allow 
us to wait for the tuning program to finish, and let us observe the 
return value; this lets the external program signal problems to MythTV.

This function was returning 'no error' when the fork call didn't work, 
this has been fixed. I've also added a check of the return value of 
execl, which will tell us if there was an access error. And I've fixed 
the status checking so it differentiates between a program killed by a 
signal or returning a non-zero value. This patch also changes the cerr 
redirects and perror's in channelbase to use the VERBOSE macro.

-- Daniel
-------------- next part --------------
Index: libs/libmythtv/channelbase.cpp
===================================================================
RCS file: /var/lib/mythcvs/mythtv/libs/libmythtv/channelbase.cpp,v
retrieving revision 1.9
diff -u -r1.9 channelbase.cpp
--- libs/libmythtv/channelbase.cpp	19 Aug 2004 02:02:20 -0000	1.9
+++ libs/libmythtv/channelbase.cpp	29 Dec 2004 19:05:15 -0000
@@ -107,7 +107,8 @@
     if (input >= 0)
         SwitchToInput(input, true);
     else
-        cerr << "Couldn't find input: " << inputname << " on card\n";
+        VERBOSE(VB_IMPORTANT, QString("ChannelBase: Could not find input: "
+                                      "%1 on card\n").arg(inputname));
 }
 
 void ChannelBase::SwitchToInput(const QString &inputname, const QString &chan)
@@ -120,7 +121,9 @@
         SetChannelByString(chan);
     }
     else
-        cerr << "Couldn't find input: " << inputname << " on card\n";
+        VERBOSE(VB_IMPORTANT,
+                QString("ChannelBase: Could not find input: %1 on card when "
+                        "setting channel %2\n").arg(inputname).arg(chan));
 }
 
 bool ChannelBase::ChangeExternalChannel(const QString &channum)
@@ -134,28 +137,73 @@
     VERBOSE(VB_CHANNEL, QString("External channel change: %1").arg(command));
     pid_t child = fork();
     if (child < 0)
-    {
-        perror("fork");
+    {   // error encountered in creating fork
+        QString msg("ChannelBase: fork error -- ");
+        msg.append(strerror(errno));
+        VERBOSE(VB_IMPORTANT, msg);
+        return false;
     }
     else if (child == 0)
-    {
+    {   // we are the new fork
         for(int i = 3; i < sysconf(_SC_OPEN_MAX) - 1; ++i)
             close(i);
-        execl("/bin/sh", "sh", "-c", command.ascii(), NULL);
-        perror("exec");
-        _exit(-11);
+        int ret=execl("/bin/sh", "sh", "-c", command.ascii(), NULL);
+        QString msg("ChannelBase: ");
+        if (EACCES==ret) {
+            msg.append(QString("Access denied to /bin/sh"
+                               " when executing %1\n").arg(command.ascii()));
+        }
+        msg.append(strerror(errno));
+        VERBOSE(VB_IMPORTANT, msg);
+        _exit(1); // this exit is ok, we are just exiting from the channel changing fork with an error.
     }
     else
-    {
-        int status;
-        if (waitpid(child, &status, 0) < 0)
+    {   // child contains the pid of the new process
+        int status=0, pid=0;
+        VERBOSE(VB_CHANNEL, "Waiting for External Tuning program to exit");
+
+        bool timed_out = false;
+        uint timeout = 30; // how long to wait in seconds
+        time_t start_time = time(0);
+        while (-1!=pid && !timed_out)
         {
-            perror("waitpid");
+            sleep(1);
+            pid = waitpid(child, &status, WUNTRACED|WNOHANG);
+            VERBOSE(VB_IMPORTANT, QString("ret_pid(%1) child(%2) status(0x%3)")
+                    .arg(pid).arg(child).arg(status,0,16));
+            if (pid==child)
+                break;
+            else if (time(0)>start_time+timeout)
+                timed_out = true;
         }
-        else if (status != 0)
+        if (timed_out)
         {
-            cerr << "External channel change command exited with status "
-                 << status << endl;
+            VERBOSE(VB_IMPORTANT, "External Tuning program timed out, killing");
+            kill(child, SIGTERM);
+            usleep(500);
+            kill(child, SIGKILL);
+            return false;
+        }
+
+        VERBOSE(VB_CHANNEL, "External Tuning program no longer running");
+        if (WIFEXITED(status))
+        {   // program exited normally
+            int ret = WEXITSTATUS(status);
+            if (ret)
+            {   // external tuning program returned error value
+                VERBOSE(VB_IMPORTANT,
+                        QString("ChannelBase: external tuning program "
+                                "exited with error %1").arg(ret));
+                return false;
+            }
+            VERBOSE(VB_IMPORTANT, "External Tuning program exited with no error");
+        }
+        else
+        {   // program exited abnormally
+            QString msg = QString("ChannelBase: external tuning program "
+                                  "encountered error %1 -- ").arg(errno);
+            msg.append(strerror(errno));
+            VERBOSE(VB_IMPORTANT, msg);
             return false;
         }
     }


More information about the mythtv-dev mailing list