From 8a84f6b751f54b71f2476beef2eec10a9c919f36 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Mon, 24 Apr 2000 13:54:23 +0200 Subject: [PATCH] Improved process handling --- dvbapi.c | 53 +++++++++++++++++++---------------------------------- dvbapi.h | 3 +-- tools.c | 38 +++++++++++++++++++++++++++++++++++++- tools.h | 7 ++++++- vdr.c | 3 +-- 5 files changed, 64 insertions(+), 40 deletions(-) diff --git a/dvbapi.c b/dvbapi.c index b38c25f8..a9544ffa 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -4,18 +4,16 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.c 1.6 2000/04/24 09:44:19 kls Exp $ + * $Id: dvbapi.c 1.7 2000/04/24 13:27:38 kls Exp $ */ #include "dvbapi.h" #include #include -#include #include #include #include #include -#include #include #include "interface.h" #include "tools.h" @@ -59,7 +57,6 @@ #define RESUMEFILESUFFIX "/resume.vdr" #define RECORDFILESUFFIX "/%03d.vdr" #define RECORDFILESUFFIXLEN 20 // some additional bytes for safety... -#define MAXPROCESSTIMEOUT 3 // seconds // The number of frames to back up when resuming an interrupted replay session: #define RESUMEBACKUP (10 * FRAMESPERSEC) @@ -554,7 +551,7 @@ private: public: cRecordBuffer(int *InFile, const char *FileName); virtual ~cRecordBuffer(); - int WriteWithTimeout(void); + int WriteWithTimeout(bool EndIfEmpty = false); }; cRecordBuffer::cRecordBuffer(int *InFile, const char *FileName) @@ -720,13 +717,13 @@ int cRecordBuffer::Write(int Max) return 0; } -int cRecordBuffer::WriteWithTimeout(void) +int cRecordBuffer::WriteWithTimeout(bool EndIfEmpty) { int w, written = 0; int t0 = time_ms(); while ((w = Write()) > 0 && time_ms() - t0 < MAXRECORDWRITETIME) written += w; - return w < 0 ? w : written; + return w < 0 ? w : (written == 0 && EndIfEmpty ? -1 : written); } // --- cReplayBuffer --------------------------------------------------------- @@ -841,7 +838,7 @@ void cReplayBuffer::SkipSeconds(int Seconds) } Index += Seconds * FRAMESPERSEC; if (Index < 0) - Index = 1; + Index = 1; // not '0', to allow GetNextIFrame() below to work! uchar FileNumber; int FileOffset; if (index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) >= 0) @@ -1226,35 +1223,17 @@ bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Sr return false; } -void cDvbApi::KillProcess(pid_t pid) -{ - pid_t Pid2Wait4 = pid; - for (time_t t0 = time(NULL); time(NULL) - t0 < MAXPROCESSTIMEOUT; ) { - int status; - pid_t pid = waitpid(Pid2Wait4, &status, WNOHANG); - if (pid < 0) { - if (errno != ECHILD) - LOG_ERROR; - return; - } - if (pid == Pid2Wait4) - return; - } - esyslog(LOG_ERR, "ERROR: process %d won't end (waited %d seconds) - terminating it...", Pid2Wait4, MAXPROCESSTIMEOUT); - if (kill(Pid2Wait4, SIGTERM) < 0) { - esyslog(LOG_ERR, "ERROR: process %d won't terminate (%s) - killing it...", Pid2Wait4, strerror(errno)); - if (kill(Pid2Wait4, SIGKILL) < 0) - esyslog(LOG_ERR, "ERROR: process %d won't die (%s) - giving up", Pid2Wait4, strerror(errno)); - } -} - bool cDvbApi::Recording(void) { + if (pidRecord && !CheckProcess(pidRecord)) + pidRecord = 0; return pidRecord; } bool cDvbApi::Replaying(void) { + if (pidReplay && !CheckProcess(pidReplay)) + pidReplay = 0; return pidReplay; } @@ -1305,6 +1284,7 @@ bool cDvbApi::StartRecord(const char *FileName) dsyslog(LOG_INFO, "start recording process (pid=%d)", getpid()); isMainProcess = false; + bool DataStreamBroken = false; int fromMain = toRecordPipe[0]; int toMain = fromRecordPipe[1]; cRecordBuffer *Buffer = new cRecordBuffer(&videoDev, FileName); @@ -1317,21 +1297,26 @@ bool cDvbApi::StartRecord(const char *FileName) struct timeval timeout; timeout.tv_sec = 1; timeout.tv_usec = 0; + bool ForceEnd = false; if (select(FD_SETSIZE, &set, NULL, NULL, &timeout) > 0) { if (FD_ISSET(videoDev, &set)) { if (Buffer->Read() < 0) break; + DataStreamBroken = false; } if (FD_ISSET(fromMain, &set)) { switch (readchar(fromMain)) { - case dvbStop: Buffer->Stop(); break; - break; + case dvbStop: Buffer->Stop(); + ForceEnd = DataStreamBroken; + break; } } } - else + else { + DataStreamBroken = true; esyslog(LOG_ERR, "ERROR: video data stream broken"); - if (Buffer->WriteWithTimeout() < 0) + } + if (Buffer->WriteWithTimeout(ForceEnd) < 0) break; } delete Buffer; diff --git a/dvbapi.h b/dvbapi.h index 1015db1b..ddfdc154 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbapi.h 1.6 2000/04/24 09:44:21 kls Exp $ + * $Id: dvbapi.h 1.7 2000/04/24 10:46:47 kls Exp $ */ #ifndef __DVBAPI_H @@ -96,7 +96,6 @@ private: int fromRecord, toRecord; int fromReplay, toReplay; void SetReplayMode(int Mode); - void KillProcess(pid_t pid); public: bool Recording(void); // Returns true if we are currently recording. diff --git a/tools.c b/tools.c index 68009b6f..c43e610f 100644 --- a/tools.c +++ b/tools.c @@ -4,13 +4,14 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.5 2000/04/24 09:46:02 kls Exp $ + * $Id: tools.c 1.6 2000/04/24 13:54:23 kls Exp $ */ #define _GNU_SOURCE #include "tools.h" #include #include +#include #include #include #include @@ -134,6 +135,41 @@ bool RemoveFileOrDir(const char *FileName) return false; } +bool CheckProcess(pid_t pid) +{ + pid_t Pid2Check = pid; + int status; + pid = waitpid(Pid2Check, &status, WNOHANG); + if (pid < 0) { + if (errno != ECHILD) + LOG_ERROR; + return false; + } + return true; +} + +void KillProcess(pid_t pid, int Timeout) +{ + pid_t Pid2Wait4 = pid; + for (time_t t0 = time(NULL); time(NULL) - t0 < Timeout; ) { + int status; + pid_t pid = waitpid(Pid2Wait4, &status, WNOHANG); + if (pid < 0) { + if (errno != ECHILD) + LOG_ERROR; + return; + } + if (pid == Pid2Wait4) + return; + } + esyslog(LOG_ERR, "ERROR: process %d won't end (waited %d seconds) - terminating it...", Pid2Wait4, Timeout); + if (kill(Pid2Wait4, SIGTERM) < 0) { + esyslog(LOG_ERR, "ERROR: process %d won't terminate (%s) - killing it...", Pid2Wait4, strerror(errno)); + if (kill(Pid2Wait4, SIGKILL) < 0) + esyslog(LOG_ERR, "ERROR: process %d won't die (%s) - giving up", Pid2Wait4, strerror(errno)); + } +} + // --- cListObject ----------------------------------------------------------- cListObject::cListObject(void) diff --git a/tools.h b/tools.h index c6708332..3263b914 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.5 2000/04/24 09:46:05 kls Exp $ + * $Id: tools.h 1.6 2000/04/24 13:09:20 kls Exp $ */ #ifndef __TOOLS_H @@ -13,6 +13,8 @@ #include #include #include +#include +#include extern int SysLogLevel; @@ -24,6 +26,7 @@ extern int SysLogLevel; #define LOG_ERROR_STR(s) esyslog(LOG_ERR, "ERROR: %s: %s", s, strerror(errno)); #define SECSINDAY 86400 +#define MAXPROCESSTIMEOUT 3 // seconds #define DELETENULL(p) (delete (p), p = NULL) @@ -36,6 +39,8 @@ int time_ms(void); void delay_ms(int ms); bool MakeDirs(const char *FileName, bool IsDirectory = false); bool RemoveFileOrDir(const char *FileName); +bool CheckProcess(pid_t pid); +void KillProcess(pid_t pid, int Timeout = MAXPROCESSTIMEOUT); class cListObject { private: diff --git a/vdr.c b/vdr.c index f852bf73..cbc09504 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.11 2000/04/24 10:33:38 kls Exp $ + * $Id: vdr.c 1.12 2000/04/24 13:36:39 kls Exp $ */ #include @@ -183,7 +183,6 @@ int main(int argc, char *argv[]) isyslog(LOG_INFO, "caught signal %d", Interrupted); DvbApi.StopRecord(); DvbApi.StopReplay(); - //TODO kill any remaining sub-processes! isyslog(LOG_INFO, "exiting"); closelog(); return 0;