This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Suggest cygrunsrv extension: --pidfile option (patch included)


On Nov 20 17:58, Christian Franke wrote:
> Hi,
> 
> when porting new daemons to Cygwin, it is necessary to add a Cygwin 
> specific option to prevent fork()ing.
> Otherwise, running as service via cygrunsrv would not be possible.
> 
> For daemons which are able to write /var/run/daemon.pid files, this pid 
> can be used to track the daemon.
> 
> Suggest adding a --pidfile option to cygrunsrv for this purpose:
> 
>  cygrunsrv -I syslogd --pidfile /var/run/syslog.pid -p /usr/sbin/syslogd
> 
> (Yes, "-a -D" is missing)
> 
> 
> For a working prototype, try { this->patch->here; }
> 
> http://franke.dvrdns.org/cygwin/cygrunsrv-pidfile-patch.txt
> 
> Note that the patch contains a new module with a waitanypid() function.
> This was necessary (tell me if I missed something) because waitpid() 
> cannot wait for child's childs.
> 
> Thanks for any comment

I like the idea and I would like to incorporate this change into
cygrunsrv, but I have some nits.

First, and MOST important ;-), you missed to add a ChangeLog entry.
Please create one.

For the other nits I have to refer to your patch, which I partly
inline here:


  @@ -1265,7 +1281,7 @@
   #undef err_out
   #undef err_out_set_error
   
  -int server_pid;
  +int terminate_pid;

I don't see a reason to change the name of this variable.  server_pid is
still correct, so I'd rather keep it.

 
  @@ -1461,8 +1499,19 @@
   
     report_service_status ();
   
  +  /* Save time if old pid file exists */
  +  time_t forktime = 0;
  +  if (pidfile_path && !access(pidfile_path, 0))
  +    {
  +      syslog (LOG_INFO, "service `%s': old pid file %s exists",
  +	svcname, pidfile_path);
  +      forktime = time(0);
  +      sleep(1);
  +    }
  +

How do you save time here?!?  This looks confusing.  If an old pid file
exists, then either the (or some) service process is still running, or
the service died without removing the pid file.  Some processes also refuse
to start if a pid file still exists.  Bottom line, shouldn't the existence
of the pid file result in complaining with LOG_ERR and exiting?

  +	    {
  +	     /* Daemon has fork()ed successfully, wait for pidfile */
  +	     int read_pid;
  +	     for (i = 1; i <= 30; i++) {
  +	       if ((read_pid = read_pidfile (pidfile_path, forktime)) != -1)
  +		 break;
  +	       syslog (LOG_INFO, "service `%s': waiting for file %s (#%d)",
  +		 svcname, pidfile_path, i);
  +	       sleep(1);
  +	     }

I'm missing a call to report_service_status here.  The dwWaitHint member is
set to 5 seconds, but this code waits up to 30 seconds without calling
report_service_status.  Looks like potential trouble.

  +	     if (read_pid != -1) 
  +	       {
  +		 /* Got the real pid, daemon now running  */
  +		 terminate_pid = read_pid; /* terminate this pid (pgrp unknown) */

Instead of using the process pid, why not retrieving the pgid of the 
service process from /proc/$pid/pgid, same as you get the winpid?
This would also allow to keep the terminate_child function untouched.

  -	    case ECHILD:
  +	    case ECHILD: case ESRCH:

I'd rather have this on two lines.

+//
+// Convert Cygwin pid into Windows pid
+// Returns windows pid, or -1 on error
+//

Could you please convert all comments to plain C /* */ comments?

  +static int
  +pid_to_winpid(pid_t pid)
  +{
  +  char path[100];
  +  sprintf(path, "/proc/%d/winpid", pid);
  +  FILE * f = fopen(path, "r");
  +  if (!f)
  +    return -1;
  +  int winpid = -1;
  +  fscanf(f, "%d", &winpid);
  +  fclose(f);
  +  return winpid;
  +}
  +
  +#else // NO_PROC
  +
  +// Another approach without using /proc
  +#include <psapi.h> // EnumProcesses(), link with -lpsapi
  +#include <sys/cygwin.h> 
  +
  +static int
  +pid_to_winpid(pid_t pid)
  +{
  +  DWORD winpids[1000], nb;
  +  if (!EnumProcesses(winpids, sizeof(winpids), &nb))
  +    return 0;
  +  int n = nb / sizeof(DWORD);
  +
  +  int olderrno = errno;
  +  int winpid = -1;
  +  for (int i = 0; i < n; i++) {
  +    if (cygwin_winpid_to_pid(winpids[i]) == pid) {
  +      winpid = winpids[i];
  +      errno = olderrno;
  +      break;
  +    }
  +  }
  +  return winpid;
  +}

I think I'd prefer the variation reading /proc.  It's more Cygwin :-)


That's all.  Did I mention that I really like this patch?


Thanks,
Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat, Inc.

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Problem reports:       http://cygwin.com/problems.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]