Thread: Re: [HACKERS] PostgreSQL libraries - PThread Support, but not use...
Patches attached to make libpq thread-safe, now uses strerror_r(), gethostbyname_r(), getpwuid_r() and crypt_r() where available. Where strtok() was previously used strchr() is now used. Thanks, Lee. Lee Kindness writes: > Tom Lane writes: > > Bruce Momjian <pgman@candle.pha.pa.us> writes: > > > We have definatly had requests for improved thread-safeness for libpq > > > and ecpg in the past, so whatever you can do would be a help. We say > > > libpq is thread-safe, but specifically mention the non-threadsafe calls > > > in the libpq documentation, or at least we should. > > We do: > > http://www.ca.postgresql.org/users-lounge/docs/7.3/postgres/libpq-threading.html > > But Lee's point about depending on possibly-unsafe libc routines is a > > good one. I don't think anyone's gone through the code with an eye to > > that. > > Right, so a reasonable angle for me to take is to go through the libpq > source looking for potential problem areas and use of "known bad" > functions. I can add autoconf checks for the replacement *_r() > functions, and use these in place of the traditional ones where > available. > > If any function is found to be not thread-safe and cannot be made so > using standard library calls then it needs to be documented as such > both in the source and the aforementioned documentation. > > This approach avoids any thread library dependencies and documents the > current state of play WRT thread safety (i.e it's a good, and needed, > basis for any later work). > > ECPG is a separate issue, and best handled as such (it will need > thread calls). I'll post a patch for it at a later date so the changes > are available to anyone who wants to play with ECPG and threads. > > Ta, Lee.
Attachment
Lee Kindness <lkindness@csl.co.uk> writes: > + #define _THREAD_SAFE > + #define _REENTRANT > + #define _POSIX_PTHREAD_SEMANTICS What is this stuff, and why isn't it wrapped in any sort of platform-specific test? If it's needed, why is it in only one .c file? Also, haven't you broken SOCK_STRERROR for the Windows case? regards, tom lane
Tom, Tom Lane writes: > Lee Kindness <lkindness@csl.co.uk> writes: > > + #define _THREAD_SAFE > > + #define _REENTRANT > > + #define _POSIX_PTHREAD_SEMANTICS > What is this stuff, and why isn't it wrapped in any sort of > platform-specific test? If it's needed, why is it in only one .c > file? It's actually in libpq-int.h too... The correct way for this is to compile with the compilers specific thread flags, however the downside to this has already been discussed. Depending on the system one, or a combination of those flags will turn on some magic such as errno being a function call rather than a global variable. This is needed to make the library thread safe. On a second look libpq-int.h isn't the best place for this (hence it also appears in one of the C files), it needs to be done in each C file before any of the system headers are included - a libpq-threads.h header? Would this be ok? Do do things 100% right we'd need to detect compiler thread flags and compile with them... > Also, haven't you broken SOCK_STRERROR for the Windows case? Sorry, I seem to have forgotton to update the prototype in win32.h to match the updated function. Updated diff attached (and online). Lee.
Attachment
Lee Kindness writes: > Patches attached to make libpq thread-safe, now uses strerror_r(), > gethostbyname_r(), getpwuid_r() and crypt_r() where available. Where > strtok() was previously used strchr() is now used. AC_TRY_RUN tests are prohibited. Also, try to factor out some of these huge tests into separate macros and put them into config/c-library.m4. And it would be nice if there was some documentation about what was checked for. If you just want to check whether gethostbyname_r() has 5 or 6 arguments you can do that in half the space. -- Peter Eisentraut peter_e@gmx.net
Patch attached, along with new libpq-reentrant.c and libpq-reentrant.h files for src/interfaces/libpq. Also at http://services.csl.co.uk/postgresql/ Thanks, Lee. Lee Kindness writes: > Ok guys, I propose that the new libpq diff and 2 source files which > i'll soon send to pgsql-patches is applied to the source. This diff is > a cleaned up version of the previous version with the wrapper > functions moved out into their own file and more comments added. Also > the use of crypt_r() has been removed (not worth the effort), the > cpp defines have been renamed to be consistent with each other and > Tom's concerns with loose #defines has been partly addressed. > > This diff does not include any configure changes. I plan to tackle > this separately ASAP, and hopefully produce something more acceptable. > > I will add checks for appropriate compiler thread flags (for compiling > libpq, and alow the removal of #defines in libpq-reentrant.h), and > link flags & libs (for a planned threaded libpq test program and > renentrant ecpg library). If a thread environment is found then check > for the reentrant functions will be done. > > Looking at various open source projects configure.in files there seems > to be little commonality in the thread test macros (telp gratefully > accepted!), I currently think that something like the approach used by > glib is most suitable (switch on OS). > > All sound acceptable? > > Thanks, Lee. > > Peter Eisentraut writes: > > Lee Kindness writes: > > > > > Patches attached to make libpq thread-safe, now uses strerror_r(), > > > gethostbyname_r(), getpwuid_r() and crypt_r() where available. Where > > > strtok() was previously used strchr() is now used. > > > > AC_TRY_RUN tests are prohibited. Also, try to factor out some of these > > huge tests into separate macros and put them into config/c-library.m4. > > And it would be nice if there was some documentation about what was > > checked for. If you just want to check whether gethostbyname_r() has 5 or > > 6 arguments you can do that in half the space.
Attachment
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. --------------------------------------------------------------------------- Lee Kindness wrote: Content-Description: message body text > Patch attached, along with new libpq-reentrant.c and libpq-reentrant.h > files for src/interfaces/libpq. > > Also at http://services.csl.co.uk/postgresql/ > > Thanks, Lee. > > Lee Kindness writes: > > Ok guys, I propose that the new libpq diff and 2 source files which > > i'll soon send to pgsql-patches is applied to the source. This diff is > > a cleaned up version of the previous version with the wrapper > > functions moved out into their own file and more comments added. Also > > the use of crypt_r() has been removed (not worth the effort), the > > cpp defines have been renamed to be consistent with each other and > > Tom's concerns with loose #defines has been partly addressed. > > > > This diff does not include any configure changes. I plan to tackle > > this separately ASAP, and hopefully produce something more acceptable. > > > > I will add checks for appropriate compiler thread flags (for compiling > > libpq, and alow the removal of #defines in libpq-reentrant.h), and > > link flags & libs (for a planned threaded libpq test program and > > renentrant ecpg library). If a thread environment is found then check > > for the reentrant functions will be done. > > > > Looking at various open source projects configure.in files there seems > > to be little commonality in the thread test macros (telp gratefully > > accepted!), I currently think that something like the approach used by > > glib is most suitable (switch on OS). > > > > All sound acceptable? > > > > Thanks, Lee. > > > > Peter Eisentraut writes: > > > Lee Kindness writes: > > > > > > > Patches attached to make libpq thread-safe, now uses strerror_r(), > > > > gethostbyname_r(), getpwuid_r() and crypt_r() where available. Where > > > > strtok() was previously used strchr() is now used. > > > > > > AC_TRY_RUN tests are prohibited. Also, try to factor out some of these > > > huge tests into separate macros and put them into config/c-library.m4. > > > And it would be nice if there was some documentation about what was > > > checked for. If you just want to check whether gethostbyname_r() has 5 or > > > 6 arguments you can do that in half the space. > [ Attachment, skipping... ] [ Attachment, skipping... ] [ Attachment, skipping... ] -- 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
Lee, I have a question about this code: char *pqStrerror(int errnum, char *strerrbuf, size_t buflen) { #if defined HAVE_STRERROR_R /* reentrant strerror_r is available */ strerror_r(errnum, strerrbuf, buflen); return strerrbuf; #elif defined HAVE_NONPOSIX_STRERROR_R /* broken (well early POSIX draft) strerror_r() which returns 'char *' */ return strerror_r(errnum, strerrbuf, buflen); #else /* no strerror_r() available, just use strerror */ return strerror(errnum); #endif } Why do we have to care about HAVE_NONPOSIX_STRERROR_R? Can't we just use the HAVE_STRERROR_R code in all cases? --------------------------------------------------------------------------- Lee Kindness wrote: Content-Description: message body text > Patch attached, along with new libpq-reentrant.c and libpq-reentrant.h > files for src/interfaces/libpq. > > Also at http://services.csl.co.uk/postgresql/ > > Thanks, Lee. > > Lee Kindness writes: > > Ok guys, I propose that the new libpq diff and 2 source files which > > i'll soon send to pgsql-patches is applied to the source. This diff is > > a cleaned up version of the previous version with the wrapper > > functions moved out into their own file and more comments added. Also > > the use of crypt_r() has been removed (not worth the effort), the > > cpp defines have been renamed to be consistent with each other and > > Tom's concerns with loose #defines has been partly addressed. > > > > This diff does not include any configure changes. I plan to tackle > > this separately ASAP, and hopefully produce something more acceptable. > > > > I will add checks for appropriate compiler thread flags (for compiling > > libpq, and alow the removal of #defines in libpq-reentrant.h), and > > link flags & libs (for a planned threaded libpq test program and > > renentrant ecpg library). If a thread environment is found then check > > for the reentrant functions will be done. > > > > Looking at various open source projects configure.in files there seems > > to be little commonality in the thread test macros (telp gratefully > > accepted!), I currently think that something like the approach used by > > glib is most suitable (switch on OS). > > > > All sound acceptable? > > > > Thanks, Lee. > > > > Peter Eisentraut writes: > > > Lee Kindness writes: > > > > > > > Patches attached to make libpq thread-safe, now uses strerror_r(), > > > > gethostbyname_r(), getpwuid_r() and crypt_r() where available. Where > > > > strtok() was previously used strchr() is now used. > > > > > > AC_TRY_RUN tests are prohibited. Also, try to factor out some of these > > > huge tests into separate macros and put them into config/c-library.m4. > > > And it would be nice if there was some documentation about what was > > > checked for. If you just want to check whether gethostbyname_r() has 5 or > > > 6 arguments you can do that in half the space. > [ Attachment, skipping... ] [ Attachment, skipping... ] [ Attachment, skipping... ] -- 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
Your call, but the "broken" call is in earlier glibc versions for sure (if you're on a Linux box take a look in /usr/include - the prototype is still there, may even get used depending on compiler options!). I seem to remember compiling this on recent Solaris, HPUX, Linux and AIX versions without hitting the "broken" version, but... L. Bruce Momjian writes: > > Lee, I have a question about this code: > > char *pqStrerror(int errnum, char *strerrbuf, size_t buflen) > { > #if defined HAVE_STRERROR_R > /* reentrant strerror_r is available */ > strerror_r(errnum, strerrbuf, buflen); > return strerrbuf; > #elif defined HAVE_NONPOSIX_STRERROR_R > /* broken (well early POSIX draft) strerror_r() which returns 'char *' */ > return strerror_r(errnum, strerrbuf, buflen); > #else > /* no strerror_r() available, just use strerror */ > return strerror(errnum); > #endif > } > > Why do we have to care about HAVE_NONPOSIX_STRERROR_R? Can't we just > use the HAVE_STRERROR_R code in all cases? > > --------------------------------------------------------------------------- > > Lee Kindness wrote: > Content-Description: message body text > > > Patch attached, along with new libpq-reentrant.c and libpq-reentrant.h > > files for src/interfaces/libpq. > > > > Also at http://services.csl.co.uk/postgresql/ > > > > Thanks, Lee. > > > > Lee Kindness writes: > > > Ok guys, I propose that the new libpq diff and 2 source files which > > > i'll soon send to pgsql-patches is applied to the source. This diff is > > > a cleaned up version of the previous version with the wrapper > > > functions moved out into their own file and more comments added. Also > > > the use of crypt_r() has been removed (not worth the effort), the > > > cpp defines have been renamed to be consistent with each other and > > > Tom's concerns with loose #defines has been partly addressed. > > > > > > This diff does not include any configure changes. I plan to tackle > > > this separately ASAP, and hopefully produce something more acceptable. > > > > > > I will add checks for appropriate compiler thread flags (for compiling > > > libpq, and alow the removal of #defines in libpq-reentrant.h), and > > > link flags & libs (for a planned threaded libpq test program and > > > renentrant ecpg library). If a thread environment is found then check > > > for the reentrant functions will be done. > > > > > > Looking at various open source projects configure.in files there seems > > > to be little commonality in the thread test macros (telp gratefully > > > accepted!), I currently think that something like the approach used by > > > glib is most suitable (switch on OS). > > > > > > All sound acceptable? > > > > > > Thanks, Lee. > > > > > > Peter Eisentraut writes: > > > > Lee Kindness writes: > > > > > > > > > Patches attached to make libpq thread-safe, now uses strerror_r(), > > > > > gethostbyname_r(), getpwuid_r() and crypt_r() where available. Where > > > > > strtok() was previously used strchr() is now used. > > > > > > > > AC_TRY_RUN tests are prohibited. Also, try to factor out some of these > > > > huge tests into separate macros and put them into config/c-library.m4. > > > > And it would be nice if there was some documentation about what was > > > > checked for. If you just want to check whether gethostbyname_r() has 5 or > > > > 6 arguments you can do that in half the space. > > > > [ Attachment, skipping... ] > > [ Attachment, skipping... ] > > [ Attachment, skipping... ] > > -- > 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
My point is why do we care whether it returns char * or nothing --- we should just return strerrbuf in all cases. --------------------------------------------------------------------------- Lee Kindness wrote: > Your call, but the "broken" call is in earlier glibc versions for > sure (if you're on a Linux box take a look in /usr/include - the > prototype is still there, may even get used depending on compiler > options!). I seem to remember compiling this on recent Solaris, HPUX, > Linux and AIX versions without hitting the "broken" version, but... > > L. > > Bruce Momjian writes: > > > > Lee, I have a question about this code: > > > > char *pqStrerror(int errnum, char *strerrbuf, size_t buflen) > > { > > #if defined HAVE_STRERROR_R > > /* reentrant strerror_r is available */ > > strerror_r(errnum, strerrbuf, buflen); > > return strerrbuf; > > #elif defined HAVE_NONPOSIX_STRERROR_R > > /* broken (well early POSIX draft) strerror_r() which returns 'char *' */ > > return strerror_r(errnum, strerrbuf, buflen); > > #else > > /* no strerror_r() available, just use strerror */ > > return strerror(errnum); > > #endif > > } > > > > Why do we have to care about HAVE_NONPOSIX_STRERROR_R? Can't we just > > use the HAVE_STRERROR_R code in all cases? > > > > --------------------------------------------------------------------------- > > > > Lee Kindness wrote: > > Content-Description: message body text > > > > > Patch attached, along with new libpq-reentrant.c and libpq-reentrant.h > > > files for src/interfaces/libpq. > > > > > > Also at http://services.csl.co.uk/postgresql/ > > > > > > Thanks, Lee. > > > > > > Lee Kindness writes: > > > > Ok guys, I propose that the new libpq diff and 2 source files which > > > > i'll soon send to pgsql-patches is applied to the source. This diff is > > > > a cleaned up version of the previous version with the wrapper > > > > functions moved out into their own file and more comments added. Also > > > > the use of crypt_r() has been removed (not worth the effort), the > > > > cpp defines have been renamed to be consistent with each other and > > > > Tom's concerns with loose #defines has been partly addressed. > > > > > > > > This diff does not include any configure changes. I plan to tackle > > > > this separately ASAP, and hopefully produce something more acceptable. > > > > > > > > I will add checks for appropriate compiler thread flags (for compiling > > > > libpq, and alow the removal of #defines in libpq-reentrant.h), and > > > > link flags & libs (for a planned threaded libpq test program and > > > > renentrant ecpg library). If a thread environment is found then check > > > > for the reentrant functions will be done. > > > > > > > > Looking at various open source projects configure.in files there seems > > > > to be little commonality in the thread test macros (telp gratefully > > > > accepted!), I currently think that something like the approach used by > > > > glib is most suitable (switch on OS). > > > > > > > > All sound acceptable? > > > > > > > > Thanks, Lee. > > > > > > > > Peter Eisentraut writes: > > > > > Lee Kindness writes: > > > > > > > > > > > Patches attached to make libpq thread-safe, now uses strerror_r(), > > > > > > gethostbyname_r(), getpwuid_r() and crypt_r() where available. Where > > > > > > strtok() was previously used strchr() is now used. > > > > > > > > > > AC_TRY_RUN tests are prohibited. Also, try to factor out some of these > > > > > huge tests into separate macros and put them into config/c-library.m4. > > > > > And it would be nice if there was some documentation about what was > > > > > checked for. If you just want to check whether gethostbyname_r() has 5 or > > > > > 6 arguments you can do that in half the space. > > > > > > > [ Attachment, skipping... ] > > > > [ Attachment, skipping... ] > > > > [ Attachment, skipping... ] > > > > -- > > 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 > -- 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
Bruce Momjian writes: > My point is why do we care whether it returns char * or nothing --- we > should just return strerrbuf in all cases. Ok, I see. Guess that is reasonable. L.
Lee, I have been looking at the code, and though the quoted function is OK to avoid the non-posix case, it seems the later ones are a problem: #if defined HAVE_NONPOSIX_GETPWUID_R /* broken (well early POSIX draft) getpwuid_r() which returns * 'struct passwd *' */ *result = getpwuid_r(uid, resultbuf, buffer, buflen); #else /* no getpwuid_r() available, just use getpwuid() */ *result = getpwuid(uid); #endif /* HAVE_NONPOSIX_GETPWUID_R */ return( (*result == NULL) ? -1 : 0 ); In this case, what logic do we use? Seems you don't want to use getpwuid_r if it exists, but only if getpwuid isn't thread safe, and I have no idea how do to this. Can we just use the *_r versions if they exist? --------------------------------------------------------------------------- Bruce Momjian wrote: > > Lee, I have a question about this code: > > char *pqStrerror(int errnum, char *strerrbuf, size_t buflen) > { > #if defined HAVE_STRERROR_R > /* reentrant strerror_r is available */ > strerror_r(errnum, strerrbuf, buflen); > return strerrbuf; > #elif defined HAVE_NONPOSIX_STRERROR_R > /* broken (well early POSIX draft) strerror_r() which returns 'char *' */ > return strerror_r(errnum, strerrbuf, buflen); > #else > /* no strerror_r() available, just use strerror */ > return strerror(errnum); > #endif > } > > Why do we have to care about HAVE_NONPOSIX_STRERROR_R? Can't we just > use the HAVE_STRERROR_R code in all cases? > > --------------------------------------------------------------------------- > > Lee Kindness wrote: > Content-Description: message body text > > > Patch attached, along with new libpq-reentrant.c and libpq-reentrant.h > > files for src/interfaces/libpq. > > > > Also at http://services.csl.co.uk/postgresql/ > > > > Thanks, Lee. > > > > Lee Kindness writes: > > > Ok guys, I propose that the new libpq diff and 2 source files which > > > i'll soon send to pgsql-patches is applied to the source. This diff is > > > a cleaned up version of the previous version with the wrapper > > > functions moved out into their own file and more comments added. Also > > > the use of crypt_r() has been removed (not worth the effort), the > > > cpp defines have been renamed to be consistent with each other and > > > Tom's concerns with loose #defines has been partly addressed. > > > > > > This diff does not include any configure changes. I plan to tackle > > > this separately ASAP, and hopefully produce something more acceptable. > > > > > > I will add checks for appropriate compiler thread flags (for compiling > > > libpq, and alow the removal of #defines in libpq-reentrant.h), and > > > link flags & libs (for a planned threaded libpq test program and > > > renentrant ecpg library). If a thread environment is found then check > > > for the reentrant functions will be done. > > > > > > Looking at various open source projects configure.in files there seems > > > to be little commonality in the thread test macros (telp gratefully > > > accepted!), I currently think that something like the approach used by > > > glib is most suitable (switch on OS). > > > > > > All sound acceptable? > > > > > > Thanks, Lee. > > > > > > Peter Eisentraut writes: > > > > Lee Kindness writes: > > > > > > > > > Patches attached to make libpq thread-safe, now uses strerror_r(), > > > > > gethostbyname_r(), getpwuid_r() and crypt_r() where available. Where > > > > > strtok() was previously used strchr() is now used. > > > > > > > > AC_TRY_RUN tests are prohibited. Also, try to factor out some of these > > > > huge tests into separate macros and put them into config/c-library.m4. > > > > And it would be nice if there was some documentation about what was > > > > checked for. If you just want to check whether gethostbyname_r() has 5 or > > > > 6 arguments you can do that in half the space. > > > > [ Attachment, skipping... ] > > [ Attachment, skipping... ] > > [ Attachment, skipping... ] > > -- > 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 > > ---------------------------(end of broadcast)--------------------------- > TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org > -- 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
I see these in the patch: /* Setup _THREAD_SAFE and _POSIX_PTHREAD_SEMANTICS, this will disappear * in time once tests to determine correct compiler switches for threads * are added to configure. */ #if !defined _THREAD_SAFE #define _THREAD_SAFE #endif #if !defined _POSIX_PTHREAD_SEMANTICS #define _POSIX_PTHREAD_SEMANTICS #endif What platforms use these? Linux? I don't see them on BSD/OS. --------------------------------------------------------------------------- Lee Kindness wrote: Content-Description: message body text > Patch attached, along with new libpq-reentrant.c and libpq-reentrant.h > files for src/interfaces/libpq. > > Also at http://services.csl.co.uk/postgresql/ > > Thanks, Lee. > > Lee Kindness writes: > > Ok guys, I propose that the new libpq diff and 2 source files which > > i'll soon send to pgsql-patches is applied to the source. This diff is > > a cleaned up version of the previous version with the wrapper > > functions moved out into their own file and more comments added. Also > > the use of crypt_r() has been removed (not worth the effort), the > > cpp defines have been renamed to be consistent with each other and > > Tom's concerns with loose #defines has been partly addressed. > > > > This diff does not include any configure changes. I plan to tackle > > this separately ASAP, and hopefully produce something more acceptable. > > > > I will add checks for appropriate compiler thread flags (for compiling > > libpq, and alow the removal of #defines in libpq-reentrant.h), and > > link flags & libs (for a planned threaded libpq test program and > > renentrant ecpg library). If a thread environment is found then check > > for the reentrant functions will be done. > > > > Looking at various open source projects configure.in files there seems > > to be little commonality in the thread test macros (telp gratefully > > accepted!), I currently think that something like the approach used by > > glib is most suitable (switch on OS). > > > > All sound acceptable? > > > > Thanks, Lee. > > > > Peter Eisentraut writes: > > > Lee Kindness writes: > > > > > > > Patches attached to make libpq thread-safe, now uses strerror_r(), > > > > gethostbyname_r(), getpwuid_r() and crypt_r() where available. Where > > > > strtok() was previously used strchr() is now used. > > > > > > AC_TRY_RUN tests are prohibited. Also, try to factor out some of these > > > huge tests into separate macros and put them into config/c-library.m4. > > > And it would be nice if there was some documentation about what was > > > checked for. If you just want to check whether gethostbyname_r() has 5 or > > > 6 arguments you can do that in half the space. > [ Attachment, skipping... ] [ Attachment, skipping... ] [ Attachment, skipping... ] -- 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
Here is the final patch for libpq threading. It adds the bulk of your patch, plus some cleanups on calling reentrant functions. We now have these per-platform configure settings: linux*) THREAD_CFLAGS="-D_REENTRANT -D_THREAD_SAFE -D_POSIX_PTHREAD_SEMANTICS" THREAD_LIBS="-lpthread" NEED_REENTRANT_FUNC_NAMES=yes They control compile flags, link libraries, and the use of reentrant function names. --------------------------------------------------------------------------- Lee Kindness wrote: Content-Description: message body text > Patch attached, along with new libpq-reentrant.c and libpq-reentrant.h > files for src/interfaces/libpq. > > Also at http://services.csl.co.uk/postgresql/ > > Thanks, Lee. > > Lee Kindness writes: > > Ok guys, I propose that the new libpq diff and 2 source files which > > i'll soon send to pgsql-patches is applied to the source. This diff is > > a cleaned up version of the previous version with the wrapper > > functions moved out into their own file and more comments added. Also > > the use of crypt_r() has been removed (not worth the effort), the > > cpp defines have been renamed to be consistent with each other and > > Tom's concerns with loose #defines has been partly addressed. > > > > This diff does not include any configure changes. I plan to tackle > > this separately ASAP, and hopefully produce something more acceptable. > > > > I will add checks for appropriate compiler thread flags (for compiling > > libpq, and alow the removal of #defines in libpq-reentrant.h), and > > link flags & libs (for a planned threaded libpq test program and > > renentrant ecpg library). If a thread environment is found then check > > for the reentrant functions will be done. > > > > Looking at various open source projects configure.in files there seems > > to be little commonality in the thread test macros (telp gratefully > > accepted!), I currently think that something like the approach used by > > glib is most suitable (switch on OS). > > > > All sound acceptable? > > > > Thanks, Lee. > > > > Peter Eisentraut writes: > > > Lee Kindness writes: > > > > > > > Patches attached to make libpq thread-safe, now uses strerror_r(), > > > > gethostbyname_r(), getpwuid_r() and crypt_r() where available. Where > > > > strtok() was previously used strchr() is now used. > > > > > > AC_TRY_RUN tests are prohibited. Also, try to factor out some of these > > > huge tests into separate macros and put them into config/c-library.m4. > > > And it would be nice if there was some documentation about what was > > > checked for. If you just want to check whether gethostbyname_r() has 5 or > > > 6 arguments you can do that in half the space. > [ Attachment, skipping... ] [ Attachment, skipping... ] [ Attachment, skipping... ] -- 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 Index: configure =================================================================== RCS file: /cvsroot/pgsql-server/configure,v retrieving revision 1.271 diff -c -c -r1.271 configure *** configure 14 Jun 2003 14:35:42 -0000 1.271 --- configure 14 Jun 2003 17:12:15 -0000 *************** *** 3591,3596 **** --- 3591,3600 ---- # # Pthreads # + # For each platform, we need to know about any special compile and link + # libraries, and whether the normal C function names are thread-safe. + # + NEED_REENTRANT_FUNC_NAMES=no if test "$with_threads" = yes; then echo "$as_me:$LINENO: checking for ANSI C header files" >&5 echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6 *************** *** 3902,3914 **** case $host_os in netbsd*|bsdi*) # these require no special flags or libraries ;; - freebsd2*|freebsd3*|freebsd4*) THREAD_CFLAGS="-pthread" ;; freebsd*) THREAD_LIBS="-lc_r" ;; linux*) THREAD_CFLAGS="-D_REENTRANT -D_THREAD_SAFE -D_POSIX_PTHREAD_SEMANTICS" THREAD_LIBS="-lpthread" ;; *) # other operating systems might fail because they have pthread.h but need --- 3906,3924 ---- case $host_os in netbsd*|bsdi*) # these require no special flags or libraries + NEED_REENTRANT_FUNC_NAMES=no + ;; + freebsd2*|freebsd3*|freebsd4*) + THREAD_CFLAGS="-pthread" + NEED_REENTRANT_FUNC_NAMES=yes ;; freebsd*) THREAD_LIBS="-lc_r" + NEED_REENTRANT_FUNC_NAMES=yes ;; linux*) THREAD_CFLAGS="-D_REENTRANT -D_THREAD_SAFE -D_POSIX_PTHREAD_SEMANTICS" THREAD_LIBS="-lpthread" + NEED_REENTRANT_FUNC_NAMES=yes ;; *) # other operating systems might fail because they have pthread.h but need *************** *** 12829,12836 **** # # Check for re-entrant versions of certain functions # ! # Include special flags if required # _CFLAGS="$CFLAGS" _LIB="$LIBS" CFLAGS="$CFLAGS $TREAD_CFLAGS" --- 12839,12852 ---- # # Check for re-entrant versions of certain functions # ! # Include special flags if threads are enabled _and_ if required for ! # threading on this platform. Some platforms have *_r functions but ! # their natively named funcs are threadsafe, and should be used instead. ! # ! # One trick here is that if the don't call AC_CHECK_FUNCS, the ! # functions are marked "not found", which is perfect. # + if test "$NEED_REENTRANT_FUNC_NAMES" = yes ; then _CFLAGS="$CFLAGS" _LIB="$LIBS" CFLAGS="$CFLAGS $TREAD_CFLAGS" *************** *** 12915,12921 **** CFLAGS="$_CFLAGS" LIB="$_LIBS" ! # This test makes sure that run tests work at all. Sometimes a shared --- 12931,12937 ---- CFLAGS="$_CFLAGS" LIB="$_LIBS" ! fi # This test makes sure that run tests work at all. Sometimes a shared Index: configure.in =================================================================== RCS file: /cvsroot/pgsql-server/configure.in,v retrieving revision 1.262 diff -c -c -r1.262 configure.in *** configure.in 14 Jun 2003 14:35:42 -0000 1.262 --- configure.in 14 Jun 2003 17:12:16 -0000 *************** *** 554,571 **** # # Pthreads # if test "$with_threads" = yes; then AC_CHECK_HEADER(pthread.h, [], [AC_MSG_ERROR([pthread.h not found, required for --with-threads])]) case $host_os in ! netbsd*|bsdi*) # these require no special flags or libraries ;; - freebsd2*|freebsd3*|freebsd4*) THREAD_CFLAGS="-pthread" ;; freebsd*) THREAD_LIBS="-lc_r" ;; linux*) THREAD_CFLAGS="-D_REENTRANT -D_THREAD_SAFE -D_POSIX_PTHREAD_SEMANTICS" THREAD_LIBS="-lpthread" ;; *) # other operating systems might fail because they have pthread.h but need --- 554,581 ---- # # Pthreads # + # For each platform, we need to know about any special compile and link + # libraries, and whether the normal C function names are thread-safe. + # + NEED_REENTRANT_FUNC_NAMES=no if test "$with_threads" = yes; then AC_CHECK_HEADER(pthread.h, [], [AC_MSG_ERROR([pthread.h not found, required for --with-threads])]) case $host_os in ! netbsd*|bsdi*) # these require no special flags or libraries + NEED_REENTRANT_FUNC_NAMES=no + ;; + freebsd2*|freebsd3*|freebsd4*) + THREAD_CFLAGS="-pthread" + NEED_REENTRANT_FUNC_NAMES=yes ;; freebsd*) THREAD_LIBS="-lc_r" + NEED_REENTRANT_FUNC_NAMES=yes ;; linux*) THREAD_CFLAGS="-D_REENTRANT -D_THREAD_SAFE -D_POSIX_PTHREAD_SEMANTICS" THREAD_LIBS="-lpthread" + NEED_REENTRANT_FUNC_NAMES=yes ;; *) # other operating systems might fail because they have pthread.h but need *************** *** 991,998 **** # # Check for re-entrant versions of certain functions # ! # Include special flags if required # _CFLAGS="$CFLAGS" _LIB="$LIBS" CFLAGS="$CFLAGS $TREAD_CFLAGS" --- 1001,1014 ---- # # Check for re-entrant versions of certain functions # ! # Include special flags if threads are enabled _and_ if required for ! # threading on this platform. Some platforms have *_r functions but ! # their natively named funcs are threadsafe, and should be used instead. ! # ! # One trick here is that if the don't call AC_CHECK_FUNCS, the ! # functions are marked "not found", which is perfect. # + if test "$NEED_REENTRANT_FUNC_NAMES" = yes ; then _CFLAGS="$CFLAGS" _LIB="$LIBS" CFLAGS="$CFLAGS $TREAD_CFLAGS" *************** *** 1000,1006 **** AC_CHECK_FUNCS([strerror_r getpwuid_r gethostbyname_r]) CFLAGS="$_CFLAGS" LIB="$_LIBS" ! # This test makes sure that run tests work at all. Sometimes a shared --- 1016,1022 ---- AC_CHECK_FUNCS([strerror_r getpwuid_r gethostbyname_r]) CFLAGS="$_CFLAGS" LIB="$_LIBS" ! fi # This test makes sure that run tests work at all. Sometimes a shared Index: src/interfaces/libpq/fe-auth.c =================================================================== RCS file: /cvsroot/pgsql-server/src/interfaces/libpq/fe-auth.c,v retrieving revision 1.79 diff -c -c -r1.79 fe-auth.c *** src/interfaces/libpq/fe-auth.c 8 Jun 2003 17:43:00 -0000 1.79 --- src/interfaces/libpq/fe-auth.c 14 Jun 2003 17:12:20 -0000 *************** *** 391,398 **** flags = fcntl(sock, F_GETFL); if (flags < 0 || fcntl(sock, F_SETFL, (long) (flags & ~O_NONBLOCK))) { snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! libpq_gettext("could not set socket to blocking mode: %s\n"), strerror(errno)); krb5_free_principal(pg_krb5_context, server); return STATUS_ERROR; } --- 391,400 ---- flags = fcntl(sock, F_GETFL); if (flags < 0 || fcntl(sock, F_SETFL, (long) (flags & ~O_NONBLOCK))) { + char sebuf[256]; + snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! libpq_gettext("could not set socket to blocking mode: %s\n"), pqStrerror(errno, sebuf, sizeof(sebuf))); krb5_free_principal(pg_krb5_context, server); return STATUS_ERROR; } *************** *** 436,444 **** if (fcntl(sock, F_SETFL, (long) flags)) { snprintf(PQerrormsg, PQERRORMSG_LENGTH, libpq_gettext("could not restore non-blocking mode on socket: %s\n"), ! strerror(errno)); ret = STATUS_ERROR; } --- 438,448 ---- if (fcntl(sock, F_SETFL, (long) flags)) { + char sebuf[256]; + snprintf(PQerrormsg, PQERRORMSG_LENGTH, libpq_gettext("could not restore non-blocking mode on socket: %s\n"), ! pqStrerror(errno, sebuf, sizeof(sebuf))); ret = STATUS_ERROR; } *************** *** 495,502 **** if (sendmsg(conn->sock, &msg, 0) == -1) { snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "pg_local_sendauth: sendmsg: %s\n", strerror(errno)); return STATUS_ERROR; } return STATUS_OK; --- 499,509 ---- if (sendmsg(conn->sock, &msg, 0) == -1) { + char sebuf[256]; + snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "pg_local_sendauth: sendmsg: %s\n", ! pqStrerror(errno, sebuf, sizeof(sebuf))); return STATUS_ERROR; } return STATUS_OK; *************** *** 739,748 **** if (GetUserName(username, &namesize)) name = username; #else ! struct passwd *pw = getpwuid(geteuid()); ! ! if (pw) ! name = pw->pw_name; #endif } --- 746,758 ---- if (GetUserName(username, &namesize)) name = username; #else ! char pwdbuf[BUFSIZ]; ! struct passwd pwdstr; ! struct passwd *pw = NULL; ! ! if( pqGetpwuid(geteuid(), &pwdstr, ! pwdbuf, sizeof(pwdbuf), &pw) == 0 ) ! name = pw->pw_name; #endif } Index: src/interfaces/libpq/fe-connect.c =================================================================== RCS file: /cvsroot/pgsql-server/src/interfaces/libpq/fe-connect.c,v retrieving revision 1.247 diff -c -c -r1.247 fe-connect.c *** src/interfaces/libpq/fe-connect.c 12 Jun 2003 08:15:29 -0000 1.247 --- src/interfaces/libpq/fe-connect.c 14 Jun 2003 17:12:23 -0000 *************** *** 713,721 **** { if (FCNTL_NONBLOCK(conn->sock) < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to non-blocking mode: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); return 0; } --- 713,723 ---- { if (FCNTL_NONBLOCK(conn->sock) < 0) { + char sebuf[256]; + printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to non-blocking mode: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } *************** *** 738,746 **** (char *) &on, sizeof(on)) < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to TCP no delay mode: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); return 0; } #endif --- 740,750 ---- (char *) &on, sizeof(on)) < 0) { + char sebuf[256]; + printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not set socket to TCP no delay mode: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return 0; } #endif *************** *** 759,764 **** --- 763,769 ---- { char hostname[NI_MAXHOST]; char service[NI_MAXHOST]; + char sebuf[256]; getnameinfo((struct sockaddr *)&conn->raddr.addr, conn->raddr.salen, hostname, sizeof(hostname), service, sizeof(service), *************** *** 770,776 **** "\tIs the server running locally and accepting\n" "\tconnections on Unix domain socket \"%s\"?\n" ), ! SOCK_STRERROR(errorno), service); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext( --- 775,781 ---- "\tIs the server running locally and accepting\n" "\tconnections on Unix domain socket \"%s\"?\n" ), ! SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), service); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext( *************** *** 778,784 **** "\tIs the server running on host %s and accepting\n" "\tTCP/IP connections on port %s?\n" ), ! SOCK_STRERROR(errorno), conn->pghostaddr ? conn->pghostaddr : (conn->pghost --- 783,789 ---- "\tIs the server running on host %s and accepting\n" "\tTCP/IP connections on port %s?\n" ), ! SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), conn->pghostaddr ? conn->pghostaddr : (conn->pghost *************** *** 1001,1006 **** --- 1006,1012 ---- PQconnectPoll(PGconn *conn) { PGresult *res; + char sebuf[256]; if (conn == NULL) return PGRES_POLLING_FAILED; *************** *** 1094,1100 **** } printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not create socket: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); break; } --- 1100,1106 ---- } printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not create socket: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); break; } *************** *** 1200,1206 **** { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get socket error status: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); goto error_return; } else if (optval != 0) --- 1206,1212 ---- { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get socket error status: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); goto error_return; } else if (optval != 0) *************** *** 1237,1243 **** { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get client address from socket: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); goto error_return; } --- 1243,1249 ---- { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get client address from socket: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); goto error_return; } *************** *** 1282,1288 **** { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send SSL negotiation packet: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); goto error_return; } /* Ok, wait for response */ --- 1288,1294 ---- { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send SSL negotiation packet: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); goto error_return; } /* Ok, wait for response */ *************** *** 1317,1323 **** { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send startup packet: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); free(startpacket); goto error_return; } --- 1323,1329 ---- { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send startup packet: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); free(startpacket); goto error_return; } *************** *** 1357,1363 **** printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive server response to SSL negotiation packet: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); goto error_return; } if (nread == 0) --- 1363,1369 ---- printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive server response to SSL negotiation packet: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); goto error_return; } if (nread == 0) *************** *** 2037,2042 **** --- 2043,2049 ---- { int save_errno = SOCK_ERRNO; int tmpsock = -1; + char sebuf[256]; struct { uint32 packetlen; *************** *** 2115,2121 **** return TRUE; cancel_errReturn: ! strcat(conn->errorMessage.data, SOCK_STRERROR(SOCK_ERRNO)); strcat(conn->errorMessage.data, "\n"); conn->errorMessage.len = strlen(conn->errorMessage.data); if (tmpsock >= 0) --- 2122,2128 ---- return TRUE; cancel_errReturn: ! strcat(conn->errorMessage.data, SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); strcat(conn->errorMessage.data, "\n"); conn->errorMessage.len = strlen(conn->errorMessage.data); if (tmpsock >= 0) *************** *** 2262,2269 **** *val; int found_keyword; ! key = strtok(line, "="); ! if (key == NULL) { printfPQExpBuffer(errorMessage, "ERROR: syntax error in service file '%s', line %d\n", --- 2269,2277 ---- *val; int found_keyword; ! key = line; ! val = strchr(line, '='); ! if( val == NULL ) { printfPQExpBuffer(errorMessage, "ERROR: syntax error in service file '%s', line %d\n", *************** *** 2272,2277 **** --- 2280,2286 ---- fclose(f); return 3; } + *val++ = '\0'; /* * If not already set, set the database name to the *************** *** 2286,2293 **** break; } } - - val = line + strlen(line) + 1; /* * Set the parameter --- but don't override any --- 2295,2300 ---- Index: src/interfaces/libpq/fe-lobj.c =================================================================== RCS file: /cvsroot/pgsql-server/src/interfaces/libpq/fe-lobj.c,v retrieving revision 1.41 diff -c -c -r1.41 fe-lobj.c *** src/interfaces/libpq/fe-lobj.c 20 Jun 2002 20:29:54 -0000 1.41 --- src/interfaces/libpq/fe-lobj.c 14 Jun 2003 17:12:23 -0000 *************** *** 396,404 **** fd = open(filename, O_RDONLY | PG_BINARY, 0666); if (fd < 0) { /* error */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open file \"%s\": %s\n"), ! filename, strerror(errno)); return InvalidOid; } --- 396,405 ---- fd = open(filename, O_RDONLY | PG_BINARY, 0666); if (fd < 0) { /* error */ + char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open file \"%s\": %s\n"), ! filename, pqStrerror(errno, sebuf, sizeof(sebuf))); return InvalidOid; } *************** *** 479,487 **** fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666); if (fd < 0) { /* error */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open file \"%s\": %s\n"), ! filename, strerror(errno)); (void) lo_close(conn, lobj); return -1; } --- 480,489 ---- fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666); if (fd < 0) { /* error */ + char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open file \"%s\": %s\n"), ! filename, pqStrerror(errno, sebuf, sizeof(sebuf))); (void) lo_close(conn, lobj); return -1; } Index: src/interfaces/libpq/fe-misc.c =================================================================== RCS file: /cvsroot/pgsql-server/src/interfaces/libpq/fe-misc.c,v retrieving revision 1.95 diff -c -c -r1.95 fe-misc.c *** src/interfaces/libpq/fe-misc.c 12 Jun 2003 08:15:29 -0000 1.95 --- src/interfaces/libpq/fe-misc.c 14 Jun 2003 17:12:24 -0000 *************** *** 536,541 **** --- 536,542 ---- { int someread = 0; int nread; + char sebuf[256]; if (conn->sock < 0) { *************** *** 606,612 **** #endif printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); return -1; } if (nread > 0) --- 607,613 ---- #endif printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return -1; } if (nread > 0) *************** *** 686,692 **** #endif printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); return -1; } if (nread > 0) --- 687,693 ---- #endif printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return -1; } if (nread > 0) *************** *** 740,745 **** --- 741,747 ---- while (len > 0) { int sent; + char sebuf[256]; sent = pqsecure_write(conn, ptr, len); *************** *** 787,793 **** default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send data to server: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); /* We don't assume it's a fatal error... */ conn->outCount = 0; return -1; --- 789,795 ---- default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send data to server: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); /* We don't assume it's a fatal error... */ conn->outCount = 0; return -1; *************** *** 963,971 **** if (result < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("select() failed: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); } return result; --- 965,975 ---- if (result < 0) { + char sebuf[256]; + printfPQExpBuffer(&conn->errorMessage, libpq_gettext("select() failed: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); } return result; Index: src/interfaces/libpq/fe-secure.c =================================================================== RCS file: /cvsroot/pgsql-server/src/interfaces/libpq/fe-secure.c,v retrieving revision 1.23 diff -c -c -r1.23 fe-secure.c *** src/interfaces/libpq/fe-secure.c 8 Jun 2003 17:43:00 -0000 1.23 --- src/interfaces/libpq/fe-secure.c 14 Jun 2003 17:12:26 -0000 *************** *** 298,311 **** */ goto rloop; case SSL_ERROR_SYSCALL: if (n == -1) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); break; case SSL_ERROR_SSL: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), SSLerrmessage()); --- 298,316 ---- */ goto rloop; case SSL_ERROR_SYSCALL: + { + char sebuf[256]; + if (n == -1) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); + break; + } case SSL_ERROR_SSL: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), SSLerrmessage()); *************** *** 360,373 **** n = 0; break; case SSL_ERROR_SYSCALL: if (n == -1) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); break; case SSL_ERROR_SSL: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), SSLerrmessage()); --- 365,382 ---- n = 0; break; case SSL_ERROR_SYSCALL: + { + char sebuf[256]; + if (n == -1) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); break; + } case SSL_ERROR_SSL: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), SSLerrmessage()); *************** *** 434,442 **** len = sizeof(addr); if (getpeername(conn->sock, &addr, &len) == -1) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("error querying socket: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); return -1; } --- 443,452 ---- len = sizeof(addr); if (getpeername(conn->sock, &addr, &len) == -1) { + char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("error querying socket: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return -1; } *************** *** 514,527 **** static DH * load_dh_file(int keylength) { ! struct passwd *pwd; FILE *fp; char fnbuf[2048]; DH *dh = NULL; int codes; ! if ((pwd = getpwuid(getuid())) == NULL) ! return NULL; /* attempt to open file. It's not an error if it doesn't exist. */ snprintf(fnbuf, sizeof fnbuf, "%s/.postgresql/dh%d.pem", --- 524,539 ---- static DH * load_dh_file(int keylength) { ! char pwdbuf[BUFSIZ]; ! struct passwd pwdstr; ! struct passwd *pwd = NULL; FILE *fp; char fnbuf[2048]; DH *dh = NULL; int codes; ! if( pqGetpwuid(getuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) == 0 ) ! return NULL; /* attempt to open file. It's not an error if it doesn't exist. */ snprintf(fnbuf, sizeof fnbuf, "%s/.postgresql/dh%d.pem", *************** *** 654,668 **** static int client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey) { ! struct passwd *pwd; struct stat buf, buf2; char fnbuf[2048]; FILE *fp; PGconn *conn = (PGconn *) SSL_get_app_data(ssl); int (*cb) () = NULL; /* how to read user password */ ! if ((pwd = getpwuid(getuid())) == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get user information\n")); --- 666,684 ---- static int client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey) { ! char pwdbuf[BUFSIZ]; ! struct passwd pwdstr; ! struct passwd *pwd = NULL; struct stat buf, buf2; char fnbuf[2048]; FILE *fp; PGconn *conn = (PGconn *) SSL_get_app_data(ssl); int (*cb) () = NULL; /* how to read user password */ + char sebuf[256]; + ! if( pqGetpwuid(getuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) == 0 ) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get user information\n")); *************** *** 678,684 **** { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open certificate (%s): %s\n"), ! fnbuf, strerror(errno)); return -1; } if (PEM_read_X509(fp, x509, NULL, NULL) == NULL) --- 694,700 ---- { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open certificate (%s): %s\n"), ! fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf))); return -1; } if (PEM_read_X509(fp, x509, NULL, NULL) == NULL) *************** *** 714,720 **** { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open private key file (%s): %s\n"), ! fnbuf, strerror(errno)); X509_free(*x509); return -1; } --- 730,736 ---- { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not open private key file (%s): %s\n"), ! fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf))); X509_free(*x509); return -1; } *************** *** 758,764 **** initialize_SSL(PGconn *conn) { struct stat buf; ! struct passwd *pwd; char fnbuf[2048]; if (!SSL_context) --- 774,782 ---- initialize_SSL(PGconn *conn) { struct stat buf; ! char pwdbuf[BUFSIZ]; ! struct passwd pwdstr; ! struct passwd *pwd = NULL; char fnbuf[2048]; if (!SSL_context) *************** *** 775,781 **** } } ! if ((pwd = getpwuid(getuid())) != NULL) { snprintf(fnbuf, sizeof fnbuf, "%s/.postgresql/root.crt", pwd->pw_dir); --- 793,799 ---- } } ! if( pqGetpwuid(getuid(), &pwdstr, pwdbuf, sizeof(pwdbuf), &pwd) == 0 ) { snprintf(fnbuf, sizeof fnbuf, "%s/.postgresql/root.crt", pwd->pw_dir); *************** *** 783,792 **** { return 0; #ifdef NOT_USED /* CLIENT CERTIFICATES NOT REQUIRED bjm 2002-09-26 */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read root certificate list (%s): %s\n"), ! fnbuf, strerror(errno)); return -1; #endif } --- 801,811 ---- { return 0; #ifdef NOT_USED + char sebuf[256]; /* CLIENT CERTIFICATES NOT REQUIRED bjm 2002-09-26 */ printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not read root certificate list (%s): %s\n"), ! fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf))); return -1; #endif } *************** *** 846,861 **** return PGRES_POLLING_WRITING; case SSL_ERROR_SYSCALL: if (r == -1) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO)); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); close_SSL(conn); return PGRES_POLLING_FAILED; ! case SSL_ERROR_SSL: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), SSLerrmessage()); --- 865,883 ---- return PGRES_POLLING_WRITING; case SSL_ERROR_SYSCALL: + { + char sebuf[256]; + if (r == -1) printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), ! SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); else printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); close_SSL(conn); return PGRES_POLLING_FAILED; ! } case SSL_ERROR_SSL: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), SSLerrmessage()); Index: src/interfaces/libpq/libpq-int.h =================================================================== RCS file: /cvsroot/pgsql-server/src/interfaces/libpq/libpq-int.h,v retrieving revision 1.73 diff -c -c -r1.73 libpq-int.h *** src/interfaces/libpq/libpq-int.h 12 Jun 2003 07:36:51 -0000 1.73 --- src/interfaces/libpq/libpq-int.h 14 Jun 2003 17:12:27 -0000 *************** *** 26,31 **** --- 26,32 ---- #include <sys/time.h> #endif + #if defined(WIN32) && (!defined(ssize_t)) typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast * not VC6) */ *************** *** 448,454 **** #define SOCK_STRERROR winsock_strerror #else #define SOCK_ERRNO errno ! #define SOCK_STRERROR strerror #endif #endif /* LIBPQ_INT_H */ --- 449,455 ---- #define SOCK_STRERROR winsock_strerror #else #define SOCK_ERRNO errno ! #define SOCK_STRERROR pqStrerror #endif #endif /* LIBPQ_INT_H */ Index: src/interfaces/libpq/win32.c =================================================================== RCS file: /cvsroot/pgsql-server/src/interfaces/libpq/win32.c,v retrieving revision 1.4 diff -c -c -r1.4 win32.c *** src/interfaces/libpq/win32.c 4 Sep 2002 20:31:47 -0000 1.4 --- src/interfaces/libpq/win32.c 14 Jun 2003 17:12:27 -0000 *************** *** 271,283 **** */ const char * ! winsock_strerror(int err) { - static char buf[512]; /* Not threadsafe */ unsigned long flags; int offs, i; ! int success = LookupWSErrorMessage(err, buf); for (i = 0; !success && i < DLLS_SIZE; i++) { --- 271,282 ---- */ const char * ! winsock_strerror(int err, char *strerrbuf, size_t buflen) { unsigned long flags; int offs, i; ! int success = LookupWSErrorMessage(err, strerrbuf); for (i = 0; !success && i < DLLS_SIZE; i++) { *************** *** 302,321 **** flags, dlls[i].handle, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), ! buf, sizeof(buf) - 64, 0 ); } if (!success) ! sprintf(buf, "Unknown socket error (0x%08X/%lu)", err, err); else { ! buf[sizeof(buf) - 1] = '\0'; ! offs = strlen(buf); ! if (offs > sizeof(buf) - 64) ! offs = sizeof(buf) - 64; ! sprintf(buf + offs, " (0x%08X/%lu)", err, err); } ! return buf; } --- 301,320 ---- flags, dlls[i].handle, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), ! strerrbuf, buflen - 64, 0 ); } if (!success) ! sprintf(strerrbuf, "Unknown socket error (0x%08X/%lu)", err, err); else { ! strerrbuf[buflen - 1] = '\0'; ! offs = strlen(strerrbuf); ! if (offs > buflen - 64) ! offs = buflen - 64; ! sprintf(strerrbuf + offs, " (0x%08X/%lu)", err, err); } ! return strerrbuf; } Index: src/interfaces/libpq/win32.h =================================================================== RCS file: /cvsroot/pgsql-server/src/interfaces/libpq/win32.h,v retrieving revision 1.22 diff -c -c -r1.22 win32.h *** src/interfaces/libpq/win32.h 9 May 2003 16:59:43 -0000 1.22 --- src/interfaces/libpq/win32.h 14 Jun 2003 17:12:27 -0000 *************** *** 37,43 **** /* * support for handling Windows Socket errors */ ! extern const char *winsock_strerror(int eno); ! #endif --- 37,42 ---- /* * support for handling Windows Socket errors */ ! extern const char *winsock_strerror(int err, char *strerrbuf, size_t buflen); #endif
This patch handles two more gethostbyname calls. --------------------------------------------------------------------------- Lee Kindness wrote: Content-Description: message body text > Patch attached, along with new libpq-reentrant.c and libpq-reentrant.h > files for src/interfaces/libpq. > > Also at http://services.csl.co.uk/postgresql/ > > Thanks, Lee. > > Lee Kindness writes: > > Ok guys, I propose that the new libpq diff and 2 source files which > > i'll soon send to pgsql-patches is applied to the source. This diff is > > a cleaned up version of the previous version with the wrapper > > functions moved out into their own file and more comments added. Also > > the use of crypt_r() has been removed (not worth the effort), the > > cpp defines have been renamed to be consistent with each other and > > Tom's concerns with loose #defines has been partly addressed. > > > > This diff does not include any configure changes. I plan to tackle > > this separately ASAP, and hopefully produce something more acceptable. > > > > I will add checks for appropriate compiler thread flags (for compiling > > libpq, and alow the removal of #defines in libpq-reentrant.h), and > > link flags & libs (for a planned threaded libpq test program and > > renentrant ecpg library). If a thread environment is found then check > > for the reentrant functions will be done. > > > > Looking at various open source projects configure.in files there seems > > to be little commonality in the thread test macros (telp gratefully > > accepted!), I currently think that something like the approach used by > > glib is most suitable (switch on OS). > > > > All sound acceptable? > > > > Thanks, Lee. > > > > Peter Eisentraut writes: > > > Lee Kindness writes: > > > > > > > Patches attached to make libpq thread-safe, now uses strerror_r(), > > > > gethostbyname_r(), getpwuid_r() and crypt_r() where available. Where > > > > strtok() was previously used strchr() is now used. > > > > > > AC_TRY_RUN tests are prohibited. Also, try to factor out some of these > > > huge tests into separate macros and put them into config/c-library.m4. > > > And it would be nice if there was some documentation about what was > > > checked for. If you just want to check whether gethostbyname_r() has 5 or > > > 6 arguments you can do that in half the space. > [ Attachment, skipping... ] [ Attachment, skipping... ] [ Attachment, skipping... ] -- 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 Index: src/interfaces/libpq/fe-secure.c =================================================================== RCS file: /cvsroot/pgsql-server/src/interfaces/libpq/fe-secure.c,v retrieving revision 1.24 diff -c -c -r1.24 fe-secure.c *** src/interfaces/libpq/fe-secure.c 14 Jun 2003 17:49:54 -0000 1.24 --- src/interfaces/libpq/fe-secure.c 14 Jun 2003 18:08:54 -0000 *************** *** 453,460 **** if (addr.sa_family == AF_UNIX) return 0; /* what do we know about the peer's common name? */ ! if ((h = gethostbyname(conn->peer_cn)) == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get information about host (%s): %s\n"), --- 453,469 ---- if (addr.sa_family == AF_UNIX) return 0; + { + struct hostent hpstr; + char buf[BUFSIZ]; + int herrno = 0; + + pqGethostbyname(conn->peer_cn, &hpstr, buf, sizeof(buf), + &h, &herrno); + } + /* what do we know about the peer's common name? */ ! if ((h == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get information about host (%s): %s\n"), Index: src/port/getaddrinfo.c =================================================================== RCS file: /cvsroot/pgsql-server/src/port/getaddrinfo.c,v retrieving revision 1.7 diff -c -c -r1.7 getaddrinfo.c *** src/port/getaddrinfo.c 12 Jun 2003 08:15:29 -0000 1.7 --- src/port/getaddrinfo.c 14 Jun 2003 18:08:55 -0000 *************** *** 84,91 **** --- 84,99 ---- else { struct hostent *hp; + #ifdef FRONTEND + struct hostent hpstr; + char buf[BUFSIZ]; + int herrno = 0; + pqGethostbyname(node, &hpstr, buf, sizeof(buf), + &hp, &herrno); + #else hp = gethostbyname(node); + #endif if (hp == NULL) { switch (h_errno)
On Sat, Jun 14, 2003 at 02:20:44PM -0400, Bruce Momjian wrote: > > This patch handles two more gethostbyname calls. > [...] > diff -c -c -r1.24 fe-secure.c > *** src/interfaces/libpq/fe-secure.c 14 Jun 2003 17:49:54 -0000 1.24 > --- src/interfaces/libpq/fe-secure.c 14 Jun 2003 18:08:54 -0000 > *************** > *** 453,460 **** > if (addr.sa_family == AF_UNIX) > return 0; > > /* what do we know about the peer's common name? */ > ! if ((h = gethostbyname(conn->peer_cn)) == NULL) > { > printfPQExpBuffer(&conn->errorMessage, > libpq_gettext("could not get information about host (%s): %s\n"), That code is inside #ifdef NOT_USED, which is why I didn't change it in my ipv6 patch. Should I convert that function to use getaddrinfo too? Others I didn't change where pg_krb4_sendauth() and pg_krb5_sendauth(), because I don't have a clue about kerberos. Kurt
Kurt Roeckx wrote: > On Sat, Jun 14, 2003 at 02:20:44PM -0400, Bruce Momjian wrote: > > > > This patch handles two more gethostbyname calls. > > > [...] > > diff -c -c -r1.24 fe-secure.c > > *** src/interfaces/libpq/fe-secure.c 14 Jun 2003 17:49:54 -0000 1.24 > > --- src/interfaces/libpq/fe-secure.c 14 Jun 2003 18:08:54 -0000 > > *************** > > *** 453,460 **** > > if (addr.sa_family == AF_UNIX) > > return 0; > > > > /* what do we know about the peer's common name? */ > > ! if ((h = gethostbyname(conn->peer_cn)) == NULL) > > { > > printfPQExpBuffer(&conn->errorMessage, > > libpq_gettext("could not get information about host (%s): %s\n"), > > That code is inside #ifdef NOT_USED, which is why I didn't change > it in my ipv6 patch. Yes, I noticed that, but it seemed reasonable to get things consistent. > > Should I convert that function to use getaddrinfo too? > > Others I didn't change where pg_krb4_sendauth() and > pg_krb5_sendauth(), because I don't have a clue about kerberos. I understand. I guess we should be consisent if we can be. -- 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