44 *
55 * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
66 *
7- * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.80 2007/05/31 15:13:04 petere Exp $
7+ * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.81 2007/07/02 21:58:31 mha Exp $
88 *
99 *-------------------------------------------------------------------------
1010 */
@@ -126,11 +126,22 @@ static void WINAPI pgwin32_ServiceHandler(DWORD);
126126static void WINAPI pgwin32_ServiceMain (DWORD ,LPTSTR * );
127127static void pgwin32_doRunAsService (void );
128128static int CreateRestrictedProcess (char * cmd ,PROCESS_INFORMATION * processInfo );
129+
130+ static SERVICE_STATUS status ;
131+ static SERVICE_STATUS_HANDLE hStatus = (SERVICE_STATUS_HANDLE )0 ;
132+ static HANDLE shutdownHandles [2 ];
133+ static pid_t postmasterPID = -1 ;
134+
135+ #define shutdownEvent shutdownHandles[0]
136+ #define postmasterProcess shutdownHandles[1]
129137#endif
138+
130139static pgpid_t get_pgpid (void );
131140static char * * readfile (const char * path );
132- static int start_postmaster (void );
133- static bool test_postmaster_connection (void );
141+ static int start_postmaster (void );
142+ static void read_post_opts (void );
143+
144+ static bool test_postmaster_connection (bool );
134145static bool postmaster_is_alive (pid_t pid );
135146
136147static char def_postopts_file [MAXPGPATH ];
@@ -391,15 +402,20 @@ start_postmaster(void)
391402
392403
393404
394- /* Find the pgport and try a connection */
405+ /*
406+ * Find the pgport and try a connection
407+ * Note that the checkpoint parameter enables a Windows service control
408+ * manager checkpoint, it's got nothing to do with database checkpoints!!
409+ */
395410static bool
396- test_postmaster_connection (void )
411+ test_postmaster_connection (bool do_checkpoint )
397412{
398413PGconn * conn ;
399414bool success = false;
400415int i ;
401416char portstr [32 ];
402417char * p ;
418+ char connstr [128 ];/* Should be way more than enough! */
403419
404420* portstr = '\0' ;
405421
@@ -464,10 +480,12 @@ test_postmaster_connection(void)
464480if (!* portstr )
465481snprintf (portstr ,sizeof (portstr ),"%d" ,DEF_PGPORT );
466482
483+ /* We need to set a connect timeout otherwise on Windows the SCM will probably timeout first */
484+ snprintf (connstr ,sizeof (connstr ),"dbname=postgres port=%s connect_timeout=5" ,portstr );
485+
467486for (i = 0 ;i < wait_seconds ;i ++ )
468487{
469- if ((conn = PQsetdbLogin (NULL ,portstr ,NULL ,NULL ,
470- "postgres" ,NULL ,NULL ))!= NULL &&
488+ if ((conn = PQconnectdb (connstr ))!= NULL &&
471489(PQstatus (conn )== CONNECTION_OK ||
472490 (strcmp (PQerrorMessage (conn ),
473491PQnoPasswordSupplied )== 0 )))
@@ -479,7 +497,25 @@ test_postmaster_connection(void)
479497else
480498{
481499PQfinish (conn );
482- print_msg ("." );
500+
501+ #if defined(WIN32 )
502+ if (do_checkpoint )
503+ {
504+ /*
505+ * Increment the wait hint by 6 secs (connection timeout + sleep)
506+ * We must do this to indicate to the SCM that our startup time is
507+ * changing, otherwise it'll usually send a stop signal after 20
508+ * seconds, despite incrementing the checkpoint counter.
509+ */
510+ status .dwWaitHint += 6000 ;
511+ status .dwCheckPoint ++ ;
512+ SetServiceStatus (hStatus , (LPSERVICE_STATUS )& status );
513+ }
514+
515+ else
516+ #endif
517+ print_msg ("." );
518+
483519pg_usleep (1000000 );/* 1 sec */
484520}
485521}
@@ -508,24 +544,10 @@ unlimit_core_size(void)
508544}
509545#endif
510546
511-
512-
513547static void
514- do_start (void )
548+ read_post_opts (void )
515549{
516- pgpid_t pid ;
517- pgpid_t old_pid = 0 ;
518550char * optline = NULL ;
519- int exitcode ;
520-
521- if (ctl_command != RESTART_COMMAND )
522- {
523- old_pid = get_pgpid ();
524- if (old_pid != 0 )
525- write_stderr (_ ("%s: another server might be running; "
526- "trying to start server anyway\n" ),
527- progname );
528- }
529551
530552if (post_opts == NULL )
531553{
@@ -536,7 +558,7 @@ do_start(void)
536558postopts_file :def_postopts_file );
537559if (optlines == NULL )
538560{
539- if (ctl_command == START_COMMAND )
561+ if (ctl_command == START_COMMAND || ctl_command == RUN_AS_SERVICE_COMMAND )
540562post_opts = "" ;
541563else
542564{
@@ -576,6 +598,25 @@ do_start(void)
576598post_opts = optline ;
577599}
578600}
601+ }
602+
603+ static void
604+ do_start (void )
605+ {
606+ pgpid_t pid ;
607+ pgpid_t old_pid = 0 ;
608+ int exitcode ;
609+
610+ if (ctl_command != RESTART_COMMAND )
611+ {
612+ old_pid = get_pgpid ();
613+ if (old_pid != 0 )
614+ write_stderr (_ ("%s: another server might be running; "
615+ "trying to start server anyway\n" ),
616+ progname );
617+ }
618+
619+ read_post_opts ();
579620
580621/* No -D or -D already added during server start */
581622if (ctl_command == RESTART_COMMAND || pgdata_opt == NULL )
@@ -642,7 +683,7 @@ do_start(void)
642683{
643684print_msg (_ ("waiting for server to start..." ));
644685
645- if (test_postmaster_connection ()== false)
686+ if (test_postmaster_connection (false )== false)
646687{
647688printf (_ ("could not start server\n" ));
648689exit (1 );
@@ -982,7 +1023,7 @@ pgwin32_CommandLine(bool registration)
9821023strcat (cmdLine ,"\"" );
9831024}
9841025
985- if (do_wait )
1026+ if (registration && do_wait )
9861027strcat (cmdLine ," -w" );
9871028
9881029if (post_opts )
@@ -1065,15 +1106,6 @@ pgwin32_doUnregister(void)
10651106CloseServiceHandle (hSCM );
10661107}
10671108
1068-
1069- static SERVICE_STATUS status ;
1070- static SERVICE_STATUS_HANDLE hStatus = (SERVICE_STATUS_HANDLE )0 ;
1071- static HANDLE shutdownHandles [2 ];
1072- static pid_t postmasterPID = -1 ;
1073-
1074- #define shutdownEvent shutdownHandles[0]
1075- #define postmasterProcess shutdownHandles[1]
1076-
10771109static void
10781110pgwin32_SetServiceStatus (DWORD currentState )
10791111{
@@ -1118,6 +1150,7 @@ pgwin32_ServiceMain(DWORD argc, LPTSTR * argv)
11181150{
11191151PROCESS_INFORMATION pi ;
11201152DWORD ret ;
1153+ DWORD check_point_start ;
11211154
11221155/* Initialize variables */
11231156status .dwWin32ExitCode = S_OK ;
@@ -1130,6 +1163,8 @@ pgwin32_ServiceMain(DWORD argc, LPTSTR * argv)
11301163
11311164memset (& pi ,0 ,sizeof (pi ));
11321165
1166+ read_post_opts ();
1167+
11331168/* Register the control request handler */
11341169if ((hStatus = RegisterServiceCtrlHandler (register_servicename ,pgwin32_ServiceHandler ))== (SERVICE_STATUS_HANDLE )0 )
11351170return ;
@@ -1147,10 +1182,27 @@ pgwin32_ServiceMain(DWORD argc, LPTSTR * argv)
11471182postmasterPID = pi .dwProcessId ;
11481183postmasterProcess = pi .hProcess ;
11491184CloseHandle (pi .hThread );
1185+
1186+ if (do_wait )
1187+ {
1188+ write_eventlog (EVENTLOG_INFORMATION_TYPE ,_ ("Waiting for server startup...\n" ));
1189+ if (test_postmaster_connection (true)== false)
1190+ {
1191+ write_eventlog (EVENTLOG_INFORMATION_TYPE ,_ ("Timed out waiting for server startup\n" ));
1192+ pgwin32_SetServiceStatus (SERVICE_STOPPED );
1193+ return ;
1194+ }
1195+ write_eventlog (EVENTLOG_INFORMATION_TYPE ,_ ("Server started and accepting connections\n" ));
1196+ }
1197+
1198+ /* Save the checkpoint value as it might have been incremented in test_postmaster_connection */
1199+ check_point_start = status .dwCheckPoint ;
1200+
11501201pgwin32_SetServiceStatus (SERVICE_RUNNING );
11511202
11521203/* Wait for quit... */
11531204ret = WaitForMultipleObjects (2 ,shutdownHandles , FALSE,INFINITE );
1205+
11541206pgwin32_SetServiceStatus (SERVICE_STOP_PENDING );
11551207switch (ret )
11561208{