void pool_shmem_exit(int code) { shmem_exit(code); /* Close syslog connection here as this function is always called on exit */ closelog(); }
void proc_exit(int code) { shmem_exit(code); while (--on_proc_exit_index >= 0) (*on_proc_exit_list[on_proc_exit_index].function) (code, on_proc_exit_list[on_proc_exit_index].arg); exit(code); }
/* * Code shared between proc_exit and the atexit handler. Note that in * normal exit through proc_exit, this will actually be called twice ... * but the second call will have nothing to do. */ static void proc_exit_prepare(int code) { /* * Once we set this flag, we are committed to exit. Any ereport() will * NOT send control back to the main loop, but right back here. */ proc_exit_inprogress = true; /* * Forget any pending cancel or die requests; we're doing our best to * close up shop already. Note that the signal handlers will not set * these flags again, now that proc_exit_inprogress is set. */ InterruptPending = false; ProcDiePending = false; QueryCancelPending = false; /* And let's just make *sure* we're not interrupted ... */ ImmediateInterruptOK = false; InterruptHoldoffCount = 1; CritSectionCount = 0; /* * Also clear the error context stack, to prevent error callbacks from * being invoked by any elog/ereport calls made during proc_exit. Whatever * context they might want to offer is probably not relevant, and in any * case they are likely to fail outright after we've done things like * aborting any open transaction. (In normal exit scenarios the context * stack should be empty anyway, but it might not be in the case of * elog(FATAL) for example.) */ error_context_stack = NULL; /* For the same reason, reset debug_query_string before it's clobbered */ debug_query_string = NULL; /* do our shared memory exits first */ shmem_exit(code); elog(DEBUG3, "proc_exit(%d): %d callbacks to make", code, on_proc_exit_index); /* * call all the registered callbacks. * * Note that since we decrement on_proc_exit_index each time, if a * callback calls ereport(ERROR) or ereport(FATAL) then it won't be * invoked again when control comes back here (nor will the * previously-completed callbacks). So, an infinite loop should not be * possible. */ while (--on_proc_exit_index >= 0) (*on_proc_exit_list[on_proc_exit_index].function) (code, on_proc_exit_list[on_proc_exit_index].arg); on_proc_exit_index = 0; }
/* * Code shared between proc_exit and the atexit handler. Note that in * normal exit through proc_exit, this will actually be called twice ... * but the second call will have nothing to do. */ void proc_exit_prepare(int code) { /* * Once we set this flag, we are committed to exit. Any ereport() will * NOT send control back to the main loop, but right back here. */ proc_exit_inprogress = true; /* * Forget any pending cancel or die requests; we're doing our best to * close up shop already. Note that the signal handlers will not set * these flags again, now that proc_exit_inprogress is set. */ InterruptPending = false; ProcDiePending = false; QueryCancelPending = false; /* And let's just make *sure* we're not interrupted ... */ ImmediateInterruptOK = false; InterruptWhenCallingPLUDF = false; InterruptHoldoffCount = 1; CritSectionCount = 0; /* do our shared memory exits first */ shmem_exit(code); elog(DEBUG3, "proc_exit(%d): %d callbacks to make", code, on_proc_exit_index); /* * call all the registered callbacks. * * Note that since we decrement on_proc_exit_index each time, if a * callback calls ereport(ERROR) or ereport(FATAL) then it won't be * invoked again when control comes back here (nor will the * previously-completed callbacks). So, an infinite loop should not be * possible. */ while (--on_proc_exit_index >= 0) (*on_proc_exit_list[on_proc_exit_index].function) (code, on_proc_exit_list[on_proc_exit_index].arg); on_proc_exit_index = 0; }
int main(int argc, char **argv) { MyStorage *storage; int cpid; printf("Creating shared memory ... "); fflush(stdout); storage = (MyStorage *) PGSharedMemoryCreate(8192, false, 5433); storage->flag = 1234; printf("OK\n"); printf("Creating semaphores ... "); fflush(stdout); PGReserveSemaphores(2, 5433); PGSemaphoreCreate(&storage->sem); printf("OK\n"); /* sema initial value is 1, so lock should work */ printf("Testing Lock ... "); fflush(stdout); PGSemaphoreLock(&storage->sem, false); printf("OK\n"); /* now sema value is 0, so trylock should fail */ printf("Testing TryLock ... "); fflush(stdout); if (PGSemaphoreTryLock(&storage->sem)) printf("unexpected result!\n"); else printf("OK\n"); /* unlocking twice and then locking twice should work... */ printf("Testing Multiple Lock ... "); fflush(stdout); PGSemaphoreUnlock(&storage->sem); PGSemaphoreUnlock(&storage->sem); PGSemaphoreLock(&storage->sem, false); PGSemaphoreLock(&storage->sem, false); printf("OK\n"); /* check Reset too */ printf("Testing Reset ... "); fflush(stdout); PGSemaphoreUnlock(&storage->sem); PGSemaphoreReset(&storage->sem); if (PGSemaphoreTryLock(&storage->sem)) printf("unexpected result!\n"); else printf("OK\n"); /* Fork a child process and see if it can communicate */ printf("Forking child process ... "); fflush(stdout); cpid = fork(); if (cpid == 0) { /* In child */ on_exit_reset(); sleep(3); storage->flag++; PGSemaphoreUnlock(&storage->sem); proc_exit(0); } if (cpid < 0) { /* Fork failed */ printf("failed: %s\n", strerror(errno)); proc_exit(1); } printf("forked child pid %d OK\n", cpid); if (storage->flag != 1234) printf("Wrong value found in shared memory!\n"); printf("Waiting for child (should wait 3 sec here) ... "); fflush(stdout); PGSemaphoreLock(&storage->sem, false); printf("OK\n"); if (storage->flag != 1235) printf("Wrong value found in shared memory!\n"); /* Test shutdown */ printf("Running shmem_exit processing ... "); fflush(stdout); shmem_exit(0); printf("OK\n"); printf("Tests complete.\n"); proc_exit(0); return 0; /* not reached */ }
/* * Code shared between proc_exit and the atexit handler. Note that in * normal exit through proc_exit, this will actually be called twice ... * but the second call will have nothing to do. */ void proc_exit_prepare(int code) { /* * If we came here from any critical section, we don't have safe way to * clean up shared memory or transaction state. Though it's not a pleasant * solution, this is better than messing up database. This is the least * desirable bail-out, and whenever you should see this situation, you * should consider to resolve the actual programming error. */ if (CritSectionCount > 0 && !SuppressPanic) elog(PANIC, "process is dying from critical section"); /* * Once we set this flag, we are committed to exit. Any ereport() will * NOT send control back to the main loop, but right back here. */ proc_exit_inprogress = true; /* * Forget any pending cancel or die requests; we're doing our best to * close up shop already. Note that the signal handlers will not set * these flags again, now that proc_exit_inprogress is set. */ InterruptPending = false; ProcDiePending = false; QueryCancelPending = false; /* And let's just make *sure* we're not interrupted ... */ ImmediateInterruptOK = false; InterruptWhenCallingPLUDF = false; InterruptHoldoffCount = 1; CritSectionCount = 0; /* * Also clear the error context stack, to prevent error callbacks * from being invoked by any elog/ereport calls made during proc_exit. * Whatever context they might want to offer is probably not relevant, * and in any case they are likely to fail outright after we've done * things like aborting any open transaction. (In normal exit scenarios * the context stack should be empty anyway, but it might not be in the * case of elog(FATAL) for example.) */ error_context_stack = NULL; /* * Make sure interconnect thread quit before shmem_exit() in FATAL case. * Otherwise, shmem_exit() may free MemoryContex of MotionConns in connHtab unexpectedly; * * For example: PORTAL_MULTI_QUERY strategy doesn't bind estate with portal, * so when fatal occurs, MotionConns of estate don't get removed through * TeardownInterconnect(), but MemoryContex of these MotionConns are freed. * * It's ok to shutdown Interconnect background thread here, process is dying, no * necessary to receive more motion data. */ WaitInterconnectQuit(); /* do our shared memory exits first */ shmem_exit(code); elog(DEBUG3, "proc_exit(%d): %d callbacks to make", code, on_proc_exit_index); /* * call all the registered callbacks. * * Note that since we decrement on_proc_exit_index each time, if a * callback calls ereport(ERROR) or ereport(FATAL) then it won't be * invoked again when control comes back here (nor will the * previously-completed callbacks). So, an infinite loop should not be * possible. */ while (--on_proc_exit_index >= 0) (*on_proc_exit_list[on_proc_exit_index].function) (code, on_proc_exit_list[on_proc_exit_index].arg); on_proc_exit_index = 0; }