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.

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


Manfred Spraul wrote:
> Bruce Momjian wrote:
> 
> >What killed the idea of doing ssl or kerberos locking inside libpq was
> >that there was no way to be sure that outside code didn't also access
> >those routines.
> >
> A callback based implementation can handle that: libpq has a default 
> implementation for apps that do not use openssl or kerberos themself. If 
> the app wants to use the libraries, too, then it must replace the hooks 
> with their own locks.
> 
> I've attached a simple proposal, just for kerberos 4. If you agree on 
> the general approach, I'll add it to all functions that are not thread safe.
> 
> >  I have documented that SSL and Kerberos are not
> >thread-safe in the libpq docs.  Let's wait and see If we need additional
> >work in this area.
> >  
> >
> It means that multithreading is not usable: As Tom explained, the 
> connect string is often set directly by the end user. Setting "sslmode" 
> would result is races - impossible to support. In the very least, 
> sslmode and Kerberos would have to fail if the app is multithreaded.
> 
> --
>     Manfred

> 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 -u -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    12 Mar 2004 20:07:02 -0000
> @@ -590,6 +590,7 @@
>  
>               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,8 +598,10 @@
>                       {
>                               snprintf(PQerrormsg, PQERRORMSG_LENGTH,
>                                       libpq_gettext("Kerberos 4 authentication 
> failed\n"));
> +                             pgunlock_thread();
>                               return STATUS_ERROR;
>                       }
> +                     pgunlock_thread();
>                       break;
>  #else
>                       snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> @@ -722,6 +725,7 @@
>       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,5 +763,6 @@
>  
>       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 -u -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 12 Mar 2004 20:07:03 -0000
> @@ -3163,4 +3163,34 @@
>  
>  #undef LINELEN
>  }
> +/*
> + * To keep the API consistent, the locking stubs are always provided, even
> + * if they are not required.
> + */
> +pgthreadlock_t *g_threadlock;
>  
> +static pgthreadlock_t default_threadlock;
> +static void
> +default_threadlock(bool 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 *
> +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/libpq-fe.h
> ===================================================================
> RCS file: /projects/cvsroot/pgsql-server/src/interfaces/libpq/libpq-fe.h,v
> retrieving revision 1.102
> diff -u -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   12 Mar 2004 20:07:03 -0000
> @@ -274,6 +274,22 @@
>                                        PQnoticeProcessor proc,
>                                        void *arg);
>  
> +typedef void (pgsigpipehandler_t)(bool enable, void **state);
> +
> +extern pgsigpipehandler_t *
> +PQregisterSigpipeCallback(pgsigpipehandler_t *newhandler);
> +
> +/*
> + *     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)(bool acquire);
> +
> +extern pgthreadlock_t * PQregisterThreadLock(pgthreadlock_t *newhandler);
> +
>  /* === 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 -u -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  12 Mar 2004 20:07:03 -0000
> @@ -359,6 +359,16 @@
>  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);

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

---------------------------(end of broadcast)---------------------------
TIP 9: the planner will ignore your desire to choose an index scan if your
      joining column's datatypes do not match

Reply via email to