Update unix postprocessor code to allow for a fixed number of simultaneous postprocessor child processes. Previous behavior killed the previous process in order to start a new one. Also correctly tracks when they die.

pull/68/head
Jeffery Weston 2022-04-29 13:47:07 -04:00
parent 5dc78909ce
commit b997771fec
1 changed files with 87 additions and 19 deletions

View File

@ -81,37 +81,49 @@ bool NetscapeIsRunning(Window *result);
bool NetscapeCheckWindow(Window window);
#endif // NETSCAPE_SUPPORT
#define MAX_SUBPROCESSES 32
static void OnSIGCHLD(int signum);
class UnixPostProcessor : public NormPostProcessor
{
public:
~UnixPostProcessor();
bool IsActive() {return (0 != process_id);}
bool IsActive();
bool ProcessFile(const char* path);
void Kill();
void OnSIGCHLD();
void ClearPid(int pid);
private:
friend class NormPostProcessor;
UnixPostProcessor();
bool IsActive(unsigned int array_element);
unsigned int GetOpenProcessIdSlot();
void Kill(unsigned int array_element);
int process_id;
int process_id[MAX_SUBPROCESSES];
#ifdef NETSCAPE_SUPPORT
Window window_id;
#endif // NETSCAPE_SUPPORT
}; // end class UnixPostProcessor
UnixPostProcessor* theprocessor;
UnixPostProcessor::UnixPostProcessor()
: process_id(0)
: process_id()
#ifdef NETSCAPE_SUPPORT
,window_id(0)
#endif // NETSCAPE_SUPPORT
{
signal(SIGCHLD, OnSIGCHLD);
}
NormPostProcessor* NormPostProcessor::Create()
{
return static_cast<NormPostProcessor*>(new UnixPostProcessor);
//return static_cast<NormPostProcessor*>(new UnixPostProcessor);
theprocessor = new UnixPostProcessor;
return static_cast<NormPostProcessor*>(theprocessor);
} // end NormPostProcessor::Create()
UnixPostProcessor::~UnixPostProcessor()
@ -119,6 +131,31 @@ UnixPostProcessor::~UnixPostProcessor()
if (IsActive()) Kill();
}
bool UnixPostProcessor::IsActive()
{
for (unsigned int i=0;i<MAX_SUBPROCESSES;i++)
{
if (0 != process_id[i]) return true;
}
return false;
}
bool UnixPostProcessor::IsActive(unsigned int array_element)
{
return (0 != process_id[array_element]);
}
unsigned int UnixPostProcessor::GetOpenProcessIdSlot()
{
for (unsigned int i=0;i<MAX_SUBPROCESSES;i++)
{
if (0 == process_id[i]) return i;
}
//No available slot, kill something
Kill(0);
return 0;
}
bool UnixPostProcessor::ProcessFile(const char* path)
{
const char** argv = (const char**)process_argv;
@ -192,7 +229,7 @@ bool UnixPostProcessor::ProcessFile(const char* path)
}
else
{
if (IsActive()) Kill();
//if (IsActive()) Kill();
window_id = USE_ACTIVE_WINDOW;
myArgs[i++] = path;
} // end if/else (NetscapeIsRunning())
@ -203,7 +240,8 @@ bool UnixPostProcessor::ProcessFile(const char* path)
else
#endif // NETSCAPE_SUPPORT
{
if (IsActive()) Kill();
//if (IsActive()) Kill();
// GetOpenProcessIdSlot() below will do this for us now...
argv[argc] = path;
}
@ -212,11 +250,12 @@ bool UnixPostProcessor::ProcessFile(const char* path)
sighandler_t sigintHandler = signal(SIGINT, SIG_DFL);
sighandler_t sigchldHandler = signal(SIGCHLD, SIG_DFL);
switch((process_id = fork()))
unsigned int idnum = GetOpenProcessIdSlot();
switch((process_id[idnum] = fork()))
{
case -1: // error
DMSG(0, "UnixPostProcessor::ProcessFile fork() error: %s\n", strerror(errno));
process_id = 0;
process_id[idnum] = 0;
process_argv[process_argc] = NULL;
return false;
@ -235,8 +274,8 @@ bool UnixPostProcessor::ProcessFile(const char* path)
signal(SIGINT, sigintHandler);
// The use of "waitpid()" here is a work-around
// for an IRIX SIGCHLD issue
int status;
while (waitpid(-1, &status, WNOHANG) > 0);
//int status;
//while (waitpid(-1, &status, WNOHANG) > 0);
signal(SIGCHLD, sigchldHandler);
break;
}
@ -245,9 +284,17 @@ bool UnixPostProcessor::ProcessFile(const char* path)
void UnixPostProcessor::Kill()
{
if (!IsActive()) return;
for (unsigned int i=0;i<MAX_SUBPROCESSES;i++)
{
if (IsActive(i)) Kill(i);
}
}
void UnixPostProcessor::Kill(unsigned int array_element)
{
if (!IsActive(array_element)) return;
int count = 0;
while((kill(process_id, SIGTERM) != 0) && count < 10)
while((kill(process_id[array_element], SIGTERM) != 0) && count < 10)
{
if (errno == ESRCH) break;
count++;
@ -255,22 +302,43 @@ void UnixPostProcessor::Kill()
}
count = 0;
int status;
while((waitpid(process_id, &status, 0) != process_id) && count < 10)
while((waitpid(process_id[array_element], &status, 0) != process_id[array_element]) && count < 10)
{
if (errno == ECHILD) break;
count++;
DMSG(0, "UnixPostProcessor::Kill waitpid() error: %s\n", strerror(errno));
}
process_id = 0;
process_id[array_element] = 0;
} // end UnixPostProcessor::Kill()
void UnixPostProcessor::OnSIGCHLD()
void UnixPostProcessor::ClearPid(int pid)
{
for (unsigned int i=0;i<MAX_SUBPROCESSES;i++)
{
if (pid == process_id[i]) process_id[i] = 0;
}
}
static void OnSIGCHLD(int signum)
{
// See if post processor exited itself
int status;
if (wait(&status) == process_id) process_id = 0;
} // end UnixPostProcessor::HandleSIGCHLD()
pid_t p;
//int wait_rtn = wait(&status);
while (true)
{
p = waitpid(-1, &status, WNOHANG);
if (p == -1)
{
if (errno == EINTR) continue;
break;
}
// check for no more children
else if (p == 0) break;
// else handle returned PID
theprocessor->ClearPid(p);
}
}
#ifdef NETSCAPE_SUPPORT
bool CheckForNetscape(const char* cmd)