/* ---------------------------------- * Startup Process main entry point * ---------------------------------- */ void StartupProcessMain(void) { /* * If possible, make this process a group leader, so that the postmaster * can signal any child processes too. */ #ifdef HAVE_SETSID if (setsid() < 0) elog(FATAL, "setsid() failed: %m"); #endif /* * Properly accept or ignore signals the postmaster might send us. */ pqsignal(SIGHUP, StartupProcSigHupHandler); /* reload config file */ pqsignal(SIGINT, SIG_IGN); /* ignore query cancel */ pqsignal(SIGTERM, StartupProcShutdownHandler); /* request shutdown */ pqsignal(SIGQUIT, startupproc_quickdie); /* hard crash time */ InitializeTimeouts(); /* establishes SIGALRM handler */ pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGUSR1, StartupProcSigUsr1Handler); pqsignal(SIGUSR2, StartupProcTriggerHandler); /* * Reset some signals that are accepted by postmaster but not here */ pqsignal(SIGCHLD, SIG_DFL); pqsignal(SIGTTIN, SIG_DFL); pqsignal(SIGTTOU, SIG_DFL); pqsignal(SIGCONT, SIG_DFL); pqsignal(SIGWINCH, SIG_DFL); /* * Register timeouts needed for standby mode */ RegisterTimeout(STANDBY_DEADLOCK_TIMEOUT, StandbyDeadLockHandler); RegisterTimeout(STANDBY_TIMEOUT, StandbyTimeoutHandler); /* * Unblock signals (they were blocked when the postmaster forked us) */ PG_SETMASK(&UnBlockSig); /* * Do what we came for. */ StartupXLOG(); /* * Exit normally. Exit code 0 tells postmaster that we completed recovery * successfully. */ proc_exit(0); }
/* * proc_exit callback to tear down the JVM */ static void _destroyJavaVM(int status, Datum dummy) { if(s_javaVM != 0) { Invocation ctx; #ifdef USE_PLJAVA_SIGHANDLERS #if PG_VERSION_NUM >= 90300 TimeoutId tid; #else pqsigfunc saveSigAlrm; #endif Invocation_pushInvocation(&ctx, false); if(sigsetjmp(recoverBuf, 1) != 0) { elog(DEBUG2, "needed to forcibly shut down the Java virtual machine"); s_javaVM = 0; return; } #if PG_VERSION_NUM >= 90300 InitializeTimeouts(); /* establishes SIGALRM handler */ tid = RegisterTimeout(USER_TIMEOUT, terminationTimeoutHandler); #else saveSigAlrm = pqsignal(SIGALRM, terminationTimeoutHandler); enable_sig_alarm(5000, false); #endif elog(DEBUG2, "shutting down the Java virtual machine"); JNI_destroyVM(s_javaVM); #if PG_VERSION_NUM >= 90300 disable_timeout(tid, false); #else disable_sig_alarm(false); pqsignal(SIGALRM, saveSigAlrm); #endif #else Invocation_pushInvocation(&ctx, false); elog(DEBUG2, "shutting down the Java virtual machine"); JNI_destroyVM(s_javaVM); #endif elog(DEBUG2, "done shutting down the Java virtual machine"); s_javaVM = 0; currentInvocation = 0; } }
void ContQuerySchedulerMain(int argc, char *argv[]) { sigjmp_buf local_sigjmp_buf; List *dbs = NIL; /* we are a postmaster subprocess now */ IsUnderPostmaster = true; am_cont_scheduler = true; /* reset MyProcPid */ MyProcPid = getpid(); MyPMChildSlot = AssignPostmasterChildSlot(); /* record Start Time for logging */ MyStartTime = time(NULL); /* Identify myself via ps */ init_ps_display("continuous query scheduler process", "", "", ""); ereport(LOG, (errmsg("continuous query scheduler started"))); if (PostAuthDelay) pg_usleep(PostAuthDelay * 1000000L); SetProcessingMode(InitProcessing); /* * If possible, make this process a group leader, so that the postmaster * can signal any child processes too. This is only for consistency sake, we * never fork the scheduler process. Instead dynamic bgworkers are used. */ #ifdef HAVE_SETSID if (setsid() < 0) elog(FATAL, "setsid() failed: %m"); #endif /* * Set up signal handlers. We operate on databases much like a regular * backend, so we use the same signal handling. See equivalent code in * tcop/postgres.c. */ pqsignal(SIGHUP, sighup_handler); pqsignal(SIGINT, sigint_handler); pqsignal(SIGTERM, sigterm_handler); pqsignal(SIGQUIT, quickdie); InitializeTimeouts(); /* establishes SIGALRM handler */ pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGUSR1, procsignal_sigusr1_handler); pqsignal(SIGUSR2, sigusr2_handler); pqsignal(SIGFPE, FloatExceptionHandler); pqsignal(SIGCHLD, SIG_DFL); #define BACKTRACE_SEGFAULTS #ifdef BACKTRACE_SEGFAULTS pqsignal(SIGSEGV, debug_segfault); #endif /* Early initialization */ BaseInit(); /* * Create a per-backend PGPROC struct in shared memory, except in the * EXEC_BACKEND case where this was done in SubPostmasterMain. We must do * this before we can use LWLocks (and in the EXEC_BACKEND case we already * had to do some stuff with LWLocks). */ #ifndef EXEC_BACKEND InitProcess(); #endif InitPostgres(NULL, InvalidOid, NULL, NULL); SetProcessingMode(NormalProcessing); /* * Create a memory context that we will do all our work in. We do this so * that we can reset the context during error recovery and thereby avoid * possible memory leaks. */ ContQuerySchedulerMemCxt = AllocSetContextCreate(TopMemoryContext, "ContQuerySchedulerCtx", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); MemoryContextSwitchTo(ContQuerySchedulerMemCxt); /* * If an exception is encountered, processing resumes here. * * This code is a stripped down version of PostgresMain error recovery. */ if (sigsetjmp(local_sigjmp_buf, 1) != 0) { /* since not using PG_TRY, must reset error stack by hand */ error_context_stack = NULL; /* Prevents interrupts while cleaning up */ HOLD_INTERRUPTS(); /* Forget any pending QueryCancel or timeout request */ disable_all_timeouts(false); QueryCancelPending = false; /* second to avoid race condition */ /* Report the error to the server log */ EmitErrorReport(); /* Abort the current transaction in order to recover */ AbortCurrentTransaction(); /* * Now return to normal top-level context and clear ErrorContext for * next time. */ MemoryContextSwitchTo(ContQuerySchedulerMemCxt); FlushErrorState(); /* Flush any leaked data in the top-level context */ MemoryContextResetAndDeleteChildren(ContQuerySchedulerMemCxt); /* Now we can allow interrupts again */ RESUME_INTERRUPTS(); /* * Sleep at least 1 second after any error. We don't want to be * filling the error logs as fast as we can. */ pg_usleep(1000000L); } /* We can now handle ereport(ERROR) */ PG_exception_stack = &local_sigjmp_buf; /* must unblock signals before calling rebuild_database_list */ PG_SETMASK(&UnBlockSig); ContQuerySchedulerShmem->scheduler_pid = MyProcPid; dbs = get_database_list(); /* Loop forever */ for (;;) { ListCell *lc; int rc; foreach(lc, dbs) { DatabaseEntry *db_entry = lfirst(lc); bool found; ContQueryProcGroup *grp = hash_search(ContQuerySchedulerShmem->proc_table, &db_entry->oid, HASH_ENTER, &found); /* If we don't have an entry for this dboid, initialize a new one and fire off bg procs */ if (!found) { grp->db_oid = db_entry->oid; namestrcpy(&grp->db_name, NameStr(db_entry->name)); start_group(grp); } } /* Allow sinval catchup interrupts while sleeping */ EnableCatchupInterrupt(); /* * Wait until naptime expires or we get some type of signal (all the * signal handlers will wake us by calling SetLatch). */ rc = WaitLatch(&MyProc->procLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0); ResetLatch(&MyProc->procLatch); DisableCatchupInterrupt(); /* * Emergency bailout if postmaster has died. This is to avoid the * necessity for manual cleanup of all postmaster children. */ if (rc & WL_POSTMASTER_DEATH) proc_exit(1); /* the normal shutdown case */ if (got_SIGTERM) break; /* update config? */ if (got_SIGHUP) { got_SIGHUP = false; ProcessConfigFile(PGC_SIGHUP); /* update tuning parameters, so that they can be read downstream by background processes */ update_tuning_params(); } /* terminate a proc group? */ if (got_SIGUSR2) { HASH_SEQ_STATUS status; ContQueryProcGroup *grp; got_SIGUSR2 = false; hash_seq_init(&status, ContQuerySchedulerShmem->proc_table); while ((grp = (ContQueryProcGroup *) hash_seq_search(&status)) != NULL) { ListCell *lc; if (!grp->terminate) continue; foreach(lc, dbs) { DatabaseEntry *entry = lfirst(lc); if (entry->oid == grp->db_oid) { dbs = list_delete(dbs, entry); break; } } terminate_group(grp); } }