summaryrefslogtreecommitdiff
path: root/src/backend/postmaster
diff options
context:
space:
mode:
authorTom Lane2017-04-15 03:50:16 +0000
committerTom Lane2017-04-15 03:50:16 +0000
commit32470825d36d99a81347ee36c181d609c952c061 (patch)
tree0fe8bfc11dbb20ae8dfe943632674cd3bc859b79 /src/backend/postmaster
parent5a617ab3e691aec56725960e6d28c98c8af6ddaa (diff)
Avoid passing function pointers across process boundaries.
We'd already recognized that we can't pass function pointers across process boundaries for functions in loadable modules, since a shared library could get loaded at different addresses in different processes. But actually the practice doesn't work for functions in the core backend either, if we're using EXEC_BACKEND. This is the cause of recent failures on buildfarm member culicidae. Switch to passing a string function name in all cases. Something like this needs to be back-patched into 9.6, but let's see if the buildfarm likes it first. Petr Jelinek, with a bunch of basically-cosmetic adjustments by me Discussion: https://postgr.es/m/548f9c1d-eafa-e3fa-9da8-f0cc2f654e60@2ndquadrant.com
Diffstat (limited to 'src/backend/postmaster')
-rw-r--r--src/backend/postmaster/bgworker.c105
1 files changed, 61 insertions, 44 deletions
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
index 9ad3e915db3..f1194891f50 100644
--- a/src/backend/postmaster/bgworker.c
+++ b/src/backend/postmaster/bgworker.c
@@ -111,25 +111,30 @@ struct BackgroundWorkerHandle
static BackgroundWorkerArray *BackgroundWorkerData;
/*
- * List of internal background workers. These are used for mapping the
- * function name to actual function when building with EXEC_BACKEND and also
- * to allow these to be loaded outside of shared_preload_libraries.
+ * List of internal background worker entry points. We need this for
+ * reasons explained in LookupBackgroundWorkerFunction(), below.
*/
-typedef struct InternalBGWorkerMain
+static const struct
{
- char *bgw_function_name;
- bgworker_main_type bgw_main;
-} InternalBGWorkerMain;
-
-static const InternalBGWorkerMain InternalBGWorkers[] = {
- {"ParallelWorkerMain", ParallelWorkerMain},
- {"ApplyLauncherMain", ApplyLauncherMain},
- {"ApplyWorkerMain", ApplyWorkerMain},
- /* Dummy entry marking end of the array. */
- {NULL, NULL}
+ const char *fn_name;
+ bgworker_main_type fn_addr;
+} InternalBGWorkers[] =
+
+{
+ {
+ "ParallelWorkerMain", ParallelWorkerMain
+ },
+ {
+ "ApplyLauncherMain", ApplyLauncherMain
+ },
+ {
+ "ApplyWorkerMain", ApplyWorkerMain
+ }
};
-static bgworker_main_type GetInternalBgWorkerMain(BackgroundWorker *worker);
+/* Private functions. */
+static bgworker_main_type LookupBackgroundWorkerFunction(const char *libraryname, const char *funcname);
+
/*
* Calculate shared memory needed.
@@ -812,18 +817,10 @@ StartBackgroundWorker(void)
}
/*
- * For internal workers set the entry point to known function address.
- * Otherwise use the entry point specified by library name (which will
- * be loaded, if necessary) and a function name (which will be looked up
- * in the named library).
+ * Look up the entry point function, loading its library if necessary.
*/
- entrypt = GetInternalBgWorkerMain(worker);
-
- if (entrypt == NULL)
- entrypt = (bgworker_main_type)
- load_external_function(worker->bgw_library_name,
- worker->bgw_function_name,
- true, NULL);
+ entrypt = LookupBackgroundWorkerFunction(worker->bgw_library_name,
+ worker->bgw_function_name);
/*
* Note that in normal processes, we would call InitPostgres here. For a
@@ -842,10 +839,11 @@ StartBackgroundWorker(void)
}
/*
- * Register a new background worker while processing shared_preload_libraries.
+ * Register a new static background worker.
*
- * This can only be called in the _PG_init function of a module library
- * that's loaded by shared_preload_libraries; otherwise it has no effect.
+ * This can only be called directly from postmaster or in the _PG_init
+ * function of a module library that's loaded by shared_preload_libraries;
+ * otherwise it will have no effect.
*/
void
RegisterBackgroundWorker(BackgroundWorker *worker)
@@ -858,7 +856,7 @@ RegisterBackgroundWorker(BackgroundWorker *worker)
(errmsg("registering background worker \"%s\"", worker->bgw_name)));
if (!process_shared_preload_libraries_in_progress &&
- GetInternalBgWorkerMain(worker) == NULL)
+ strcmp(worker->bgw_library_name, "postgres") != 0)
{
if (!IsUnderPostmaster)
ereport(LOG,
@@ -1193,26 +1191,45 @@ TerminateBackgroundWorker(BackgroundWorkerHandle *handle)
}
/*
- * Search the known internal worker array and return its main function
- * pointer if found.
+ * Look up (and possibly load) a bgworker entry point function.
+ *
+ * For functions contained in the core code, we use library name "postgres"
+ * and consult the InternalBGWorkers array. External functions are
+ * looked up, and loaded if necessary, using load_external_function().
*
- * Returns NULL if not known internal worker.
+ * The point of this is to pass function names as strings across process
+ * boundaries. We can't pass actual function addresses because of the
+ * possibility that the function has been loaded at a different address
+ * in a different process. This is obviously a hazard for functions in
+ * loadable libraries, but it can happen even for functions in the core code
+ * on platforms using EXEC_BACKEND (e.g., Windows).
+ *
+ * At some point it might be worthwhile to get rid of InternalBGWorkers[]
+ * in favor of applying load_external_function() for core functions too;
+ * but that raises portability issues that are not worth addressing now.
*/
static bgworker_main_type
-GetInternalBgWorkerMain(BackgroundWorker *worker)
+LookupBackgroundWorkerFunction(const char *libraryname, const char *funcname)
{
- int i;
+ /*
+ * If the function is to be loaded from postgres itself, search the
+ * InternalBGWorkers array.
+ */
+ if (strcmp(libraryname, "postgres") == 0)
+ {
+ int i;
- /* Internal workers always have to use postgres as library name. */
- if (strncmp(worker->bgw_library_name, "postgres", BGW_MAXLEN) != 0)
- return NULL;
+ for (i = 0; i < lengthof(InternalBGWorkers); i++)
+ {
+ if (strcmp(InternalBGWorkers[i].fn_name, funcname) == 0)
+ return InternalBGWorkers[i].fn_addr;
+ }
- for (i = 0; InternalBGWorkers[i].bgw_function_name; i++)
- {
- if (strncmp(InternalBGWorkers[i].bgw_function_name,
- worker->bgw_function_name, BGW_MAXLEN) == 0)
- return InternalBGWorkers[i].bgw_main;
+ /* We can only reach this by programming error. */
+ elog(ERROR, "internal function \"%s\" not found", funcname);
}
- return NULL;
+ /* Otherwise load from external library. */
+ return (bgworker_main_type)
+ load_external_function(libraryname, funcname, true, NULL);
}