Skip site navigation (1) Skip section navigation (2)

Re: [HACKERS] libpq thread safety

From: Bruce Momjian <pgman(at)candle(dot)pha(dot)pa(dot)us>
To: Manfred Spraul <manfred(at)colorfullife(dot)com>
Cc: PostgreSQL-patches <pgsql-patches(at)postgresql(dot)org>
Subject: Re: [HACKERS] libpq thread safety
Date: 2004-03-22 03:49:09
Message-ID: 200403220349.i2M3n9e12658@candle.pha.pa.us (view raw or flat)
Thread:
Lists: pgsql-hackerspgsql-patches
I could not get this patch to compile.  I am getting a failure because
BSD/OS doesn't have pthread_rwlock_wrlock().  I am concerned other
platforms might not have it either.

The compile failure is:

gcc -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes -Wmissing-declarations -O1 -Wall -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wcast-align -fpic -I. -I../../../src/include -I/usr/local/include/readline -I/usr/contrib/include  -DFRONTEND -DSYSCONFDIR='"/usr/local/pgsql/etc"'  -c -o fe-secure.o fe-secure.c
fe-secure.c:848: syntax error before `*'
fe-secure.c:848: warning: type defaults to `int' in declaration of `pq_lockarray'
fe-secure.c:848: warning: data definition has no type or storage class
fe-secure.c: In function `pq_lockingcallback':
fe-secure.c:853: warning: implicit declaration of function `pthread_rwlock_wrlock'
fe-secure.c:855: warning: implicit declaration of function `pthread_rwlock_unlock'
fe-secure.c: In function `init_ssl_system':
fe-secure.c:875: `pthread_rwlock_t' undeclared (first use in this function)
fe-secure.c:875: (Each undeclared identifier is reported only once
fe-secure.c:875: for each function it appears in.)
fe-secure.c:881: warning: implicit declaration of function `pthread_rwlock_init'
gmake: *** [fe-secure.o] Error 1


---------------------------------------------------------------------------

Manfred Spraul wrote:
> Bruce Momjian wrote:
> 
> >Your patch has been added to the PostgreSQL unapplied patches list at:
> >
> >	http://momjian.postgresql.org/cgi-bin/pgpatches
> >
> >I will try to apply it within the next 48 hours.
> >  
> >
> You are too fast: the patch was a proof of concept, not really tested 
> (actually quite buggy).
> Attached are two patches:
> 
> - ready-sigpipe: check_sigpipe_handler skips pthread_create_key if a 
> signal handler was installed. This is wrong - the key is always required.
> - ready-locking: locking around kerberos and openssl.
> 
> The patches pass the regression tests on i386 linux. Kerberos is 
> untested, ssl only partially tested due to the lack of a test setup.
> I'm still not sure if the new code is the right thing for the openssl 
> initialization: libpq calls SSL_library_init() unconditionally. If the 
> calling app uses ssl, too, this might confuse openssl.
> 
> Could you replace my initial proposal with these two patches?
> 
> Btw, is it intentional that THREAD_SUPPORT is not set in src/template/linux?
> 
> --
>     Manfred

> Index: src/backend/libpq/md5.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/backend/libpq/md5.c,v
> retrieving revision 1.22
> diff -c -r1.22 md5.c
> *** src/backend/libpq/md5.c	29 Nov 2003 19:51:49 -0000	1.22
> --- src/backend/libpq/md5.c	14 Mar 2004 10:46:54 -0000
> ***************
> *** 271,277 ****
>   static void
>   bytesToHex(uint8 b[16], char *s)
>   {
> ! 	static char *hex = "0123456789abcdef";
>   	int			q,
>   				w;
>   
> --- 271,277 ----
>   static void
>   bytesToHex(uint8 b[16], char *s)
>   {
> ! 	static const char *hex = "0123456789abcdef";
>   	int			q,
>   				w;
>   
> Index: src/interfaces/libpq/fe-auth.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/fe-auth.c,v
> retrieving revision 1.89
> diff -c -r1.89 fe-auth.c
> *** src/interfaces/libpq/fe-auth.c	7 Jan 2004 18:56:29 -0000	1.89
> --- src/interfaces/libpq/fe-auth.c	14 Mar 2004 10:46:55 -0000
> ***************
> *** 590,595 ****
> --- 590,596 ----
>   
>   		case AUTH_REQ_KRB4:
>   #ifdef KRB4
> + 			pglock_thread();
>   			if (pg_krb4_sendauth(PQerrormsg, conn->sock,
>   							   (struct sockaddr_in *) & conn->laddr.addr,
>   							   (struct sockaddr_in *) & conn->raddr.addr,
> ***************
> *** 597,604 ****
> --- 598,607 ----
>   			{
>   				snprintf(PQerrormsg, PQERRORMSG_LENGTH,
>   					libpq_gettext("Kerberos 4 authentication failed\n"));
> + 				pgunlock_thread();
>   				return STATUS_ERROR;
>   			}
> + 			pgunlock_thread();
>   			break;
>   #else
>   			snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> ***************
> *** 608,620 ****
> --- 611,626 ----
>   
>   		case AUTH_REQ_KRB5:
>   #ifdef KRB5
> + 			pglock_thread();
>   			if (pg_krb5_sendauth(PQerrormsg, conn->sock,
>   								 hostname) != STATUS_OK)
>   			{
>   				snprintf(PQerrormsg, PQERRORMSG_LENGTH,
>   					libpq_gettext("Kerberos 5 authentication failed\n"));
> + 				pgunlock_thread();
>   				return STATUS_ERROR;
>   			}
> + 			pgunlock_thread();
>   			break;
>   #else
>   			snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> ***************
> *** 722,727 ****
> --- 728,734 ----
>   	if (authsvc == 0)
>   		return NULL;			/* leave original error message in place */
>   
> + 	pglock_thread();
>   #ifdef KRB4
>   	if (authsvc == STARTUP_KRB4_MSG)
>   		name = pg_krb4_authname(PQerrormsg);
> ***************
> *** 759,763 ****
> --- 766,771 ----
>   
>   	if (name && (authn = (char *) malloc(strlen(name) + 1)))
>   		strcpy(authn, name);
> + 	pgunlock_thread();
>   	return authn;
>   }
> Index: src/interfaces/libpq/fe-connect.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/fe-connect.c,v
> retrieving revision 1.268
> diff -c -r1.268 fe-connect.c
> *** src/interfaces/libpq/fe-connect.c	10 Mar 2004 21:12:47 -0000	1.268
> --- src/interfaces/libpq/fe-connect.c	14 Mar 2004 10:46:56 -0000
> ***************
> *** 2902,2908 ****
>   PQsetClientEncoding(PGconn *conn, const char *encoding)
>   {
>   	char		qbuf[128];
> ! 	static char query[] = "set client_encoding to '%s'";
>   	PGresult   *res;
>   	int			status;
>   
> --- 2902,2908 ----
>   PQsetClientEncoding(PGconn *conn, const char *encoding)
>   {
>   	char		qbuf[128];
> ! 	static const char query[] = "set client_encoding to '%s'";
>   	PGresult   *res;
>   	int			status;
>   
> ***************
> *** 3162,3166 ****
> --- 3162,3207 ----
>   	return NULL;
>   
>   #undef LINELEN
> + }
> + 
> + /*
> +  * To keep the API consistent, the locking stubs are always provided, even
> +  * if they are not required.
> +  */
> + 
> + void
> + PQenableSSLLocks(int enable)
> + {
> + #if defined(ENABLE_THREAD_SAFETY) && defined(USE_SSL)
> + 	pq_usessllocks = enable;
> + #endif
> + }
> + 
> + static pgthreadlock_t default_threadlock;
> + static void
> + default_threadlock(int acquire)
> + {
> + #if defined(ENABLE_THREAD_SAFETY)
> + 	static pthread_mutex_t singlethread_lock = PTHREAD_MUTEX_INITIALIZER;
> + 	if (acquire)
> + 		pthread_mutex_lock(&singlethread_lock);
> + 	else
> + 		pthread_mutex_unlock(&singlethread_lock);
> + #endif
> + }
> + 
> + pgthreadlock_t *g_threadlock = default_threadlock;
> + 
> + pgthreadlock_t *
> + PQregisterThreadLock(pgthreadlock_t *newhandler)
> + {
> + 	pgthreadlock_t *prev;
> + 
> + 	prev = g_threadlock;
> + 	if (newhandler)
> + 		g_threadlock = newhandler;
> + 	else
> + 		g_threadlock = default_threadlock;
> + 	return prev;
>   }
>   
> Index: src/interfaces/libpq/fe-secure.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/fe-secure.c,v
> retrieving revision 1.37
> diff -c -r1.37 fe-secure.c
> *** src/interfaces/libpq/fe-secure.c	10 Feb 2004 15:21:24 -0000	1.37
> --- src/interfaces/libpq/fe-secure.c	14 Mar 2004 10:46:56 -0000
> ***************
> *** 135,145 ****
>   static DH  *load_dh_buffer(const char *, size_t);
>   static DH  *tmp_dh_cb(SSL *s, int is_export, int keylength);
>   static int	client_cert_cb(SSL *, X509 **, EVP_PKEY **);
>   static int	initialize_SSL(PGconn *);
>   static void destroy_SSL(void);
>   static PostgresPollingStatusType open_client_SSL(PGconn *);
>   static void close_SSL(PGconn *);
> ! static const char *SSLerrmessage(void);
>   #endif
>   
>   #ifdef USE_SSL
> --- 135,147 ----
>   static DH  *load_dh_buffer(const char *, size_t);
>   static DH  *tmp_dh_cb(SSL *s, int is_export, int keylength);
>   static int	client_cert_cb(SSL *, X509 **, EVP_PKEY **);
> + static int	init_ssl_system(PGconn *conn);
>   static int	initialize_SSL(PGconn *);
>   static void destroy_SSL(void);
>   static PostgresPollingStatusType open_client_SSL(PGconn *);
>   static void close_SSL(PGconn *);
> ! static char *SSLerrmessage(void);
> ! static void SSLerrfree(char *buf);
>   #endif
>   
>   #ifdef USE_SSL
> ***************
> *** 251,259 ****
>   			!SSL_set_app_data(conn->ssl, conn) ||
>   			!SSL_set_fd(conn->ssl, conn->sock))
>   		{
>   			printfPQExpBuffer(&conn->errorMessage,
>   			   libpq_gettext("could not establish SSL connection: %s\n"),
> ! 							  SSLerrmessage());
>   			close_SSL(conn);
>   			return PGRES_POLLING_FAILED;
>   		}
> --- 253,263 ----
>   			!SSL_set_app_data(conn->ssl, conn) ||
>   			!SSL_set_fd(conn->ssl, conn->sock))
>   		{
> + 			char *err = SSLerrmessage();
>   			printfPQExpBuffer(&conn->errorMessage,
>   			   libpq_gettext("could not establish SSL connection: %s\n"),
> ! 							  err);
> ! 			SSLerrfree(err);
>   			close_SSL(conn);
>   			return PGRES_POLLING_FAILED;
>   		}
> ***************
> *** 327,334 ****
>   					break;
>   				}
>   			case SSL_ERROR_SSL:
> ! 				printfPQExpBuffer(&conn->errorMessage,
> ! 					  libpq_gettext("SSL error: %s\n"), SSLerrmessage());
>   				/* fall through */
>   			case SSL_ERROR_ZERO_RETURN:
>   				SOCK_ERRNO_SET(ECONNRESET);
> --- 331,342 ----
>   					break;
>   				}
>   			case SSL_ERROR_SSL:
> ! 				{
> ! 					char *err = SSLerrmessage();
> ! 					printfPQExpBuffer(&conn->errorMessage,
> ! 						  libpq_gettext("SSL error: %s\n"), err);
> ! 					SSLerrfree(err);
> ! 				}
>   				/* fall through */
>   			case SSL_ERROR_ZERO_RETURN:
>   				SOCK_ERRNO_SET(ECONNRESET);
> ***************
> *** 402,409 ****
>   					break;
>   				}
>   			case SSL_ERROR_SSL:
> ! 				printfPQExpBuffer(&conn->errorMessage,
> ! 					  libpq_gettext("SSL error: %s\n"), SSLerrmessage());
>   				/* fall through */
>   			case SSL_ERROR_ZERO_RETURN:
>   				SOCK_ERRNO_SET(ECONNRESET);
> --- 410,421 ----
>   					break;
>   				}
>   			case SSL_ERROR_SSL:
> ! 				{
> ! 					char *err = SSLerrmessage();
> ! 					printfPQExpBuffer(&conn->errorMessage,
> ! 						  libpq_gettext("SSL error: %s\n"), err);
> ! 					SSLerrfree(err);
> ! 				}
>   				/* fall through */
>   			case SSL_ERROR_ZERO_RETURN:
>   				SOCK_ERRNO_SET(ECONNRESET);
> ***************
> *** 750,758 ****
>   	}
>   	if (PEM_read_X509(fp, x509, NULL, NULL) == NULL)
>   	{
>   		printfPQExpBuffer(&conn->errorMessage,
>   				  libpq_gettext("could not read certificate (%s): %s\n"),
> ! 						  fnbuf, SSLerrmessage());
>   		fclose(fp);
>   		return -1;
>   	}
> --- 762,772 ----
>   	}
>   	if (PEM_read_X509(fp, x509, NULL, NULL) == NULL)
>   	{
> + 		char *err = SSLerrmessage();
>   		printfPQExpBuffer(&conn->errorMessage,
>   				  libpq_gettext("could not read certificate (%s): %s\n"),
> ! 						  fnbuf, err);
> ! 		SSLerrfree(err);
>   		fclose(fp);
>   		return -1;
>   	}
> ***************
> *** 795,803 ****
>   	}
>   	if (PEM_read_PrivateKey(fp, pkey, cb, NULL) == NULL)
>   	{
>   		printfPQExpBuffer(&conn->errorMessage,
>   				  libpq_gettext("could not read private key (%s): %s\n"),
> ! 						  fnbuf, SSLerrmessage());
>   		X509_free(*x509);
>   		fclose(fp);
>   		return -1;
> --- 809,819 ----
>   	}
>   	if (PEM_read_PrivateKey(fp, pkey, cb, NULL) == NULL)
>   	{
> + 		char *err = SSLerrmessage();
>   		printfPQExpBuffer(&conn->errorMessage,
>   				  libpq_gettext("could not read private key (%s): %s\n"),
> ! 						  fnbuf, err);
> ! 		SSLerrfree(err);
>   		X509_free(*x509);
>   		fclose(fp);
>   		return -1;
> ***************
> *** 807,815 ****
>   	/* verify that the cert and key go together */
>   	if (!X509_check_private_key(*x509, *pkey))
>   	{
>   		printfPQExpBuffer(&conn->errorMessage,
>   			libpq_gettext("certificate/private key mismatch (%s): %s\n"),
> ! 						  fnbuf, SSLerrmessage());
>   		X509_free(*x509);
>   		EVP_PKEY_free(*pkey);
>   		return -1;
> --- 823,833 ----
>   	/* verify that the cert and key go together */
>   	if (!X509_check_private_key(*x509, *pkey))
>   	{
> + 		char *err = SSLerrmessage();
>   		printfPQExpBuffer(&conn->errorMessage,
>   			libpq_gettext("certificate/private key mismatch (%s): %s\n"),
> ! 						  fnbuf, err);
> ! 		SSLerrfree(err);
>   		X509_free(*x509);
>   		EVP_PKEY_free(*pkey);
>   		return -1;
> ***************
> *** 819,838 ****
>   #endif
>   }
>   
> ! /*
> !  *	Initialize global SSL context.
> !  */
>   static int
> ! initialize_SSL(PGconn *conn)
>   {
> ! #ifndef WIN32
> ! 	struct stat buf;
> ! 	char		pwdbuf[BUFSIZ];
> ! 	struct passwd pwdstr;
> ! 	struct passwd *pwd = NULL;
> ! 	char		fnbuf[2048];
> ! #endif
>   
>   	if (!SSL_context)
>   	{
>   		SSL_library_init();
> --- 837,888 ----
>   #endif
>   }
>   
> ! #ifdef ENABLE_THREAD_SAFETY
> ! 
> ! static unsigned long
> ! pq_threadidcallback(void)
> ! {
> ! 	return (unsigned long)pthread_self();
> ! }
> ! 
> ! static pthread_rwlock_t *pq_lockarray;
> ! static void
> ! pq_lockingcallback(int mode, int n, const char *file, int line)
> ! {
> ! 	if (mode & CRYPTO_LOCK) {
> ! 		pthread_rwlock_wrlock(&pq_lockarray[n]);
> ! 	} else {
> ! 		pthread_rwlock_unlock(&pq_lockarray[n]);
> ! 	}
> ! }
> ! 
> ! bool pq_usessllocks = true;
> ! 
> ! #endif /* ENABLE_THRAD_SAFETY */
> ! 
>   static int
> ! init_ssl_system(PGconn *conn)
>   {
> ! #ifdef ENABLE_THREAD_SAFETY
> ! static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
> ! 
> ! 	pthread_mutex_lock(&init_mutex);
> ! 	
> ! 	if (pq_usessllocks && pq_lockarray == NULL) {
> ! 		int i;
> ! 		CRYPTO_set_id_callback(pq_threadidcallback);
> ! 
> ! 		pq_lockarray = malloc(sizeof(pthread_rwlock_t)*CRYPTO_num_locks());
> ! 		if (!pq_lockarray) {
> ! 			pthread_mutex_unlock(&init_mutex);
> ! 			return -1;
> ! 		}
> ! 		for (i=0;i<CRYPTO_num_locks();i++)
> ! 			pthread_rwlock_init(&pq_lockarray[i], NULL);
>   
> + 		CRYPTO_set_locking_callback(pq_lockingcallback);
> + 	}
> + #endif
>   	if (!SSL_context)
>   	{
>   		SSL_library_init();
> ***************
> *** 840,851 ****
>   		SSL_context = SSL_CTX_new(TLSv1_method());
>   		if (!SSL_context)
>   		{
>   			printfPQExpBuffer(&conn->errorMessage,
>   					 libpq_gettext("could not create SSL context: %s\n"),
> ! 							  SSLerrmessage());
>   			return -1;
>   		}
>   	}
>   
>   #ifndef WIN32
>   	if (pqGetpwuid(getuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) == 0)
> --- 890,927 ----
>   		SSL_context = SSL_CTX_new(TLSv1_method());
>   		if (!SSL_context)
>   		{
> + 			char *err = SSLerrmessage();
>   			printfPQExpBuffer(&conn->errorMessage,
>   					 libpq_gettext("could not create SSL context: %s\n"),
> ! 							  err);
> ! 			SSLerrfree(err);
> ! #ifdef ENABLE_THREAD_SAFETY
> ! 			pthread_mutex_unlock(&init_mutex);
> ! #endif
>   			return -1;
>   		}
>   	}
> + #ifdef ENABLE_THREAD_SAFETY
> + 	pthread_mutex_unlock(&init_mutex);
> + #endif
> + 	return 0;
> + }
> + /*
> +  *	Initialize global SSL context.
> +  */
> + static int
> + initialize_SSL(PGconn *conn)
> + {
> + #ifndef WIN32
> + 	struct stat buf;
> + 	char		pwdbuf[BUFSIZ];
> + 	struct passwd pwdstr;
> + 	struct passwd *pwd = NULL;
> + 	char		fnbuf[2048];
> + #endif
> + 
> + 	if(!init_ssl_system(conn))
> + 		return -1;
>   
>   #ifndef WIN32
>   	if (pqGetpwuid(getuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) == 0)
> ***************
> *** 867,875 ****
>   		}
>   		if (!SSL_CTX_load_verify_locations(SSL_context, fnbuf, 0))
>   		{
>   			printfPQExpBuffer(&conn->errorMessage,
>   							  libpq_gettext("could not read root certificate list (%s): %s\n"),
> ! 							  fnbuf, SSLerrmessage());
>   			return -1;
>   		}
>   	}
> --- 943,953 ----
>   		}
>   		if (!SSL_CTX_load_verify_locations(SSL_context, fnbuf, 0))
>   		{
> + 			char *err = SSLerrmessage();
>   			printfPQExpBuffer(&conn->errorMessage,
>   							  libpq_gettext("could not read root certificate list (%s): %s\n"),
> ! 							  fnbuf, err);
> ! 			SSLerrfree(err);
>   			return -1;
>   		}
>   	}
> ***************
> *** 936,945 ****
>   					return PGRES_POLLING_FAILED;
>   				}
>   			case SSL_ERROR_SSL:
> ! 				printfPQExpBuffer(&conn->errorMessage,
> ! 					  libpq_gettext("SSL error: %s\n"), SSLerrmessage());
> ! 				close_SSL(conn);
> ! 				return PGRES_POLLING_FAILED;
>   
>   			default:
>   				printfPQExpBuffer(&conn->errorMessage,
> --- 1014,1027 ----
>   					return PGRES_POLLING_FAILED;
>   				}
>   			case SSL_ERROR_SSL:
> ! 				{
> ! 					char *err = SSLerrmessage();
> ! 					printfPQExpBuffer(&conn->errorMessage,
> ! 						  libpq_gettext("SSL error: %s\n"), err);
> ! 					SSLerrfree(err);
> ! 					close_SSL(conn);
> ! 					return PGRES_POLLING_FAILED;
> ! 				}
>   
>   			default:
>   				printfPQExpBuffer(&conn->errorMessage,
> ***************
> *** 973,981 ****
>   	conn->peer = SSL_get_peer_certificate(conn->ssl);
>   	if (conn->peer == NULL)
>   	{
>   		printfPQExpBuffer(&conn->errorMessage,
>   				libpq_gettext("certificate could not be obtained: %s\n"),
> ! 						  SSLerrmessage());
>   		close_SSL(conn);
>   		return PGRES_POLLING_FAILED;
>   	}
> --- 1055,1065 ----
>   	conn->peer = SSL_get_peer_certificate(conn->ssl);
>   	if (conn->peer == NULL)
>   	{
> + 		char *err = SSLerrmessage();
>   		printfPQExpBuffer(&conn->errorMessage,
>   				libpq_gettext("certificate could not be obtained: %s\n"),
> ! 						  err);
> ! 		SSLerrfree(err);
>   		close_SSL(conn);
>   		return PGRES_POLLING_FAILED;
>   	}
> ***************
> *** 1036,1058 ****
>    * return NULL if it doesn't recognize the error code.  We don't
>    * want to return NULL ever.
>    */
> ! static const char *
>   SSLerrmessage(void)
>   {
>   	unsigned long errcode;
>   	const char *errreason;
> ! 	static char errbuf[32];
>   
>   	errcode = ERR_get_error();
> ! 	if (errcode == 0)
> ! 		return "No SSL error reported";
>   	errreason = ERR_reason_error_string(errcode);
> ! 	if (errreason != NULL)
> ! 		return errreason;
> ! 	snprintf(errbuf, sizeof(errbuf), "SSL error code %lu", errcode);
>   	return errbuf;
>   }
>   
>   /*
>    *	Return pointer to SSL object.
>    */
> --- 1120,1159 ----
>    * return NULL if it doesn't recognize the error code.  We don't
>    * want to return NULL ever.
>    */
> ! static char ssl_nomem[] = "Out of memory allocating error description";
> ! #define SSL_ERR_LEN	128
> ! 
> ! static char *
>   SSLerrmessage(void)
>   {
>   	unsigned long errcode;
>   	const char *errreason;
> ! 	char *errbuf;
>   
> + 	errbuf = malloc(SSL_ERR_LEN);
> + 	if (!errbuf)
> + 		return ssl_nomem;
>   	errcode = ERR_get_error();
> ! 	if (errcode == 0) {
> ! 		strcpy(errbuf, "No SSL error reported");
> ! 		return errbuf;
> ! 	}
>   	errreason = ERR_reason_error_string(errcode);
> ! 	if (errreason != NULL) {
> ! 		strncpy(errbuf, errreason, SSL_ERR_LEN-1);
> ! 		errbuf[SSL_ERR_LEN-1] = '\0';
> ! 		return errbuf;
> ! 	}
> ! 	snprintf(errbuf, SSL_ERR_LEN, "SSL error code %lu", errcode);
>   	return errbuf;
>   }
>   
> + static void
> + SSLerrfree(char *buf)
> + {
> + 	if (buf != ssl_nomem)
> + 		free(buf);
> + }
>   /*
>    *	Return pointer to SSL object.
>    */
> Index: src/interfaces/libpq/libpq-fe.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/libpq-fe.h,v
> retrieving revision 1.102
> diff -c -r1.102 libpq-fe.h
> *** src/interfaces/libpq/libpq-fe.h	9 Jan 2004 02:02:43 -0000	1.102
> --- src/interfaces/libpq/libpq-fe.h	14 Mar 2004 10:46:57 -0000
> ***************
> *** 274,279 ****
> --- 274,293 ----
>   					 PQnoticeProcessor proc,
>   					 void *arg);
>   
> + /*
> +  *     Used to set callback that prevents concurrent access to
> +  *     non-thread safe functions that libpq needs.
> +  *     The default implementation uses a libpq internal mutex.
> +  *     Only required for multithreaded apps that use kerberos
> +  *     both within their app and for postgresql connections.
> +  */
> + typedef void (pgthreadlock_t)(int acquire);
> + 
> + extern pgthreadlock_t * PQregisterThreadLock(pgthreadlock_t *newhandler);
> + 
> + void
> + PQenableSSLLocks(int enable);
> + 
>   /* === in fe-exec.c === */
>   
>   /* Simple synchronous query */
> Index: src/interfaces/libpq/libpq-int.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/libpq-int.h,v
> retrieving revision 1.85
> diff -c -r1.85 libpq-int.h
> *** src/interfaces/libpq/libpq-int.h	5 Mar 2004 01:53:59 -0000	1.85
> --- src/interfaces/libpq/libpq-int.h	14 Mar 2004 10:46:57 -0000
> ***************
> *** 359,364 ****
> --- 359,374 ----
>   extern int pqPacketSend(PGconn *conn, char pack_type,
>   			 const void *buf, size_t buf_len);
>   
> + #ifdef ENABLE_THREAD_SAFETY
> + extern pgthreadlock_t *g_threadlock;
> + #define pglock_thread() g_threadlock(true);
> + #define pgunlock_thread() g_threadlock(false);
> + #else
> + #define pglock_thread() ((void)0)
> + #define pgunlock_thread() ((void)0)
> + #endif
> + 	 
> + 
>   /* === in fe-exec.c === */
>   
>   extern void pqSetResultError(PGresult *res, const char *msg);
> ***************
> *** 448,453 ****
> --- 458,464 ----
>   #ifdef ENABLE_THREAD_SAFETY
>   extern void check_sigpipe_handler(void);
>   extern pthread_key_t thread_in_send;
> + extern bool pq_usessllocks;
>   #endif
>   
>   /*

> Index: src/interfaces/libpq/fe-secure.c
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/fe-secure.c,v
> retrieving revision 1.37
> diff -c -r1.37 fe-secure.c
> *** src/interfaces/libpq/fe-secure.c	10 Feb 2004 15:21:24 -0000	1.37
> --- src/interfaces/libpq/fe-secure.c	14 Mar 2004 08:31:48 -0000
> ***************
> *** 1077,1096 ****
>   	pqsigfunc pipehandler;
>   
>   	/*
>   	 *	If the app hasn't set a SIGPIPE handler, define our own
>   	 *	that ignores SIGPIPE on libpq send() and does SIG_DFL
>   	 *	for other SIGPIPE cases.
>   	 */
>   	pipehandler = pqsignalinquire(SIGPIPE);
>   	if (pipehandler == SIG_DFL)	/* not set by application */
> - 	{
> - 		/*
> - 		 *	Create key first because the signal handler might be called
> - 		 *	right after being installed.
> - 		 */
> - 		pthread_key_create(&thread_in_send, NULL);	
>   		pqsignal(SIGPIPE, sigpipe_handler_ignore_send);
> - 	}
>   }
>   
>   /*
> --- 1077,1096 ----
>   	pqsigfunc pipehandler;
>   
>   	/*
> + 	 * 	Always create the key for SIGPIPE handling - PQinSend needs
> + 	 * 	it. Create it first because the signal handler might be called
> + 	 *	right after being installed.
> + 	 */
> + 	pthread_key_create(&thread_in_send, NULL);	
> + 
> + 	/*
>   	 *	If the app hasn't set a SIGPIPE handler, define our own
>   	 *	that ignores SIGPIPE on libpq send() and does SIG_DFL
>   	 *	for other SIGPIPE cases.
>   	 */
>   	pipehandler = pqsignalinquire(SIGPIPE);
>   	if (pipehandler == SIG_DFL)	/* not set by application */
>   		pqsignal(SIGPIPE, sigpipe_handler_ignore_send);
>   }
>   
>   /*

> 
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
> 
>                http://www.postgresql.org/docs/faqs/FAQ.html

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman(at)candle(dot)pha(dot)pa(dot)us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073

In response to

Responses

pgsql-hackers by date

Next:From: Bruce MomjianDate: 2004-03-22 04:00:46
Subject: Re: pg_autovacuum next steps
Previous:From: Gavin SherryDate: 2004-03-22 03:38:34
Subject: Re: pg_autovacuum next steps

pgsql-patches by date

Next:From: Bruce MomjianDate: 2004-03-22 03:57:33
Subject: Re: Another pg_autovacuum patch
Previous:From: Bruce MomjianDate: 2004-03-22 03:38:53
Subject: Re: change output of \dp

Privacy Policy | About PostgreSQL
Copyright © 1996-2014 The PostgreSQL Global Development Group