Blame src/ProcWait.cc

Packit 8f70b4
/*
Packit 8f70b4
 * lftp - file transfer program
Packit 8f70b4
 *
Packit 8f70b4
 * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net)
Packit 8f70b4
 *
Packit 8f70b4
 * This program is free software; you can redistribute it and/or modify
Packit 8f70b4
 * it under the terms of the GNU General Public License as published by
Packit 8f70b4
 * the Free Software Foundation; either version 3 of the License, or
Packit 8f70b4
 * (at your option) any later version.
Packit 8f70b4
 *
Packit 8f70b4
 * This program is distributed in the hope that it will be useful,
Packit 8f70b4
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8f70b4
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8f70b4
 * GNU General Public License for more details.
Packit 8f70b4
 *
Packit 8f70b4
 * You should have received a copy of the GNU General Public License
Packit 8f70b4
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 8f70b4
 */
Packit 8f70b4
Packit 8f70b4
#include <config.h>
Packit 8f70b4
#include <sys/wait.h>
Packit 8f70b4
#include <errno.h>
Packit 8f70b4
#include "trio.h"
Packit 8f70b4
#include "ProcWait.h"
Packit 8f70b4
#include "SignalHook.h"
Packit 8f70b4
Packit 8f70b4
xmap<ProcWait*> ProcWait::all_proc;
Packit 8f70b4
Packit 8f70b4
const xstring& ProcWait::proc_key(pid_t p)
Packit 8f70b4
{
Packit 8f70b4
   static xstring tmp_key;
Packit 8f70b4
   tmp_key.nset((const char*)&p,sizeof(p));
Packit 8f70b4
   return tmp_key;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
int ProcWait::Do()
Packit 8f70b4
{
Packit 8f70b4
   int m=STALL;
Packit 8f70b4
   if(status!=RUNNING)
Packit 8f70b4
   {
Packit 8f70b4
   final:
Packit 8f70b4
      if(auto_die)
Packit 8f70b4
      {
Packit 8f70b4
	 Delete(this);
Packit 8f70b4
	 return MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      return m;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   int info;
Packit 8f70b4
   int res=waitpid(pid,&info,WNOHANG|WUNTRACED);
Packit 8f70b4
   if(res==-1)
Packit 8f70b4
   {
Packit 8f70b4
      if(status!=RUNNING)
Packit 8f70b4
	 return MOVED;
Packit 8f70b4
      // waitpid failed, check the process existence
Packit 8f70b4
      if(kill(pid,0)==-1)
Packit 8f70b4
      {
Packit 8f70b4
	 status=TERMINATED;
Packit 8f70b4
	 term_info=255;
Packit 8f70b4
	 m=MOVED;
Packit 8f70b4
	 goto final;
Packit 8f70b4
      }
Packit 8f70b4
      goto leave;
Packit 8f70b4
   }
Packit 8f70b4
   if(res==pid)
Packit 8f70b4
   {
Packit 8f70b4
      if(handle_info(info))
Packit 8f70b4
      {
Packit 8f70b4
	 m=MOVED;
Packit 8f70b4
	 goto final;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
leave:
Packit 8f70b4
   Timeout(500); // check from time to time, in case SIGCHLD fails
Packit 8f70b4
   return m;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
bool ProcWait::handle_info(int info)
Packit 8f70b4
{
Packit 8f70b4
   if(WIFSTOPPED(info))
Packit 8f70b4
   {
Packit 8f70b4
      SignalHook::IncreaseCount(SIGTSTP);
Packit 8f70b4
      return false;
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      if(WIFSIGNALED(info) && WTERMSIG(info)==SIGINT)
Packit 8f70b4
	 SignalHook::IncreaseCount(SIGINT);
Packit 8f70b4
      status=TERMINATED;
Packit 8f70b4
      term_info=info;
Packit 8f70b4
      return true;
Packit 8f70b4
   }
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
int ProcWait::Kill(int sig)
Packit 8f70b4
{
Packit 8f70b4
   Do();
Packit 8f70b4
   if(status!=RUNNING)
Packit 8f70b4
      return -1;
Packit 8f70b4
Packit 8f70b4
   int res;
Packit 8f70b4
   res=kill(-pid,sig);
Packit 8f70b4
   if(res==-1)
Packit 8f70b4
      res=kill(pid,sig);
Packit 8f70b4
   return res;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
ProcWait::ProcWait(pid_t p)
Packit 8f70b4
   : pid(p)
Packit 8f70b4
{
Packit 8f70b4
   auto_die=false;
Packit 8f70b4
   status=RUNNING;
Packit 8f70b4
   term_info=-1;
Packit 8f70b4
   saved_errno=0;
Packit 8f70b4
Packit 8f70b4
   all_proc.add(proc_key(pid),this);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
ProcWait::~ProcWait()
Packit 8f70b4
{
Packit 8f70b4
   all_proc.remove(proc_key(pid));
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void ProcWait::Signal(bool yes)
Packit 8f70b4
{
Packit 8f70b4
   if(yes)
Packit 8f70b4
   {
Packit 8f70b4
      SignalHook::DoCount(SIGCHLD);   // select() will return -1 with EINTR
Packit 8f70b4
      SignalHook::Unblock(SIGCHLD);
Packit 8f70b4
   }
Packit 8f70b4
   else
Packit 8f70b4
      SignalHook::Block(SIGCHLD);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void ProcWait::DeleteAll()
Packit 8f70b4
{
Packit 8f70b4
   Signal(false);
Packit 8f70b4
   for(ProcWait *w=all_proc.each_begin(); w; w=all_proc.each_next())
Packit 8f70b4
      Delete(w);
Packit 8f70b4
}