Don't use bgw_main even to specify in-core bgworker entrypoints.
On EXEC_BACKEND builds, this can fail if ASLR is in use. Backpatch to 9.5. On master, completely remove the bgw_main field completely, since there is no situation in which it is safe for an EXEC_BACKEND build. On 9.6 and 9.5, leave the field intact to avoid breaking things for third-party code that doesn't care about working under EXEC_BACKEND. Prior to 9.5, there are no in-core bgworker entrypoints. Petr Jelinek, reviewed by me. Discussion: http://postgr.es/m/09d8ad33-4287-a09b-a77f-77f8761adb5e@2ndquadrant.com
This commit is contained in:
parent
c281cd5fe1
commit
2113ac4cbb
@ -54,9 +54,8 @@ typedef struct BackgroundWorker
|
|||||||
int bgw_flags;
|
int bgw_flags;
|
||||||
BgWorkerStartTime bgw_start_time;
|
BgWorkerStartTime bgw_start_time;
|
||||||
int bgw_restart_time; /* in seconds, or BGW_NEVER_RESTART */
|
int bgw_restart_time; /* in seconds, or BGW_NEVER_RESTART */
|
||||||
bgworker_main_type bgw_main;
|
char bgw_library_name[BGW_MAXLEN];
|
||||||
char bgw_library_name[BGW_MAXLEN]; /* only if bgw_main is NULL */
|
char bgw_function_name[BGW_MAXLEN];
|
||||||
char bgw_function_name[BGW_MAXLEN]; /* only if bgw_main is NULL */
|
|
||||||
Datum bgw_main_arg;
|
Datum bgw_main_arg;
|
||||||
char bgw_extra[BGW_EXTRALEN];
|
char bgw_extra[BGW_EXTRALEN];
|
||||||
int bgw_notify_pid;
|
int bgw_notify_pid;
|
||||||
@ -130,27 +129,13 @@ typedef struct BackgroundWorker
|
|||||||
process in case of a crash.
|
process in case of a crash.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
|
||||||
<structfield>bgw_main</structfield> is a pointer to the function to run when
|
|
||||||
the process is started. This field can only safely be used to launch
|
|
||||||
functions within the core server, because shared libraries may be loaded
|
|
||||||
at different starting addresses in different backend processes. This will
|
|
||||||
happen on all platforms when the library is loaded using any mechanism
|
|
||||||
other than <xref linkend="guc-shared-preload-libraries">. Even when that
|
|
||||||
mechanism is used, address space layout variations will still occur on
|
|
||||||
Windows, and when <literal>EXEC_BACKEND</> is used. Therefore, most users
|
|
||||||
of this API should set this field to NULL. If it is non-NULL, it takes
|
|
||||||
precedence over <structfield>bgw_library_name</> and
|
|
||||||
<structfield>bgw_function_name</>.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<structfield>bgw_library_name</structfield> is the name of a library in
|
<structfield>bgw_library_name</structfield> is the name of a library in
|
||||||
which the initial entry point for the background worker should be sought.
|
which the initial entry point for the background worker should be sought.
|
||||||
The named library will be dynamically loaded by the worker process and
|
The named library will be dynamically loaded by the worker process and
|
||||||
<structfield>bgw_function_name</structfield> will be used to identify the
|
<structfield>bgw_function_name</structfield> will be used to identify the
|
||||||
function to be called. If loading a function from the core code,
|
function to be called. If loading a function from the core code, this must
|
||||||
<structfield>bgw_main</> should be set instead.
|
be set to "postgres".
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -161,13 +146,10 @@ typedef struct BackgroundWorker
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
<structfield>bgw_main_arg</structfield> is the <type>Datum</> argument
|
<structfield>bgw_main_arg</structfield> is the <type>Datum</> argument
|
||||||
to the background worker main function. Regardless of whether that
|
to the background worker main function. This main function should take a
|
||||||
function is specified via <structfield>bgw_main</> or via the combination
|
single argument of type <type>Datum</> and return <type>void</>.
|
||||||
of <function>bgw_library_name</> and <function>bgw_function_name</>,
|
<structfield>bgw_main_arg</structfield> will be passed as the argument.
|
||||||
this main function should take a single argument of type <type>Datum</>
|
In addition, the global variable <literal>MyBgworkerEntry</literal>
|
||||||
and return <type>void</>. <structfield>bgw_main_arg</structfield> will be
|
|
||||||
passed as the argument. In addition, the global variable
|
|
||||||
<literal>MyBgworkerEntry</literal>
|
|
||||||
points to a copy of the <structname>BackgroundWorker</structname> structure
|
points to a copy of the <structname>BackgroundWorker</structname> structure
|
||||||
passed at registration time; the worker may find it helpful to examine
|
passed at registration time; the worker may find it helpful to examine
|
||||||
this structure.
|
this structure.
|
||||||
@ -215,7 +197,7 @@ typedef struct BackgroundWorker
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Signals are initially blocked when control reaches the
|
Signals are initially blocked when control reaches the
|
||||||
<structfield>bgw_main</> function, and must be unblocked by it; this is to
|
background worker's main function, and must be unblocked by it; this is to
|
||||||
allow the process to customize its signal handlers, if necessary.
|
allow the process to customize its signal handlers, if necessary.
|
||||||
Signals can be unblocked in the new process by calling
|
Signals can be unblocked in the new process by calling
|
||||||
<function>BackgroundWorkerUnblockSignals</> and blocked by calling
|
<function>BackgroundWorkerUnblockSignals</> and blocked by calling
|
||||||
|
@ -110,7 +110,6 @@ static dlist_head pcxt_list = DLIST_STATIC_INIT(pcxt_list);
|
|||||||
/* Private functions. */
|
/* Private functions. */
|
||||||
static void HandleParallelMessage(ParallelContext *pcxt, int i, StringInfo msg);
|
static void HandleParallelMessage(ParallelContext *pcxt, int i, StringInfo msg);
|
||||||
static void ParallelExtensionTrampoline(dsm_segment *seg, shm_toc *toc);
|
static void ParallelExtensionTrampoline(dsm_segment *seg, shm_toc *toc);
|
||||||
static void ParallelWorkerMain(Datum main_arg);
|
|
||||||
static void WaitForParallelWorkersToExit(ParallelContext *pcxt);
|
static void WaitForParallelWorkersToExit(ParallelContext *pcxt);
|
||||||
|
|
||||||
|
|
||||||
@ -458,7 +457,8 @@ LaunchParallelWorkers(ParallelContext *pcxt)
|
|||||||
| BGWORKER_CLASS_PARALLEL;
|
| BGWORKER_CLASS_PARALLEL;
|
||||||
worker.bgw_start_time = BgWorkerStart_ConsistentState;
|
worker.bgw_start_time = BgWorkerStart_ConsistentState;
|
||||||
worker.bgw_restart_time = BGW_NEVER_RESTART;
|
worker.bgw_restart_time = BGW_NEVER_RESTART;
|
||||||
worker.bgw_main = ParallelWorkerMain;
|
sprintf(worker.bgw_library_name, "postgres");
|
||||||
|
sprintf(worker.bgw_function_name, "ParallelWorkerMain");
|
||||||
worker.bgw_main_arg = UInt32GetDatum(dsm_segment_handle(pcxt->seg));
|
worker.bgw_main_arg = UInt32GetDatum(dsm_segment_handle(pcxt->seg));
|
||||||
worker.bgw_notify_pid = MyProcPid;
|
worker.bgw_notify_pid = MyProcPid;
|
||||||
memset(&worker.bgw_extra, 0, BGW_EXTRALEN);
|
memset(&worker.bgw_extra, 0, BGW_EXTRALEN);
|
||||||
@ -931,7 +931,7 @@ AtEOXact_Parallel(bool isCommit)
|
|||||||
/*
|
/*
|
||||||
* Main entrypoint for parallel workers.
|
* Main entrypoint for parallel workers.
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
ParallelWorkerMain(Datum main_arg)
|
ParallelWorkerMain(Datum main_arg)
|
||||||
{
|
{
|
||||||
dsm_segment *seg;
|
dsm_segment *seg;
|
||||||
|
@ -15,12 +15,14 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
|
#include "access/parallel.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "pgstat.h"
|
#include "pgstat.h"
|
||||||
#include "port/atomics.h"
|
#include "port/atomics.h"
|
||||||
#include "postmaster/bgworker_internals.h"
|
#include "postmaster/bgworker_internals.h"
|
||||||
#include "postmaster/postmaster.h"
|
#include "postmaster/postmaster.h"
|
||||||
#include "replication/logicallauncher.h"
|
#include "replication/logicallauncher.h"
|
||||||
|
#include "replication/logicalworker.h"
|
||||||
#include "storage/dsm.h"
|
#include "storage/dsm.h"
|
||||||
#include "storage/ipc.h"
|
#include "storage/ipc.h"
|
||||||
#include "storage/latch.h"
|
#include "storage/latch.h"
|
||||||
@ -109,14 +111,26 @@ struct BackgroundWorkerHandle
|
|||||||
static BackgroundWorkerArray *BackgroundWorkerData;
|
static BackgroundWorkerArray *BackgroundWorkerData;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* List of workers that are allowed to be started outside of
|
* List of internal background workers. These are used for mapping the
|
||||||
* shared_preload_libraries.
|
* function name to actual function when building with EXEC_BACKEND and also
|
||||||
|
* to allow these to be loaded outside of shared_preload_libraries.
|
||||||
*/
|
*/
|
||||||
static const bgworker_main_type InternalBGWorkers[] = {
|
typedef struct InternalBGWorkerMain
|
||||||
ApplyLauncherMain,
|
{
|
||||||
NULL
|
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}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bgworker_main_type GetInternalBgWorkerMain(BackgroundWorker *worker);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate shared memory needed.
|
* Calculate shared memory needed.
|
||||||
*/
|
*/
|
||||||
@ -341,7 +355,6 @@ BackgroundWorkerStateChange(void)
|
|||||||
rw->rw_worker.bgw_flags = slot->worker.bgw_flags;
|
rw->rw_worker.bgw_flags = slot->worker.bgw_flags;
|
||||||
rw->rw_worker.bgw_start_time = slot->worker.bgw_start_time;
|
rw->rw_worker.bgw_start_time = slot->worker.bgw_start_time;
|
||||||
rw->rw_worker.bgw_restart_time = slot->worker.bgw_restart_time;
|
rw->rw_worker.bgw_restart_time = slot->worker.bgw_restart_time;
|
||||||
rw->rw_worker.bgw_main = slot->worker.bgw_main;
|
|
||||||
rw->rw_worker.bgw_main_arg = slot->worker.bgw_main_arg;
|
rw->rw_worker.bgw_main_arg = slot->worker.bgw_main_arg;
|
||||||
memcpy(rw->rw_worker.bgw_extra, slot->worker.bgw_extra, BGW_EXTRALEN);
|
memcpy(rw->rw_worker.bgw_extra, slot->worker.bgw_extra, BGW_EXTRALEN);
|
||||||
|
|
||||||
@ -763,17 +776,14 @@ StartBackgroundWorker(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If bgw_main is set, we use that value as the initial entrypoint.
|
* For internal workers set the entry point to known function address.
|
||||||
* However, if the library containing the entrypoint wasn't loaded at
|
* Otherwise use the entry point specified by library name (which will
|
||||||
* postmaster startup time, passing it as a direct function pointer is not
|
* be loaded, if necessary) and a function name (which will be looked up
|
||||||
* possible. To work around that, we allow callers for whom a function
|
* in the named library).
|
||||||
* pointer is not available to pass a library name (which will be loaded,
|
|
||||||
* if necessary) and a function name (which will be looked up in the named
|
|
||||||
* library).
|
|
||||||
*/
|
*/
|
||||||
if (worker->bgw_main != NULL)
|
entrypt = GetInternalBgWorkerMain(worker);
|
||||||
entrypt = worker->bgw_main;
|
|
||||||
else
|
if (entrypt == NULL)
|
||||||
entrypt = (bgworker_main_type)
|
entrypt = (bgworker_main_type)
|
||||||
load_external_function(worker->bgw_library_name,
|
load_external_function(worker->bgw_library_name,
|
||||||
worker->bgw_function_name,
|
worker->bgw_function_name,
|
||||||
@ -806,23 +816,13 @@ RegisterBackgroundWorker(BackgroundWorker *worker)
|
|||||||
{
|
{
|
||||||
RegisteredBgWorker *rw;
|
RegisteredBgWorker *rw;
|
||||||
static int numworkers = 0;
|
static int numworkers = 0;
|
||||||
bool internal = false;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
ereport(DEBUG1,
|
ereport(DEBUG1,
|
||||||
(errmsg("registering background worker \"%s\"", worker->bgw_name)));
|
(errmsg("registering background worker \"%s\"", worker->bgw_name)));
|
||||||
|
|
||||||
for (i = 0; InternalBGWorkers[i]; i++)
|
if (!process_shared_preload_libraries_in_progress &&
|
||||||
{
|
GetInternalBgWorkerMain(worker) == NULL)
|
||||||
if (worker->bgw_main == InternalBGWorkers[i])
|
|
||||||
{
|
|
||||||
internal = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!process_shared_preload_libraries_in_progress && !internal)
|
|
||||||
{
|
{
|
||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
@ -1152,3 +1152,28 @@ TerminateBackgroundWorker(BackgroundWorkerHandle *handle)
|
|||||||
if (signal_postmaster)
|
if (signal_postmaster)
|
||||||
SendPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE);
|
SendPostmasterSignal(PMSIGNAL_BACKGROUND_WORKER_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Search the known internal worker array and return its main function
|
||||||
|
* pointer if found.
|
||||||
|
*
|
||||||
|
* Returns NULL if not known internal worker.
|
||||||
|
*/
|
||||||
|
static bgworker_main_type
|
||||||
|
GetInternalBgWorkerMain(BackgroundWorker *worker)
|
||||||
|
{
|
||||||
|
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; 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@ -295,7 +295,8 @@ logicalrep_worker_launch(Oid dbid, Oid subid, const char *subname, Oid userid,
|
|||||||
bgw.bgw_flags = BGWORKER_SHMEM_ACCESS |
|
bgw.bgw_flags = BGWORKER_SHMEM_ACCESS |
|
||||||
BGWORKER_BACKEND_DATABASE_CONNECTION;
|
BGWORKER_BACKEND_DATABASE_CONNECTION;
|
||||||
bgw.bgw_start_time = BgWorkerStart_RecoveryFinished;
|
bgw.bgw_start_time = BgWorkerStart_RecoveryFinished;
|
||||||
bgw.bgw_main = ApplyWorkerMain;
|
snprintf(bgw.bgw_library_name, BGW_MAXLEN, "postgres");
|
||||||
|
snprintf(bgw.bgw_function_name, BGW_MAXLEN, "ApplyWorkerMain");
|
||||||
if (OidIsValid(relid))
|
if (OidIsValid(relid))
|
||||||
snprintf(bgw.bgw_name, BGW_MAXLEN,
|
snprintf(bgw.bgw_name, BGW_MAXLEN,
|
||||||
"logical replication worker for subscription %u sync %u", subid, relid);
|
"logical replication worker for subscription %u sync %u", subid, relid);
|
||||||
@ -553,7 +554,8 @@ ApplyLauncherRegister(void)
|
|||||||
bgw.bgw_flags = BGWORKER_SHMEM_ACCESS |
|
bgw.bgw_flags = BGWORKER_SHMEM_ACCESS |
|
||||||
BGWORKER_BACKEND_DATABASE_CONNECTION;
|
BGWORKER_BACKEND_DATABASE_CONNECTION;
|
||||||
bgw.bgw_start_time = BgWorkerStart_RecoveryFinished;
|
bgw.bgw_start_time = BgWorkerStart_RecoveryFinished;
|
||||||
bgw.bgw_main = ApplyLauncherMain;
|
snprintf(bgw.bgw_library_name, BGW_MAXLEN, "postgres");
|
||||||
|
snprintf(bgw.bgw_function_name, BGW_MAXLEN, "ApplyLauncherMain");
|
||||||
snprintf(bgw.bgw_name, BGW_MAXLEN,
|
snprintf(bgw.bgw_name, BGW_MAXLEN,
|
||||||
"logical replication launcher");
|
"logical replication launcher");
|
||||||
bgw.bgw_restart_time = 5;
|
bgw.bgw_restart_time = 5;
|
||||||
|
@ -67,4 +67,6 @@ extern void AtEOXact_Parallel(bool isCommit);
|
|||||||
extern void AtEOSubXact_Parallel(bool isCommit, SubTransactionId mySubId);
|
extern void AtEOSubXact_Parallel(bool isCommit, SubTransactionId mySubId);
|
||||||
extern void ParallelWorkerReportLastRecEnd(XLogRecPtr last_xlog_end);
|
extern void ParallelWorkerReportLastRecEnd(XLogRecPtr last_xlog_end);
|
||||||
|
|
||||||
|
extern void ParallelWorkerMain(Datum main_arg);
|
||||||
|
|
||||||
#endif /* PARALLEL_H */
|
#endif /* PARALLEL_H */
|
||||||
|
@ -91,9 +91,8 @@ typedef struct BackgroundWorker
|
|||||||
int bgw_flags;
|
int bgw_flags;
|
||||||
BgWorkerStartTime bgw_start_time;
|
BgWorkerStartTime bgw_start_time;
|
||||||
int bgw_restart_time; /* in seconds, or BGW_NEVER_RESTART */
|
int bgw_restart_time; /* in seconds, or BGW_NEVER_RESTART */
|
||||||
bgworker_main_type bgw_main;
|
char bgw_library_name[BGW_MAXLEN];
|
||||||
char bgw_library_name[BGW_MAXLEN]; /* only if bgw_main is NULL */
|
char bgw_function_name[BGW_MAXLEN];
|
||||||
char bgw_function_name[BGW_MAXLEN]; /* only if bgw_main is NULL */
|
|
||||||
Datum bgw_main_arg;
|
Datum bgw_main_arg;
|
||||||
char bgw_extra[BGW_EXTRALEN];
|
char bgw_extra[BGW_EXTRALEN];
|
||||||
pid_t bgw_notify_pid; /* SIGUSR1 this backend on start/stop */
|
pid_t bgw_notify_pid; /* SIGUSR1 this backend on start/stop */
|
||||||
|
@ -216,7 +216,6 @@ setup_background_workers(int nworkers, dsm_segment *seg)
|
|||||||
worker.bgw_flags = BGWORKER_SHMEM_ACCESS;
|
worker.bgw_flags = BGWORKER_SHMEM_ACCESS;
|
||||||
worker.bgw_start_time = BgWorkerStart_ConsistentState;
|
worker.bgw_start_time = BgWorkerStart_ConsistentState;
|
||||||
worker.bgw_restart_time = BGW_NEVER_RESTART;
|
worker.bgw_restart_time = BGW_NEVER_RESTART;
|
||||||
worker.bgw_main = NULL; /* new worker might not have library loaded */
|
|
||||||
sprintf(worker.bgw_library_name, "test_shm_mq");
|
sprintf(worker.bgw_library_name, "test_shm_mq");
|
||||||
sprintf(worker.bgw_function_name, "test_shm_mq_main");
|
sprintf(worker.bgw_function_name, "test_shm_mq_main");
|
||||||
snprintf(worker.bgw_name, BGW_MAXLEN, "test_shm_mq");
|
snprintf(worker.bgw_name, BGW_MAXLEN, "test_shm_mq");
|
||||||
|
@ -347,7 +347,8 @@ _PG_init(void)
|
|||||||
BGWORKER_BACKEND_DATABASE_CONNECTION;
|
BGWORKER_BACKEND_DATABASE_CONNECTION;
|
||||||
worker.bgw_start_time = BgWorkerStart_RecoveryFinished;
|
worker.bgw_start_time = BgWorkerStart_RecoveryFinished;
|
||||||
worker.bgw_restart_time = BGW_NEVER_RESTART;
|
worker.bgw_restart_time = BGW_NEVER_RESTART;
|
||||||
worker.bgw_main = worker_spi_main;
|
sprintf(worker.bgw_library_name, "worker_spi");
|
||||||
|
sprintf(worker.bgw_function_name, "worker_spi_main");
|
||||||
worker.bgw_notify_pid = 0;
|
worker.bgw_notify_pid = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -378,7 +379,6 @@ worker_spi_launch(PG_FUNCTION_ARGS)
|
|||||||
BGWORKER_BACKEND_DATABASE_CONNECTION;
|
BGWORKER_BACKEND_DATABASE_CONNECTION;
|
||||||
worker.bgw_start_time = BgWorkerStart_RecoveryFinished;
|
worker.bgw_start_time = BgWorkerStart_RecoveryFinished;
|
||||||
worker.bgw_restart_time = BGW_NEVER_RESTART;
|
worker.bgw_restart_time = BGW_NEVER_RESTART;
|
||||||
worker.bgw_main = NULL; /* new worker might not have library loaded */
|
|
||||||
sprintf(worker.bgw_library_name, "worker_spi");
|
sprintf(worker.bgw_library_name, "worker_spi");
|
||||||
sprintf(worker.bgw_function_name, "worker_spi_main");
|
sprintf(worker.bgw_function_name, "worker_spi_main");
|
||||||
snprintf(worker.bgw_name, BGW_MAXLEN, "worker %d", i);
|
snprintf(worker.bgw_name, BGW_MAXLEN, "worker %d", i);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user