Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 02185a0

Browse files
committed
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.
1 parent d22ae3e commit 02185a0

File tree

1 file changed

+89
-6
lines changed

1 file changed

+89
-6
lines changed

src/pl/tcl/pltcl.c

+89-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* pltcl.c - PostgreSQL support for Tcl as
33
* procedural language (PL)
44
*
5-
* $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.112 2007/04/02 03:49:42 tgl Exp $
5+
* $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.113 2007/09/21 00:30:49 tgl Exp $
66
*
77
**********************************************************************/
88

@@ -33,9 +33,11 @@
3333
#include "utils/syscache.h"
3434
#include "utils/typcache.h"
3535

36+
#define HAVE_TCL_VERSION(maj,min) \
37+
((TCL_MAJOR_VERSION > maj) || \
38+
(TCL_MAJOR_VERSION == maj && TCL_MINOR_VERSION >= min))
3639

37-
#if defined(UNICODE_CONVERSION) && TCL_MAJOR_VERSION == 8 \
38-
&& TCL_MINOR_VERSION > 0
40+
#if defined(UNICODE_CONVERSION) && HAVE_TCL_VERSION(8,1)
3941

4042
#include "mb/pg_wchar.h"
4143

@@ -164,6 +166,68 @@ static void pltcl_build_tuple_argument(HeapTuple tuple, TupleDesc tupdesc,
164166
Tcl_DString *retval);
165167

166168

169+
/*
170+
* Hack to override Tcl's builtin Notifier subsystem. This prevents the
171+
* backend from becoming multithreaded, which breaks all sorts of things.
172+
* That happens in the default version of Tcl_InitNotifier if the TCL library
173+
* has been compiled with multithreading support (i.e. when TCL_THREADS is
174+
* defined under Unix, and in all cases under Windows).
175+
* It's okay to disable the notifier because we never enter the Tcl event loop
176+
* from Postgres, so the notifier capabilities are initialized, but never
177+
* used. Only InitNotifier and DeleteFileHandler ever seem to get called
178+
* within Postgres, but we implement all the functions for completeness.
179+
* We can only fix this with Tcl >= 8.2, when Tcl_SetNotifier() appeared.
180+
*/
181+
#if HAVE_TCL_VERSION(8,2)
182+
183+
static ClientData
184+
pltcl_InitNotifier(void)
185+
{
186+
static int fakeThreadKey; /* To give valid address for ClientData */
187+
188+
return (ClientData) &(fakeThreadKey);
189+
}
190+
191+
static void
192+
pltcl_FinalizeNotifier(ClientData clientData)
193+
{
194+
}
195+
196+
static void
197+
pltcl_SetTimer(Tcl_Time *timePtr)
198+
{
199+
}
200+
201+
static void
202+
pltcl_AlertNotifier(ClientData clientData)
203+
{
204+
}
205+
206+
static void
207+
pltcl_CreateFileHandler(int fd, int mask,
208+
Tcl_FileProc *proc, ClientData clientData)
209+
{
210+
}
211+
212+
static void
213+
pltcl_DeleteFileHandler(int fd)
214+
{
215+
}
216+
217+
static void
218+
pltcl_ServiceModeHook(int mode)
219+
{
220+
}
221+
222+
static int
223+
pltcl_WaitForEvent(Tcl_Time *timePtr)
224+
{
225+
return 0;
226+
}
227+
228+
#endif /* HAVE_TCL_VERSION(8,2) */
229+
230+
167231
/*
168232
* This routine is a crock, and so is everyplace that calls it. The problem
169233
* is that the cached form of pltcl functions/queries is allocated permanently
@@ -198,6 +262,25 @@ _PG_init(void)
198262
Tcl_FindExecutable("");
199263
#endif
200264

265+
#if HAVE_TCL_VERSION(8,2)
266+
/*
267+
* Override the functions in the Notifier subsystem. See comments above.
268+
*/
269+
{
270+
Tcl_NotifierProcs notifier;
271+
272+
notifier.setTimerProc = pltcl_SetTimer;
273+
notifier.waitForEventProc = pltcl_WaitForEvent;
274+
notifier.createFileHandlerProc = pltcl_CreateFileHandler;
275+
notifier.deleteFileHandlerProc = pltcl_DeleteFileHandler;
276+
notifier.initNotifierProc = pltcl_InitNotifier;
277+
notifier.finalizeNotifierProc = pltcl_FinalizeNotifier;
278+
notifier.alertNotifierProc = pltcl_AlertNotifier;
279+
notifier.serviceModeHookProc = pltcl_ServiceModeHook;
280+
Tcl_SetNotifier(&notifier);
281+
}
282+
#endif
283+
201284
/************************************************************
202285
* Create the dummy hold interpreter to prevent close of
203286
* stdout and stderr on DeleteInterp
@@ -1808,9 +1891,9 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
18081891
PG_TRY();
18091892
{
18101893
/************************************************************
1811-
* Resolve argument type names and then look them up by oid
1812-
* in the system cache, and remember the required information
1813-
* for input conversion.
1894+
* Resolve argument type names and then look them up by oid
1895+
* in the system cache, and remember the required information
1896+
* for input conversion.
18141897
************************************************************/
18151898
for (i = 0; i < nargs; i++)
18161899
{

0 commit comments

Comments
 (0)