Mailing-List: contact cygwin-apps-help AT sourceware DOT cygnus DOT com; run by ezmlm Sender: cygwin-apps-owner AT sourceware DOT cygnus DOT com List-Subscribe: List-Archive: List-Post: List-Help: , Delivered-To: mailing list cygwin-apps AT sources DOT redhat DOT com Message-ID: <3B2A666C.932B5FB7@ontosys.com> Date: Fri, 15 Jun 2001 14:47:56 -0500 From: Fred Yankowski X-Mailer: Mozilla 4.76 [en] (WinNT; U) X-Accept-Language: en MIME-Version: 1.0 To: cygwin-apps AT cygwin DOT com Cc: pgsql-cygwin AT postgresql DOT org Subject: cygrunsrv patch for system shutdown handling References: <20010517161408 DOT A60686 AT enteract DOT com> <20010518101617 DOT B31266 AT cygbert DOT vinschen DOT de> <20010518103001 DOT A61059 AT enteract DOT com> <20010518182956 DOT D31266 AT cygbert DOT vinschen DOT de> Content-Type: multipart/mixed; boundary="------------4B8487E3562AF76A6AD717ED" This is a multi-part message in MIME format. --------------4B8487E3562AF76A6AD717ED Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Attached is a patch to cygrunsrv that adds an optional feature where cygrunsrv accepts SERVICE_CONTROL_SHUTDOWN notifications from the Service Control Manager and explicitly terminates the managed application process on receipt of such a notification. This gives the application a chance to shutdown cleanly, just as it does during a manual stop ("net stop"). This feature is useful with the Cygwin port of PostgreSQL. Without this feature it seems that the abrupt termination of the postmaster process during system shutdown leaves the PostgreSQL data in a state where postmaster cannot start up without manual intervention (the postmaster.pid file, in particular). Note that postmaster/postgres must also ignore SIGHUP signals for this to work -- a separate patch. The bulk of the patch is the usual stuff to enable a new command line option and manage the registry value. The interesting part of the code is merely the new set_service_controls_accepted() function that enables the service to accept the shutdown control, and the change to service_handler() that treats the SERVICE_CONTROL_SHUTDOWN notification exactly like SERVICE_CONTROL_STOP. More elaborate handling of the shutdown case is possible, such as sending STOP_PENDING messages until the managed process actually terminates, but in practice this simple scheme works just fine (for PostgreSQL at least). -- Fred Yankowski fred AT OntoSys DOT com tel: +1.630.879.1312 Principal Consultant www.OntoSys.com fax: +1.630.879.1370 OntoSys, Inc 38W242 Deerpath Rd, Batavia, IL 60510, USA --------------4B8487E3562AF76A6AD717ED Content-Type: text/plain; charset=us-ascii; name="cygrunsrv.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="cygrunsrv.diff" Index: crit.cc =================================================================== RCS file: /home/cvs/cvsroot/src/cygrunsrv/crit.cc,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 crit.cc --- crit.cc 2001/05/18 20:10:32 1.1.1.1 +++ crit.cc 2001/06/15 19:19:43 @@ -69,4 +69,16 @@ set_service_status (DWORD state, DWORD c LeaveCriticalSection (&ssc); } - +void +set_service_controls_accepted (bool accept_shutdown) +{ + EnterCriticalSection (&ssc); + if (ssh) + { + ss.dwControlsAccepted = SERVICE_ACCEPT_STOP; + if (accept_shutdown) + ss.dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN; + SetServiceStatus(ssh, &ss); + } + LeaveCriticalSection (&ssc); +} Index: crit.h =================================================================== RCS file: /home/cvs/cvsroot/src/cygrunsrv/crit.h,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 crit.h --- crit.h 2001/05/18 20:10:32 1.1.1.1 +++ crit.h 2001/06/15 19:19:43 @@ -29,5 +29,6 @@ extern void set_service_status (DWORD st DWORD check_point = 0, DWORD wait_hint = 0, DWORD exit_code = NO_ERROR); +extern void set_service_controls_accepted(bool shutdown); #endif /* _CRIT_H */ Index: cygrunsrv.cc =================================================================== RCS file: /home/cvs/cvsroot/src/cygrunsrv/cygrunsrv.cc,v retrieving revision 1.7 diff -u -p -r1.7 cygrunsrv.cc --- cygrunsrv.cc 2001/05/31 16:09:09 1.7 +++ cygrunsrv.cc 2001/06/15 19:19:44 @@ -63,16 +63,18 @@ struct option longopts[] = { { "stdin", required_argument, NULL, '0' }, { "stdout", required_argument, NULL, '1' }, { "stderr", required_argument, NULL, '2' }, + { "shutdown", no_argument, NULL, 'o' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { 0, no_argument, NULL, 0 } }; -char *opts = "I:R:S:E:p:a:c:e:d:u:w:t:s:y:0:1:2:hv"; +char *opts = "I:R:S:E:p:a:c:e:d:ou:w:t:s:y:0:1:2:hv"; char *appname; char *svcname; DWORD termsig; +DWORD shutdown; enum action_t { Undefined, @@ -124,7 +126,7 @@ int install_registry_keys (const char *name, const char *path, char *args, char *dir, env_t *env, DWORD termsig, const char *in_stdin, const char *in_stdout, - const char *in_stderr) + const char *in_stderr, DWORD shutdown) { HKEY srv_key = NULL; HKEY env_key = NULL; @@ -181,6 +183,11 @@ install_registry_keys (const char *name, (const BYTE *) in_stderr, strlen (in_stderr) + 1) != ERROR_SUCCESS) err_out (RegSetValueEx); + if (shutdown) + if (RegSetValueEx (srv_key, PARAM_SHUTDOWN, 0, REG_DWORD, + (const BYTE *) &shutdown, + sizeof(DWORD)) != ERROR_SUCCESS) + err_out (RegSetValueEx); RegFlushKey (srv_key); out: @@ -248,7 +255,8 @@ reeval_io_path (int fd, char *&io_path, int get_reg_entries (const char *name, char *&path, char *&args, char *&dir, env_t *&env, DWORD *termsig_p, - char *&stdin_path, char *&stdout_path, char *&stderr_path) + char *&stdin_path, char *&stdout_path, char *&stderr_path, + DWORD *shutdown_p) { HKEY srv_key = NULL; HKEY env_key = NULL; @@ -283,6 +291,11 @@ get_reg_entries (const char *name, char (BYTE *) termsig_p, (size = sizeof(*termsig_p), &size)) != ERROR_SUCCESS) *termsig_p = SIGTERM; // the default + /* Get (optional) shutdown flag. */ + if (RegQueryValueEx (srv_key, PARAM_SHUTDOWN, 0, &type, + (BYTE *) shutdown_p, + (size = sizeof(*shutdown_p), &size)) != ERROR_SUCCESS) + *shutdown_p = 0; // the default /* Get (optional) stdin/stdout/stderr redirection files. */ if ((ret = get_opt_string_entry (srv_key, PARAM_STDIN, stdin_path))) goto out; @@ -820,6 +833,7 @@ service_handler (DWORD ctrl) switch (ctrl) { case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: /* Since the service_handler doesn't run in the same thread as the service_main routine, it has to setup exception handling. */ exception_list except_list; @@ -895,13 +909,15 @@ service_main (DWORD argc, LPSTR *argv) char *stdout_path = NULL; char *stderr_path = NULL; if (err = get_reg_entries (svcname, path, args, dir, env, &termsig, - stdin_path, stdout_path, stderr_path)) + stdin_path, stdout_path, stderr_path, + &shutdown)) { syslog_starterr ("get_reg_entries", err); set_service_status (SERVICE_STOPPED, 0, 0, err); return; } + set_service_controls_accepted ( shutdown ); report_service_status (); /* Step 2: Further preparations: @@ -1026,6 +1042,7 @@ main (int argc, char **argv) char *in_stdin = NULL; char *in_stdout = NULL; char *in_stderr = NULL; + int in_shutdown = 0; appname = argv[0]; @@ -1107,6 +1124,13 @@ main (int argc, char **argv) return error (OnlyOneDisp); in_disp = optarg; break; + case 'o': + if (action != Install) + return error (ShutdownNotAllowed); + if (in_shutdown) + return error (OnlyOneShutdown); + in_shutdown = 1; + break; case 's': if (action != Install) return error (SigNotAllowed); @@ -1199,7 +1223,8 @@ main (int argc, char **argv) return ret; if (ret = install_registry_keys (in_name, in_path, in_args, in_dir, in_env, in_termsig, - in_stdin, in_stdout, in_stderr)) + in_stdin, in_stdout, in_stderr, + in_shutdown)) remove_service (in_name); return ret; break; Index: cygrunsrv.h =================================================================== RCS file: /home/cvs/cvsroot/src/cygrunsrv/cygrunsrv.h,v retrieving revision 1.6 diff -u -p -r1.6 cygrunsrv.h --- cygrunsrv.h 2001/05/31 16:09:09 1.6 +++ cygrunsrv.h 2001/06/15 19:19:44 @@ -31,6 +31,7 @@ #define PARAM_STDERR "StdErr" #define PARAM_ENVIRON "Environment" #define PARAM_TERMSIG "TermSig" +#define PARAM_SHUTDOWN "Shutdown" #define DEF_STDIN_PATH "/dev/null" #define DEF_LOG_PATH "/var/log/" Index: utils.cc =================================================================== RCS file: /home/cvs/cvsroot/src/cygrunsrv/utils.cc,v retrieving revision 1.6 diff -u -p -r1.6 utils.cc --- utils.cc 2001/05/31 16:09:09 1.6 +++ utils.cc 2001/06/15 19:19:44 @@ -57,6 +57,8 @@ char *reason_list[] = { "--dep is only allowed with --install", "--std{in,out,err} are only allowed with --install", "Each of --std{in,out,err} is allowed only once", + "--shutdown is only allowed with --install", + "Only one --shutdown is allowed", "Trailing commandline arguments not allowed", "You must specify one of the `-IRSE' options", "Error installing a service", @@ -159,6 +161,7 @@ usage () uprint (" Default is /var/log/.log."); uprint (" -2, --stderr Optional output file used for stderr redirection."); uprint (" Default is /var/log/.log."); + uprint (" -o, --shutdown Stop service application during system shutdown."); uprint ("\nInformative output:"); uprint (" -h, --help print this help, then exit."); uprint (" -v, --version print cygrunsrv program version number, then exit."); Index: utils.h =================================================================== RCS file: /home/cvs/cvsroot/src/cygrunsrv/utils.h,v retrieving revision 1.5 diff -u -p -r1.5 utils.h --- utils.h 2001/05/31 16:09:09 1.5 +++ utils.h 2001/06/15 19:19:44 @@ -48,6 +48,8 @@ enum reason_t { DepNotAllowed, IONotAllowed, OnlyOneIO, + ShutdownNotAllowed, + OnlyOneShutdown, TrailingArgs, StartAsSvcErr, InstallErr, --------------4B8487E3562AF76A6AD717ED Content-Type: text/plain; charset=us-ascii; name="cygrunsrv.changelog" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="cygrunsrv.changelog" Index: ChangeLog =================================================================== RCS file: /home/cvs/cvsroot/src/cygrunsrv/ChangeLog,v retrieving revision 1.11 diff -u -p -r1.11 ChangeLog --- ChangeLog 2001/05/31 16:09:09 1.11 +++ ChangeLog 2001/06/15 19:19:43 @@ -1,3 +1,24 @@ +2001-06-15 Fred Yankowski + + * utils.h (reason_t): Add codes for --shutdown errors. + * utils.cc (reason_list): Add error strings for --shutdown. + (usage): Add help text for --shutdown option. + * cygrunsrv.h (PARAM_SHUTDOWN): New registry name for shutdown + parameter. + * cygrunsrv.cc (longopts): Add '--shutdown' option. + (opts): Add '-o' option. + (shutdown): Define new global. + (install_registry_keys): Add 'shutdown' parameter, and writing + parameter to registry. + (get_reg_entries): Add 'shutdown_p' parameter and reading + parameter from registry. + (service_handler): Case for SERVICE_CONTROL_SHUTDOWN control. + (service_main): Set global 'shutdown' parameter, and call + set_service_controls_accepted. + (main): Add handling for '--shutdown' parameter. + * crit.h (set_service_controls_accepted): Declare new function. + * crit.cc (set_service_controls_accepted): New function. + 2001-05-31 Corinna Vinschen * cygrunsrv.cc (longopts): Add `--chdir' option. --------------4B8487E3562AF76A6AD717ED--