summaryrefslogtreecommitdiff
path: root/src/backend/postmaster
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/postmaster')
-rw-r--r--src/backend/postmaster/bgworker.c103
1 files changed, 57 insertions, 46 deletions
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
index 5ea5abff8da..ff266009fc2 100644
--- a/src/backend/postmaster/bgworker.c
+++ b/src/backend/postmaster/bgworker.c
@@ -95,23 +95,24 @@ 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},
- /* Dummy entry marking end of the array. */
- {NULL, NULL}
+ const char *fn_name;
+ bgworker_main_type fn_addr;
+} InternalBGWorkers[] =
+
+{
+ {
+ "ParallelWorkerMain", ParallelWorkerMain
+ }
};
-static bgworker_main_type GetInternalBgWorkerMain(BackgroundWorker *worker);
+/* Private functions. */
+static bgworker_main_type LookupBackgroundWorkerFunction(char *libraryname, char *funcname);
+
/*
* Calculate shared memory needed.
@@ -715,27 +716,18 @@ StartBackgroundWorker(void)
#endif
}
- /* For internal workers set the entry point to known function address. */
- entrypt = GetInternalBgWorkerMain(worker);
-
/*
- * Otherwise, if bgw_main is set, we use that value as the initial
- * entrypoint. This does not work well EXEC_BACKEND outside Windows but
- * we keep the logic for backwards compatibility. In other cases 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).
+ * If bgw_main is set, we use that value as the entry point function.
+ * Passing function addresses across processes is unreliable on many
+ * platforms, but we'll leave the option in place in 9.x for backwards
+ * compatibility. Otherwise, look up the entry point function, loading
+ * its library if necessary.
*/
- if (entrypt == NULL)
- {
- if (worker->bgw_main != NULL)
- entrypt = worker->bgw_main;
- else
- entrypt = (bgworker_main_type)
- load_external_function(worker->bgw_library_name,
- worker->bgw_function_name,
- true, NULL);
- }
+ if (worker->bgw_main != NULL)
+ entrypt = worker->bgw_main;
+ else
+ entrypt = LookupBackgroundWorkerFunction(worker->bgw_library_name,
+ worker->bgw_function_name);
/*
* Note that in normal processes, we would call InitPostgres here. For a
@@ -1077,26 +1069,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.
*
- * Returns NULL if not known internal worker.
+ * 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().
+ *
+ * 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(char *libraryname, 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);
}