Insert a hack in pl/tcl to disable Tcl's built-in Notifier subsystem, which

has a bad habit of launching multiple threads within the backend and thereby
causing all kinds of havoc.  Fortunately, we don't need it, and recent Tcl
versions provide an easy way to disable it.  Diagnosis and fix by
Steve Marshall, Paul Bayer, and Doug Knight of WSI Corporation.
This commit is contained in:
Tom Lane 2007-09-21 00:30:49 +00:00
parent d22ae3ecc2
commit 02185a0716
1 changed files with 89 additions and 6 deletions

View File

@ -2,7 +2,7 @@
* pltcl.c - PostgreSQL support for Tcl as
* procedural language (PL)
*
* $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.112 2007/04/02 03:49:42 tgl Exp $
* $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.113 2007/09/21 00:30:49 tgl Exp $
*
**********************************************************************/
@ -33,9 +33,11 @@
#include "utils/syscache.h"
#include "utils/typcache.h"
#define HAVE_TCL_VERSION(maj,min) \
((TCL_MAJOR_VERSION > maj) || \
(TCL_MAJOR_VERSION == maj && TCL_MINOR_VERSION >= min))
#if defined(UNICODE_CONVERSION) && TCL_MAJOR_VERSION == 8 \
&& TCL_MINOR_VERSION > 0
#if defined(UNICODE_CONVERSION) && HAVE_TCL_VERSION(8,1)
#include "mb/pg_wchar.h"
@ -164,6 +166,68 @@ static void pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,
Tcl_DString *retval);
/*
* Hack to override Tcl's builtin Notifier subsystem. This prevents the
* backend from becoming multithreaded, which breaks all sorts of things.
* That happens in the default version of Tcl_InitNotifier if the TCL library
* has been compiled with multithreading support (i.e. when TCL_THREADS is
* defined under Unix, and in all cases under Windows).
* It's okay to disable the notifier because we never enter the Tcl event loop
* from Postgres, so the notifier capabilities are initialized, but never
* used. Only InitNotifier and DeleteFileHandler ever seem to get called
* within Postgres, but we implement all the functions for completeness.
* We can only fix this with Tcl >= 8.2, when Tcl_SetNotifier() appeared.
*/
#if HAVE_TCL_VERSION(8,2)
static ClientData
pltcl_InitNotifier(void)
{
static int fakeThreadKey; /* To give valid address for ClientData */
return (ClientData) &(fakeThreadKey);
}
static void
pltcl_FinalizeNotifier(ClientData clientData)
{
}
static void
pltcl_SetTimer(Tcl_Time *timePtr)
{
}
static void
pltcl_AlertNotifier(ClientData clientData)
{
}
static void
pltcl_CreateFileHandler(int fd, int mask,
Tcl_FileProc *proc, ClientData clientData)
{
}
static void
pltcl_DeleteFileHandler(int fd)
{
}
static void
pltcl_ServiceModeHook(int mode)
{
}
static int
pltcl_WaitForEvent(Tcl_Time *timePtr)
{
return 0;
}
#endif /* HAVE_TCL_VERSION(8,2) */
/*
* This routine is a crock, and so is everyplace that calls it. The problem
* is that the cached form of pltcl functions/queries is allocated permanently
@ -198,6 +262,25 @@ _PG_init(void)
Tcl_FindExecutable("");
#endif
#if HAVE_TCL_VERSION(8,2)
/*
* Override the functions in the Notifier subsystem. See comments above.
*/
{
Tcl_NotifierProcs notifier;
notifier.setTimerProc = pltcl_SetTimer;
notifier.waitForEventProc = pltcl_WaitForEvent;
notifier.createFileHandlerProc = pltcl_CreateFileHandler;
notifier.deleteFileHandlerProc = pltcl_DeleteFileHandler;
notifier.initNotifierProc = pltcl_InitNotifier;
notifier.finalizeNotifierProc = pltcl_FinalizeNotifier;
notifier.alertNotifierProc = pltcl_AlertNotifier;
notifier.serviceModeHookProc = pltcl_ServiceModeHook;
Tcl_SetNotifier(&notifier);
}
#endif
/************************************************************
* Create the dummy hold interpreter to prevent close of
* stdout and stderr on DeleteInterp
@ -1808,9 +1891,9 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
PG_TRY();
{
/************************************************************
* Resolve argument type names and then look them up by oid
* in the system cache, and remember the required information
* for input conversion.
* Resolve argument type names and then look them up by oid
* in the system cache, and remember the required information
* for input conversion.
************************************************************/
for (i = 0; i < nargs; i++)
{