|
11 | 11 | *
|
12 | 12 | *
|
13 | 13 | * IDENTIFICATION
|
14 |
| - * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.57 2004/11/20 00:35:13 tgl Exp $ |
| 14 | + * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.58 2004/12/02 15:32:54 momjian Exp $ |
15 | 15 | *
|
16 | 16 | * NOTES
|
17 | 17 | * [ Most of these notes are wrong/obsolete, but perhaps not all ]
|
@@ -152,12 +152,6 @@ bool pq_initssllib = true;
|
152 | 152 | static SSL_CTX *SSL_context = NULL;
|
153 | 153 | #endif
|
154 | 154 |
|
155 |
| -#ifdef ENABLE_THREAD_SAFETY |
156 |
| -static void sigpipe_handler_ignore_send(int signo); |
157 |
| -pthread_key_t pq_thread_in_send = 0; /* initializer needed on Darwin */ |
158 |
| -static pqsigfunc pq_pipe_handler; |
159 |
| -#endif |
160 |
| - |
161 | 155 | /* ------------------------------------------------------------ */
|
162 | 156 | /* Hardcoded values */
|
163 | 157 | /* ------------------------------------------------------------ */
|
@@ -379,9 +373,12 @@ ssize_t
|
379 | 373 | pqsecure_write(PGconn *conn, const void *ptr, size_t len)
|
380 | 374 | {
|
381 | 375 | ssize_t n;
|
382 |
| - |
| 376 | + |
383 | 377 | #ifdef ENABLE_THREAD_SAFETY
|
384 |
| - pthread_setspecific(pq_thread_in_send, "t"); |
| 378 | + sigset_t osigmask; |
| 379 | + bool sigpipe_pending; |
| 380 | + |
| 381 | + pq_block_sigpipe(&osigmask, &sigpipe_pending); |
385 | 382 | #else
|
386 | 383 | #ifndef WIN32
|
387 | 384 | pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN);
|
@@ -452,9 +449,14 @@ pqsecure_write(PGconn *conn, const void *ptr, size_t len)
|
452 | 449 | else
|
453 | 450 | #endif
|
454 | 451 | n = send(conn->sock, ptr, len, 0);
|
| 452 | + /* |
| 453 | + * Possible optimization: if sigpending() turns out to be an |
| 454 | + * expensive operation, we can set sigpipe_pending = 'true' |
| 455 | + * here if errno != EPIPE, avoiding a sigpending call. |
| 456 | + */ |
455 | 457 |
|
456 | 458 | #ifdef ENABLE_THREAD_SAFETY
|
457 |
| - pthread_setspecific(pq_thread_in_send, "f"); |
| 459 | + pq_reset_sigpipe(&osigmask, sigpipe_pending); |
458 | 460 | #else
|
459 | 461 | #ifndef WIN32
|
460 | 462 | pqsignal(SIGPIPE, oldsighandler);
|
@@ -1216,65 +1218,77 @@ PQgetssl(PGconn *conn)
|
1216 | 1218 | }
|
1217 | 1219 | #endif /* USE_SSL */
|
1218 | 1220 |
|
1219 |
| - |
1220 | 1221 | #ifdef ENABLE_THREAD_SAFETY
|
1221 |
| -#ifndef WIN32 |
1222 | 1222 | /*
|
1223 |
| - * Check SIGPIPE handler and perhaps install our own. |
| 1223 | + * Block SIGPIPE for this thread. This prevents send()/write() from exiting |
| 1224 | + * the application. |
1224 | 1225 | */
|
1225 |
| -void |
1226 |
| -pq_check_sigpipe_handler(void) |
1227 |
| -{ |
1228 |
| - pthread_key_create(&pq_thread_in_send, NULL); |
1229 |
| - |
1230 |
| - /* |
1231 |
| - * Find current pipe handler and chain on to it. |
1232 |
| - */ |
1233 |
| - pq_pipe_handler = pqsignalinquire(SIGPIPE); |
1234 |
| - pqsignal(SIGPIPE, sigpipe_handler_ignore_send); |
1235 |
| -} |
1236 |
| - |
1237 |
| -/* |
1238 |
| - * Threaded SIGPIPE signal handler |
1239 |
| - */ |
1240 |
| -void |
1241 |
| -sigpipe_handler_ignore_send(int signo) |
| 1226 | +int |
| 1227 | +pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending) |
1242 | 1228 | {
|
1243 |
| - /* |
1244 |
| - * If we have gotten a SIGPIPE outside send(), chain or exit if we are |
1245 |
| - * at the end of the chain. Synchronous signals are delivered to the |
1246 |
| - * thread that caused the signal. |
1247 |
| - */ |
1248 |
| - if (!PQinSend()) |
| 1229 | + sigset_t sigpipe_sigset; |
| 1230 | + sigset_t sigset; |
| 1231 | + int ret; |
| 1232 | + |
| 1233 | + sigemptyset(&sigpipe_sigset); |
| 1234 | + sigaddset(&sigpipe_sigset, SIGPIPE); |
| 1235 | + |
| 1236 | + /* Block SIGPIPE and save previous mask for later reset */ |
| 1237 | + ret = pthread_sigmask(SIG_BLOCK, &sigpipe_sigset, osigset); |
| 1238 | + |
| 1239 | + /* We can have a pending SIGPIPE only if it was blocked before */ |
| 1240 | + if (sigismember(osigset, SIGPIPE)) |
1249 | 1241 | {
|
1250 |
| - if (pq_pipe_handler == SIG_DFL) /* not set by application */ |
1251 |
| - exit(128 + SIGPIPE); /* typical return value for SIG_DFL */ |
| 1242 | + /* Is there a pending SIGPIPE? */ |
| 1243 | + if (sigpending(&sigset) != 0) |
| 1244 | + return -1; |
| 1245 | + |
| 1246 | + if (sigismember(&sigset, SIGPIPE)) |
| 1247 | + *sigpipe_pending = true; |
1252 | 1248 | else
|
1253 |
| - (*pq_pipe_handler) (signo); /* call original handler */ |
| 1249 | + *sigpipe_pending = false; |
1254 | 1250 | }
|
| 1251 | + else |
| 1252 | + *sigpipe_pending = false; |
| 1253 | + |
| 1254 | + return ret; |
1255 | 1255 | }
|
1256 |
| -#endif |
1257 |
| -#endif |
1258 |
| - |
| 1256 | + |
1259 | 1257 | /*
|
1260 |
| - * Indicates whether the current thread is in send() |
1261 |
| - * For use by SIGPIPE signal handlers; they should |
1262 |
| - * ignore SIGPIPE when libpq is in send(). This means |
1263 |
| - * that the backend has died unexpectedly. |
| 1258 | + * Discard any pending SIGPIPE and reset the signal mask. |
| 1259 | + * We might be discarding a blocked SIGPIPE that we didn't generate, |
| 1260 | + * but we document that you can't keep blocked SIGPIPE calls across |
| 1261 | + * libpq function calls. |
1264 | 1262 | */
|
1265 |
| -pqbool |
1266 |
| -PQinSend(void) |
| 1263 | +int |
| 1264 | +pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending) |
1267 | 1265 | {
|
1268 |
| -#ifdef ENABLE_THREAD_SAFETY |
1269 |
| - return (pthread_getspecific(pq_thread_in_send) /* has it been set? */ && |
1270 |
| - *(char *) pthread_getspecific(pq_thread_in_send) == 't') ? true : false; |
1271 |
| -#else |
| 1266 | + int signo; |
| 1267 | + sigset_t sigset; |
1272 | 1268 |
|
1273 |
| - /* |
1274 |
| - * No threading: our code ignores SIGPIPE around send(). Therefore, we |
1275 |
| - * can't be in send() if we are checking from a SIGPIPE signal |
1276 |
| - * handler. |
1277 |
| - */ |
1278 |
| - return false; |
1279 |
| -#endif |
| 1269 | + /* Clear SIGPIPE only if none was pending */ |
| 1270 | + if (!sigpipe_pending) |
| 1271 | + { |
| 1272 | + if (sigpending(&sigset) != 0) |
| 1273 | + return -1; |
| 1274 | + |
| 1275 | + /* |
| 1276 | + * Discard pending and blocked SIGPIPE |
| 1277 | + */ |
| 1278 | + if (sigismember(&sigset, SIGPIPE)) |
| 1279 | + { |
| 1280 | + sigset_t sigpipe_sigset; |
| 1281 | + |
| 1282 | + sigemptyset(&sigpipe_sigset); |
| 1283 | + sigaddset(&sigpipe_sigset, SIGPIPE); |
| 1284 | + |
| 1285 | + sigwait(&sigpipe_sigset, &signo); |
| 1286 | + if (signo != SIGPIPE) |
| 1287 | + return -1; |
| 1288 | + } |
| 1289 | + } |
| 1290 | + |
| 1291 | + /* Restore saved block mask */ |
| 1292 | + return pthread_sigmask(SIG_SETMASK, osigset, NULL); |
1280 | 1293 | }
|
| 1294 | +#endif |
0 commit comments