📄 postmaster.c
字号:
int exitstatus) /* child's exit status. */{ Dlelem *prev, *curr; Backend *bp; int sig; if (DebugLvl) { fprintf(stderr, "%s: CleanupProc: pid %d exited with status %d\n", progname, pid, exitstatus); } /* * If a backend dies in an ugly way (i.e. exit status not 0) then we * must signal all other backends to quickdie. If exit status is zero * we assume everything is hunky dory and simply remove the backend * from the active backend list. */ if (!exitstatus) { curr = DLGetHead(BackendList); while (curr) { bp = (Backend *) DLE_VAL(curr); if (bp->pid == pid) { DLRemove(curr); free(bp); DLFreeElem(curr); break; } curr = DLGetSucc(curr); } ProcRemove(pid); return; } curr = DLGetHead(BackendList); while (curr) { bp = (Backend *) DLE_VAL(curr); /* ----------------- * SIGUSR1 is the special signal that says exit * without proc_exit and let the user know what's going on. * ProcSemaphoreKill() cleans up the backends semaphore. If * SendStop is set (-s on command line), then we send a SIGSTOP so * that we can core dumps from all backends by hand. * ----------------- */ sig = (SendStop) ? SIGSTOP : SIGUSR1; if (bp->pid != pid) { if (DebugLvl) fprintf(stderr, "%s: CleanupProc: sending %s to process %d\n", progname, (sig == SIGUSR1) ? "SIGUSR1" : "SIGSTOP", bp->pid); kill(bp->pid, sig); } ProcRemove(bp->pid); prev = DLGetPred(curr); DLRemove(curr); free(bp); DLFreeElem(curr); if (!prev) { /* removed head */ curr = DLGetHead(BackendList); continue; } curr = DLGetSucc(prev); } /* * Nothing up my sleeve here, ActiveBackends means that since the last * time we recreated shared memory and sems another frontend has * requested and received a connection and I have forked off another * backend. This prevents me from reinitializing shared stuff more * than once for the set of backends that caused the failure and were * killed off. */ if (ActiveBackends == TRUE && Reinit) { if (DebugLvl) fprintf(stderr, "%s: CleanupProc: reinitializing shared memory and semaphores\n", progname); shmem_exit(0); reset_shared(PostPortName); }}/* * Send a signal to all chidren processes. */static voidSignalChildren(int signal){ Dlelem *curr, *next; Backend *bp; int mypid = getpid(); curr = DLGetHead(BackendList); while (curr) { next = DLGetSucc(curr); bp = (Backend *) DLE_VAL(curr); if (bp->pid != mypid) { TPRINTF(TRACE_VERBOSE, "SignalChildren: sending signal %d to process %d", signal, bp->pid); kill(bp->pid, signal); } curr = next; }}/* * BackendStartup -- start backend process * * returns: STATUS_ERROR if the fork/exec failed, STATUS_OK * otherwise. * */static intBackendStartup(Port *port){ Backend *bn; /* for backend cleanup */ int pid, i;#ifdef CYR_RECODE#define NR_ENVIRONMENT_VBL 6 char ChTable[80];#else#define NR_ENVIRONMENT_VBL 5#endif static char envEntry[NR_ENVIRONMENT_VBL][2 * ARGV_SIZE]; for (i = 0; i < NR_ENVIRONMENT_VBL; ++i) MemSet(envEntry[i], 0, 2 * ARGV_SIZE); /* * Set up the necessary environment variables for the backend This * should really be some sort of message.... */ sprintf(envEntry[0], "POSTPORT=%d", PostPortName); putenv(envEntry[0]); sprintf(envEntry[1], "POSTID=%d", NextBackendTag); putenv(envEntry[1]); sprintf(envEntry[2], "PG_USER=%s", port->user); putenv(envEntry[2]); if (!getenv("PGDATA")) { sprintf(envEntry[3], "PGDATA=%s", DataDir); putenv(envEntry[3]); } sprintf(envEntry[4], "IPC_KEY=%d", ipc_key); putenv(envEntry[4]);#ifdef CYR_RECODE GetCharSetByHost(ChTable, port->raddr.in.sin_addr.s_addr, DataDir); if (*ChTable != '\0') { sprintf(envEntry[5], "PG_RECODETABLE=%s", ChTable); putenv(envEntry[5]); }#endif /* * Compute the cancel key that will be assigned to this backend. The * backend will have its own copy in the forked-off process' value of * MyCancelKey, so that it can transmit the key to the frontend. */ MyCancelKey = PostmasterRandom(); if (DebugLvl > 2) { char **p; extern char **environ; fprintf(stderr, "%s: BackendStartup: environ dump:\n", progname); fprintf(stderr, "-----------------------------------------\n"); for (p = environ; *p; ++p) fprintf(stderr, "\t%s\n", *p); fprintf(stderr, "-----------------------------------------\n"); } /* * Flush stdio channels just before fork, to avoid double-output * problems. Ideally we'd use fflush(NULL) here, but there are still a * few non-ANSI stdio libraries out there (like SunOS 4.1.x) that * coredump if we do. Presently stdout and stderr are the only stdio * output channels used by the postmaster, so fflush'ing them should * be sufficient. */ fflush(stdout); fflush(stderr); if ((pid = fork()) == 0) { /* child */ if (DoBackend(port)) { fprintf(stderr, "%s child[%d]: BackendStartup: backend startup failed\n", progname, (int) getpid()); exit(1); } else exit(0); } /* in parent */ if (pid < 0) { fprintf(stderr, "%s: BackendStartup: fork failed: %s\n", progname, strerror(errno)); return STATUS_ERROR; } if (DebugLvl) fprintf(stderr, "%s: BackendStartup: pid %d user %s db %s socket %d\n", progname, pid, port->user, port->database, port->sock); /* Generate a new backend tag for every backend we start */ /* * XXX theoretically this could wrap around, if you have the patience * to start 2^31 backends ... */ NextBackendTag -= 1; /* * Everything's been successful, it's safe to add this backend to our * list of backends. */ if (!(bn = (Backend *) calloc(1, sizeof(Backend)))) { fprintf(stderr, "%s: BackendStartup: malloc failed\n", progname); ExitPostmaster(1); } bn->pid = pid; bn->cancel_key = MyCancelKey; DLAddHead(BackendList, DLNewElem(bn)); ActiveBackends = TRUE; return STATUS_OK;}/* * split_opts -- split a string of options and append it to an argv array * * NB: the string is destructively modified! * * Since no current POSTGRES arguments require any quoting characters, * we can use the simple-minded tactic of assuming each set of space- * delimited characters is a separate argv element. * * If you don't like that, well, we *used* to pass the whole option string * as ONE argument to execl(), which was even less intelligent... */static voidsplit_opts(char **argv, int *argcp, char *s){ int i = *argcp; while (s && *s) { while (isspace(*s)) ++s; if (*s == '\0') break; argv[i++] = s; while (*s && !isspace(*s)) ++s; if (*s) *s++ = '\0'; } *argcp = i;}/* * DoBackend -- set up the backend's argument list and invoke backend main(). * * This used to perform an execv() but we no longer exec the backend; * it's the same executable as the postmaster. * * returns: * Shouldn't return at all. * If PostgresMain() fails, return status. */static intDoBackend(Port *port){ char *av[ARGV_SIZE * 2]; int ac = 0; char execbuf[MAXPATHLEN]; char debugbuf[ARGV_SIZE]; char protobuf[ARGV_SIZE]; char dbbuf[ARGV_SIZE]; char optbuf[ARGV_SIZE]; char ttybuf[ARGV_SIZE]; int i; struct timeval now; struct timezone tz; /* * Let's clean up ourselves as the postmaster child */ /* We don't want the postmaster's proc_exit() handlers */ on_exit_reset(); /* ---------------- * register signal handlers. * Thanks to the postmaster, these are currently blocked. * ---------------- */ pqsignal(SIGINT, die); pqsignal(SIGHUP, die); pqsignal(SIGTERM, die); pqsignal(SIGPIPE, die); pqsignal(SIGUSR1, quickdie); pqsignal(SIGUSR2, Async_NotifyHandler); pqsignal(SIGFPE, FloatExceptionHandler); pqsignal(SIGCHLD, SIG_DFL); pqsignal(SIGTTIN, SIG_DFL); pqsignal(SIGTTOU, SIG_DFL); pqsignal(SIGCONT, SIG_DFL); /* OK, let's unblock our signals, all together now... */ sigprocmask(SIG_SETMASK, &oldsigmask, 0); /* Close the postmaster sockets */ if (NetServer) StreamClose(ServerSock_INET);#ifndef __CYGWIN32__ StreamClose(ServerSock_UNIX);#endif /* Save port etc. for ps status */ MyProcPort = port; MyProcPid = getpid(); /* * Don't want backend to be able to see the postmaster random number * generator state. We have to clobber the static random_seed *and* * start a new random sequence in the random() library function. */ random_seed = 0; gettimeofday(&now, &tz); srandom(now.tv_usec); /* ---------------- * Now, build the argv vector that will be given to PostgresMain. * * The layout of the command line is * postgres [secure switches] -p databasename [insecure switches] * where the switches after -p come from the client request. * ---------------- */ StrNCpy(execbuf, Execfile, MAXPATHLEN); av[ac++] = execbuf; /* * We need to set our argv[0] to an absolute path name because some * OS's use this for dynamic loading, like BSDI. Without it, when we * change directories to the database dir, the dynamic loader can't * find the base executable and fails. Another advantage is that this * changes the 'ps' displayed process name on some platforms. It does * on BSDI. That's a big win. */#ifndef linux /* * This doesn't work on linux and overwrites the only valid pointer to * the argv buffer. See PS_INIT_STATUS macro. */ real_argv[0] = Execfile;#endif /* * Pass the requested debugging level along to the backend. We * decrement by one; level one debugging in the postmaster traces * postmaster connection activity, and levels two and higher are * passed along to the backend. This allows us to watch only the * postmaster or the postmaster and the backend. */ if (DebugLvl > 1) { sprintf(debugbuf, "-d%d", DebugLvl); av[ac++] = debugbuf; } /* * Pass any backend switches specified with -o in the postmaster's own * command line. We assume these are secure. (It's OK to mangle * ExtraOptions since we are now in the child process; this won't * change the postmaster's copy.) */ split_opts(av, &ac, ExtraOptions); /* Tell the backend what protocol the frontend is using. */ sprintf(protobuf, "-v%u", port->proto); av[ac++] = protobuf; /* * Tell the backend it is being called from the postmaster, and which * database to use. -p marks the end of secure switches. */ av[ac++] = "-p"; StrNCpy(dbbuf, port->database, ARGV_SIZE); av[ac++] = dbbuf; /* * Pass the (insecure) option switches from the connection request. */ StrNCpy(optbuf, port->options, ARGV_SIZE); split_opts(av, &ac, optbuf); /* * Pass the (insecure) debug output file request. * * NOTE: currently, this is useless code, since the backend will not * honor an insecure -o switch. I left it here since the backend * could be modified to allow insecure -o, given adequate checking * that the specified filename is something safe to write on. */ if (port->tty[0]) { StrNCpy(ttybuf, port->tty, ARGV_SIZE); av[ac++] = "-o"; av[ac++] = ttybuf; } av[ac] = (char *) NULL; if (DebugLvl > 1) { fprintf(stderr, "%s child[%d]: starting with (", progname, MyProcPid); for (i = 0; i < ac; ++i) fprintf(stderr, "%s ", av[i]); fprintf(stderr, ")\n"); } return (PostgresMain(ac, av, real_argc, real_argv));}/* * ExitPostmaster -- cleanup */static voidExitPostmaster(int status){ /* should cleanup shared memory and kill all backends */ /* * Not sure of the semantics here. When the Postmaster dies, should * the backends all be killed? probably not. */ if (ServerSock_INET != INVALID_SOCK) StreamClose(ServerSock_INET);#ifndef __CYGWIN32__ if (ServerSock_UNIX != INVALID_SOCK) StreamClose(ServerSock_UNIX);#endif proc_exit(status);}static voiddumpstatus(SIGNAL_ARGS){ Dlelem *curr = DLGetHead(PortList); while (curr) { Port *port = DLE_VAL(curr); fprintf(stderr, "%s: dumpstatus:\n", progname); fprintf(stderr, "\tsock %d\n", port->sock); curr = DLGetSucc(curr); }}/* * CharRemap */static charCharRemap(long int ch){ if (ch < 0) ch = -ch; ch = ch % 62; if (ch < 26) return 'A' + ch; ch -= 26; if (ch < 26) return 'a' + ch; ch -= 26; return '0' + ch;}/* * RandomSalt */static voidRandomSalt(char *salt){ long rand = PostmasterRandom(); *salt = CharRemap(rand % 62); *(salt + 1) = CharRemap(rand / 62);}/* * PostmasterRandom */static longPostmasterRandom(void){ static bool initialized = false; if (!initialized) { Assert(random_seed != 0 && !IsUnderPostmaster); srandom(random_seed); initialized = true; } return random() ^ random_seed;}/* * Count up number of child processes. */static intCountChildren(void){ Dlelem *curr; Backend *bp; int mypid = getpid(); int cnt = 0; for (curr = DLGetHead(BackendList); curr; curr = DLGetSucc(curr)) { bp = (Backend *) DLE_VAL(curr); if (bp->pid != mypid) cnt++; } return cnt;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -