cygrunsrv patch for system shutdown handling - Mailing list pgsql-cygwin
From | Fred Yankowski |
---|---|
Subject | cygrunsrv patch for system shutdown handling |
Date | |
Msg-id | 3B2A666C.932B5FB7@ontosys.com Whole thread Raw |
List | pgsql-cygwin |
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@OntoSys.com tel: +1.630.879.1312 Principal Consultant www.OntoSys.com fax: +1.630.879.1370 OntoSys, Inc 38W242 Deerpath Rd, Batavia, IL 60510, USAIndex: 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/<svc_name>.log."); uprint (" -2, --stderr <file> Optional output file used for stderr redirection."); uprint (" Default is /var/log/<svc_name>.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, 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 <fred@ontosys.com> + + * 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 <corinna@vinschen.de> * cygrunsrv.cc (longopts): Add `--chdir' option.
pgsql-cygwin by date: