Blame src/ProcWait.cc

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