Last active
May 31, 2017 10:08
-
-
Save lmb/a35e7b9566fa79e7bf971ac21bbb9efb to your computer and use it in GitHub Desktop.
[PATCH] LMDB: Suppress SIGPIPE in mdb_env_copythr on OS X
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 5092fd69abc0d9fd81b62a0a00553ace556cbc0a Mon Sep 17 00:00:00 2001 | |
From: Lorenz Bauer <lmb@xxx> | |
Date: Wed, 15 Feb 2017 18:58:05 +0000 | |
Subject: [PATCH] Use F_SETNOSIGPIPE on OS X | |
It seems like OS X delivers SIGPIPE to the whole process, instead of the generating thread, as on other UNIXes. Therefore the current code sometimes works, but mostly doesn't, since the call to sigwait doesn't happen quickly enough. | |
Instead of masking SIGPIPE, we use an OS X specific fcntl to disable SIGPIPE for that particular fd. | |
--- | |
libraries/liblmdb/mdb.c | 18 ++++++++---------- | |
1 file changed, 8 insertions(+), 10 deletions(-) | |
diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c | |
index ac381d9..cb08d4f 100644 | |
--- a/libraries/liblmdb/mdb.c | |
+++ b/libraries/liblmdb/mdb.c | |
@@ -9815,7 +9815,14 @@ mdb_env_copythr(void *arg) | |
#else | |
int len; | |
#define DO_WRITE(rc, fd, ptr, w2, len) len = write(fd, ptr, w2); rc = (len >= 0) | |
-#ifdef SIGPIPE | |
+#ifdef F_SETNOSIGPIPE | |
+ /* OS X delivers SIGPIPE to the whole process, not the thread that caused it. | |
+ * Disable SIGPIPE using platform specific fcntl. | |
+ */ | |
+ int enabled = 1; | |
+ if ((rc = fcntl(my->mc_fd, F_SETNOSIGPIPE, &enabled)) != 0) | |
+ my->mc_error = errno; | |
+#elif defined SIGPIPE | |
sigset_t set; | |
sigemptyset(&set); | |
sigaddset(&set, SIGPIPE); | |
@@ -9838,15 +9845,6 @@ again: | |
DO_WRITE(rc, my->mc_fd, ptr, wsize, len); | |
if (!rc) { | |
rc = ErrCode(); | |
-#if defined(SIGPIPE) && !defined(_WIN32) | |
- if (rc == EPIPE) { | |
- /* Collect the pending SIGPIPE, otherwise at least OS X | |
- * gives it to the process on thread-exit (ITS#8504). | |
- */ | |
- int tmp; | |
- sigwait(&set, &tmp); | |
- } | |
-#endif | |
break; | |
} else if (len > 0) { | |
rc = MDB_SUCCESS; | |
-- | |
2.9.0 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From ee1f53872db5d60c612ada95695b3f1bb0d49250 Mon Sep 17 00:00:00 2001 | |
From: Lorenz Bauer <[email protected]> | |
Date: Wed, 31 May 2017 11:07:38 +0100 | |
Subject: [PATCH 2/2] Add tests for SIGPIPE behaviour | |
--- | |
libraries/liblmdb/Makefile | 1 + | |
libraries/liblmdb/mtest7.c | 101 +++++++++++++++++++++++++++++++++++++++++++++ | |
2 files changed, 102 insertions(+) | |
create mode 100644 libraries/liblmdb/mtest7.c | |
diff --git a/libraries/liblmdb/Makefile b/libraries/liblmdb/Makefile | |
index 72d0984..1b4567a 100644 | |
--- a/libraries/liblmdb/Makefile | |
+++ b/libraries/liblmdb/Makefile | |
@@ -78,6 +78,7 @@ mtest3: mtest3.o liblmdb.a | |
mtest4: mtest4.o liblmdb.a | |
mtest5: mtest5.o liblmdb.a | |
mtest6: mtest6.o liblmdb.a | |
+mtest7: mtest7.o liblmdb.a | |
mdb.o: mdb.c lmdb.h midl.h | |
$(CC) $(CFLAGS) $(CPPFLAGS) -c mdb.c | |
diff --git a/libraries/liblmdb/mtest7.c b/libraries/liblmdb/mtest7.c | |
new file mode 100644 | |
index 0000000..dc84dd9 | |
--- /dev/null | |
+++ b/libraries/liblmdb/mtest7.c | |
@@ -0,0 +1,101 @@ | |
+/* | |
+ * Copyright 2011-2017 Howard Chu, Symas Corp. | |
+ * Copyright 2017 Lorenz Bauer, Cloudflare, Ltd. | |
+ * All rights reserved. | |
+ * | |
+ * Redistribution and use in source and binary forms, with or without | |
+ * modification, are permitted only as authorized by the OpenLDAP | |
+ * Public License. | |
+ * | |
+ * A copy of this license is available in the file LICENSE in the | |
+ * top-level directory of the distribution or, alternatively, at | |
+ * <http://www.OpenLDAP.org/license.html>. | |
+ */ | |
+/* | |
+ * Tests conditions under which SIGPIPE can be generated, and verifies we return EPIPE. | |
+ */ | |
+#include <stdio.h> | |
+#include <stdlib.h> | |
+#include <unistd.h> | |
+#include <pthread.h> | |
+#include <errno.h> | |
+#include <sys/types.h> | |
+#include <sys/socket.h> | |
+#include <fcntl.h> | |
+#include "lmdb.h" | |
+ | |
+#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr) | |
+#define E_ERRNO(expr) CHECK((expr) != -1 || (rc = errno) != 0, #expr) | |
+#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \ | |
+ "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort())) | |
+ | |
+/* Has to be larger than socketpair send / receive buffer */ | |
+#define VALSIZE (10*1024*1024) | |
+ | |
+void *threadfn(void *arg) | |
+{ | |
+ char buf[4096]; | |
+ int fd = (intptr_t)arg; | |
+ read(fd, (void*)buf, sizeof(buf)); | |
+ close(fd); | |
+ return NULL; | |
+} | |
+ | |
+int main(int argc,char * argv[]) | |
+{ | |
+ int rc, nfail = 0; | |
+ MDB_env *env; | |
+ MDB_txn *txn; | |
+ MDB_dbi dbi; | |
+ MDB_val key, val; | |
+ int pipefd[2]; | |
+ int socketfd[2]; | |
+ int filefd; | |
+ pthread_t thr; | |
+ | |
+ key.mv_size = 7; | |
+ key.mv_data = "testing"; | |
+ val.mv_size = VALSIZE; | |
+ val.mv_data = (void*)malloc(VALSIZE); | |
+ | |
+ E(mdb_env_create(&env)); | |
+ E(mdb_env_set_mapsize(env, VALSIZE*3)); | |
+ E(mdb_env_open(env, "./testdb", 0, 0664)); | |
+ E(mdb_txn_begin(env, NULL, 0, &txn)); | |
+ E(mdb_dbi_open(txn, NULL, 0, &dbi)); | |
+ E(mdb_put(txn, dbi, &key, &val, 0)); | |
+ E(mdb_txn_commit(txn)); | |
+ txn = NULL; | |
+ | |
+ // pipe | |
+ E_ERRNO(pipe(pipefd)); | |
+ E_ERRNO(close(pipefd[0])); | |
+ rc = mdb_env_copyfd2(env, pipefd[1], MDB_CP_COMPACT); | |
+ if (rc != EPIPE) { | |
+ nfail++; | |
+ fprintf(stderr, "invalid pipe return code: %s\n", mdb_strerror(rc)); | |
+ } | |
+ | |
+ // socketpair | |
+ E_ERRNO(socketpair(AF_UNIX, SOCK_STREAM, 0, socketfd)); | |
+ E(pthread_create(&thr, NULL, threadfn, (void *)(intptr_t)socketfd[0])); | |
+ rc = mdb_env_copyfd2(env, socketfd[1], MDB_CP_COMPACT); | |
+ if (rc != EPIPE && rc != ENOTCONN) { | |
+ nfail++; | |
+ fprintf(stderr, "invalid socketpair return code: %d %s\n", rc, mdb_strerror(rc)); | |
+ } | |
+ | |
+ // file, sanity check | |
+ E_ERRNO(filefd = open("./testdb/temp.out", O_WRONLY|O_CREAT|O_TRUNC, 0644)); | |
+ rc = mdb_env_copyfd2(env, filefd, MDB_CP_COMPACT); | |
+ if (rc) { | |
+ nfail++; | |
+ fprintf(stderr, "invalid file return code: %s\n", mdb_strerror(rc)); | |
+ } | |
+ close(filefd); | |
+ | |
+ mdb_dbi_close(env, dbi); | |
+ mdb_env_close(env); | |
+ free(val.mv_data); | |
+ return nfail; | |
+} | |
-- | |
2.9.0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment