diff options
author | Robert Haas <rhaas@postgresql.org> | 2024-04-02 10:15:56 -0400 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2024-04-02 10:15:56 -0400 |
commit | f5e4dedfa81f00de93b1b90d06c44cc50e052eaf (patch) | |
tree | dfd58b39ed329db653949de280e0dd6c4f9df6f1 | |
parent | 3a352df05e65de740b4a375a0ecbcae97a1f6196 (diff) | |
download | postgresql-f5e4dedfa81f00de93b1b90d06c44cc50e052eaf.tar.gz postgresql-f5e4dedfa81f00de93b1b90d06c44cc50e052eaf.zip |
Expose PQsocketPoll via libpq
This is useful when connecting to a database asynchronously via
PQconnectStart(), since it handles deciding between poll() and
select(), and some of the required boilerplate.
Tristan Partin, reviewed by Gurjeet Singh, Heikki Linnakangas, Jelte
Fennema-Nio, and me.
Discussion: http://postgr.es/m/D08WWCPVHKHN.3QELIKZJ2D9RZ@neon.tech
-rw-r--r-- | doc/src/sgml/libpq.sgml | 40 | ||||
-rw-r--r-- | src/interfaces/libpq/exports.txt | 1 | ||||
-rw-r--r-- | src/interfaces/libpq/fe-misc.c | 7 | ||||
-rw-r--r-- | src/interfaces/libpq/libpq-fe.h | 4 |
4 files changed, 47 insertions, 5 deletions
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index d3e87056f2c..e69feacfe6a 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -262,6 +262,41 @@ PGconn *PQsetdb(char *pghost, </listitem> </varlistentry> + <varlistentry id="libpq-PQsocketPoll"> + <term><function>PQsocketPoll</function><indexterm><primary>PQsocketPoll</primary></indexterm></term> + <listitem> + <para> + <indexterm><primary>nonblocking connection</primary></indexterm> + Poll a connection's underlying socket descriptor retrieved with <xref linkend="libpq-PQsocket"/>. +<synopsis> +int PQsocketPoll(int sock, int forRead, int forWrite, time_t end_time); +</synopsis> + </para> + + <para> + This function sets up polling of a file descriptor. The underlying function is either + <function>poll(2)</function> or <function>select(2)</function>, depending on platform + support. The primary use of this function is iterating through the connection sequence + described in the documentation of <xref linkend="libpq-PQconnectStartParams"/>. If + <parameter>forRead</parameter> is specified, the function waits for the socket to be ready + for reading. If <parameter>forWrite</parameter> is specified, the function waits for the + socket to be ready for write. See <literal>POLLIN</literal> and <literal>POLLOUT</literal> + from <function>poll(2)</function>, or <parameter>readfds</parameter> and + <parameter>writefds</parameter> from <function>select(2)</function> for more information. If + <parameter>end_time</parameter> is not <literal>-1</literal>, it specifies the time at which + this function should stop waiting for the condition to be met. + </para> + + <para> + The function returns a value greater than <literal>0</literal> if the specified condition + is met, <literal>0</literal> if a timeout occurred, or <literal>-1</literal> if an error + occurred. The error can be retrieved by checking the <literal>errno(3)</literal> value. In + the event <literal>forRead</literal> and <literal>forWrite</literal> are not set, the + function immediately returns a timeout condition. + </para> + </listitem> + </varlistentry> + <varlistentry id="libpq-PQconnectStartParams"> <term><function>PQconnectStartParams</function><indexterm><primary>PQconnectStartParams</primary></indexterm></term> <term><function>PQconnectStart</function><indexterm><primary>PQconnectStart</primary></indexterm></term> @@ -358,7 +393,10 @@ PostgresPollingStatusType PQconnectPoll(PGconn *conn); Loop thus: If <function>PQconnectPoll(conn)</function> last returned <symbol>PGRES_POLLING_READING</symbol>, wait until the socket is ready to read (as indicated by <function>select()</function>, <function>poll()</function>, or - similar system function). + similar system function). Note that <function>PQsocketPoll</function> + can help reduce boilerplate by abstracting the setup of + <function>select(2)</function> or <function>poll(2)</function> if it is + available on your system. Then call <function>PQconnectPoll(conn)</function> again. Conversely, if <function>PQconnectPoll(conn)</function> last returned <symbol>PGRES_POLLING_WRITING</symbol>, wait until the socket is ready diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt index 9fbd3d34074..1e48d37677d 100644 --- a/src/interfaces/libpq/exports.txt +++ b/src/interfaces/libpq/exports.txt @@ -202,3 +202,4 @@ PQcancelSocket 199 PQcancelErrorMessage 200 PQcancelReset 201 PQcancelFinish 202 +PQsocketPoll 203 diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c index f2fc78a481c..f562cd8d344 100644 --- a/src/interfaces/libpq/fe-misc.c +++ b/src/interfaces/libpq/fe-misc.c @@ -55,7 +55,6 @@ static int pqPutMsgBytes(const void *buf, size_t len, PGconn *conn); static int pqSendSome(PGconn *conn, int len); static int pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time); -static int pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time); /* * PQlibVersion: return the libpq version number @@ -1059,7 +1058,7 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) /* We will retry as long as we get EINTR */ do - result = pqSocketPoll(conn->sock, forRead, forWrite, end_time); + result = PQsocketPoll(conn->sock, forRead, forWrite, end_time); while (result < 0 && SOCK_ERRNO == EINTR); if (result < 0) @@ -1083,8 +1082,8 @@ pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) * Timeout is infinite if end_time is -1. Timeout is immediate (no blocking) * if end_time is 0 (or indeed, any time before now). */ -static int -pqSocketPoll(int sock, int forRead, int forWrite, time_t end_time) +int +PQsocketPoll(int sock, int forRead, int forWrite, time_t end_time) { /* We use poll(2) if available, otherwise select(2) */ #ifdef HAVE_POLL diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 09b485bd2bc..8d3c5c6f662 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -21,6 +21,7 @@ extern "C" #endif #include <stdio.h> +#include <time.h> /* * postgres_ext.h defines the backend's externally visible types, @@ -670,6 +671,9 @@ extern int lo_export(PGconn *conn, Oid lobjId, const char *filename); /* Get the version of the libpq library in use */ extern int PQlibVersion(void); +/* Poll a socket for reading and/or writing with an optional timeout */ +extern int PQsocketPoll(int sock, int forRead, int forWrite, time_t end_time); + /* Determine length of multibyte encoded char at *s */ extern int PQmblen(const char *s, int encoding); |