Re: [HACKERS] libpq thread safety - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | Re: [HACKERS] libpq thread safety |
Date | |
Msg-id | 200403220349.i2M3n9e12658@candle.pha.pa.us Whole thread Raw |
Responses |
Re: [HACKERS] libpq thread safety
|
List | pgsql-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@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073
pgsql-patches by date: