summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornelsonb%netscape.com <devnull@localhost>2001-06-08 02:56:31 +0000
committernelsonb%netscape.com <devnull@localhost>2001-06-08 02:56:31 +0000
commit30debe533c0537e49febeefe135ea069d7fbe2f2 (patch)
treee311c95c57b62c2a372a52266e8935a14191684a
parent3dfc0af3a855abc59786f626a28ee27ede0ec9cf (diff)
downloadnss-hg-30debe533c0537e49febeefe135ea069d7fbe2f2.tar.gz
Portable POSIX-like unnamed semaphores that work in process-shared memory.
-rw-r--r--security/nss/lib/ssl/sslmutex.c385
-rw-r--r--security/nss/lib/ssl/sslmutex.h101
2 files changed, 486 insertions, 0 deletions
diff --git a/security/nss/lib/ssl/sslmutex.c b/security/nss/lib/ssl/sslmutex.c
new file mode 100644
index 000000000..7c021ffd7
--- /dev/null
+++ b/security/nss/lib/ssl/sslmutex.c
@@ -0,0 +1,385 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 2001 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ *
+ * $Id$
+ */
+
+#include "sslmutex.h"
+#include "prerr.h"
+
+#if defined(LINUX) || defined(AIX)
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include "unix_err.h"
+
+#define SSL_MUTEX_MAGIC 0xfeedfd
+#define NONBLOCKING_POSTS 1 /* maybe this is faster */
+
+#if NONBLOCKING_POSTS
+
+#ifndef FNONBLOCK
+#define FNONBLOCK O_NONBLOCK
+#endif
+
+static int
+setNonBlocking(int fd, int nonBlocking)
+{
+ int flags;
+ int err;
+
+ flags = fcntl(fd, F_GETFL, 0);
+ if (0 > flags)
+ return flags;
+ if (nonBlocking)
+ flags |= FNONBLOCK;
+ else
+ flags &= ~FNONBLOCK;
+ err = fcntl(fd, F_SETFL, flags);
+ return err;
+}
+#endif
+
+SECStatus
+sslMutex_Init(sslMutex *pMutex, int shared)
+{
+ int err;
+ int mPipes[3];
+ char c = 1;
+
+ memset(pMutex, -1, sizeof *pMutex);
+ err = pipe(mPipes);
+ if (err) {
+ return err;
+ }
+ /* close-on-exec is false by default */
+ if (!shared) {
+ err = fcntl(mPipes[0], F_SETFD, FD_CLOEXEC);
+ if (err)
+ goto loser;
+
+ err = fcntl(mPipes[1], F_SETFD, FD_CLOEXEC);
+ if (err)
+ goto loser;
+ }
+
+#if NONBLOCKING_POSTS
+ err = setNonBlocking(mPipes[1], 1);
+ if (err)
+ goto loser;
+#endif
+
+
+ do {
+ err = write(mPipes[1], &c, 1);
+ } while (err < 0 && (errno == EINTR || errno == EAGAIN));
+ if (0 > err)
+ goto loser;
+
+ mPipes[2] = SSL_MUTEX_MAGIC;
+
+ memcpy(pMutex, mPipes, sizeof mPipes);
+ return SECSuccess;
+
+loser:
+ nss_MD_unix_map_default_error(errno);
+ close(mPipes[0]);
+ close(mPipes[1]);
+ return SECFailure;
+}
+
+SECStatus
+sslMutex_Destroy(sslMutex *pMutex)
+{
+ int * mPipes = (int *)pMutex;
+ if (mPipes[2] != SSL_MUTEX_MAGIC) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ close(mPipes[0]);
+ close(mPipes[1]);
+ memset(pMutex, -1, sizeof *pMutex);
+ return SECSuccess;
+}
+
+SECStatus
+sslMutex_Unlock(sslMutex *pMutex)
+{
+ int * mPipes = (int *)pMutex;
+ int cc;
+ char c = 1;
+
+ if (mPipes[2] != SSL_MUTEX_MAGIC) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ do {
+ cc = write(mPipes[1], &c, 1);
+ } while (cc < 0 && (errno == EINTR || errno == EAGAIN));
+ if (cc == 1)
+ return SECSuccess;
+ if (cc < 0)
+ nss_MD_unix_map_default_error(errno);
+ else
+ PORT_SetError(PR_UNKNOWN_ERROR);
+ return SECFailure;
+}
+
+SECStatus
+sslMutex_Lock(sslMutex *pMutex)
+{
+ int * mPipes = (int *)pMutex;
+ int cc;
+ char c;
+
+ if (mPipes[2] != SSL_MUTEX_MAGIC) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ do {
+ cc = read(mPipes[0], &c, 1);
+ } while (cc < 0 && errno == EINTR);
+ if (cc == 1)
+ return SECSuccess;
+ if (cc < 0)
+ nss_MD_unix_map_default_error(errno);
+ else
+ PORT_SetError(PR_UNKNOWN_ERROR);
+ return SECFailure;
+}
+
+#elif defined(WIN32)
+
+#include "win32err.h"
+
+/* The presence of the TRUE element in this struct makes the semaphore
+ * inheritable. The NULL means use process's default security descriptor.
+ */
+
+SECStatus
+sslMutex_Init(sslMutex *pMutex, int shared)
+{
+
+ HANDLE hMutex;
+ SECURITY_ATTRIBUTES attributes =
+ { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
+
+ PR_ASSERT(pMutex != 0 && (*pMutex == 0 || *pMutex == INVALID_HANDLE_VALUE));
+ if (!pMutex || ((hMutex = *pMutex) != 0 && hMutex != INVALID_HANDLE_VALUE)) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ attributes.bInheritHandle = (shared ? TRUE : FALSE);
+ hMutex = CreateMutex(&attributes, FALSE, NULL);
+ if (hMutex == NULL) {
+ hMutex = INVALID_HANDLE_VALUE;
+ nss_MD_win32_map_default_error(GetLastError());
+ return SECFailure;
+ }
+ *pMutex = hMutex;
+ return SECSuccess;
+}
+
+int
+sslMutex_Destroy(sslMutex *pMutex)
+{
+ HANDLE hMutex;
+ int rv;
+
+ PR_ASSERT(pMutex != 0 && *pMutex != 0 && *pMutex != INVALID_HANDLE_VALUE);
+ if (!pMutex || (hMutex = *pMutex) == 0 || hMutex == INVALID_HANDLE_VALUE) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ rv = CloseHandle(hMutex); /* ignore error */
+ if (rv) {
+ *pMutex = hMutex = INVALID_HANDLE_VALUE;
+ return SECSuccess;
+ }
+ nss_MD_win32_map_default_error(GetLastError());
+ return SECFailure;
+}
+
+int
+sslMutex_Unlock(sslMutex *pMutex)
+{
+ BOOL success = FALSE;
+ HANDLE hMutex;
+
+ PR_ASSERT(pMutex != 0 && *pMutex != 0 && *pMutex != INVALID_HANDLE_VALUE);
+ if (!pMutex || (hMutex = *pMutex) == 0 || hMutex == INVALID_HANDLE_VALUE) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
+ success = ReleaseMutex(hMutex);
+ if (!success) {
+ nss_MD_win32_map_default_error(GetLastError());
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+int
+sslMutex_Lock(sslMutex *pMutex)
+{
+ HANDLE hMutex;
+ DWORD event;
+ DWORD lastError;
+ SECStatus rv;
+
+ PR_ASSERT(pMutex != 0 && *pMutex != 0 && *pMutex != INVALID_HANDLE_VALUE);
+ if (!pMutex || (hMutex = *pMutex) == 0 || hMutex == INVALID_HANDLE_VALUE) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure; /* what else ? */
+ }
+ event = WaitForSingleObject(hMutex, INFINITE);
+ switch (event) {
+ case WAIT_OBJECT_0:
+ case WAIT_ABANDONED:
+ rv = SECSuccess;
+ break;
+
+ case WAIT_TIMEOUT:
+ case WAIT_IO_COMPLETION:
+ default: /* should never happen. nothing we can do. */
+ PR_ASSERT(!("WaitForSingleObject returned invalid value."));
+ PORT_SetError(PR_UNKNOWN_ERROR);
+ rv = SECFailure;
+ break;
+
+ case WAIT_FAILED: /* failure returns this */
+ rv = SECFailure;
+ lastError = GetLastError(); /* for debugging */
+ nss_MD_win32_map_default_error(lastError);
+ break;
+ }
+ return rv;
+}
+
+#elif defined(XP_UNIX)
+
+#include <errno.h>
+#include "unix_err.h"
+
+SECStatus
+sslMutex_Init(sslMutex *pMutex, int shared)
+{
+ int rv;
+ do {
+ rv = sem_init(pMutex, shared, 1);
+ } while (rv < 0 && errno == EINTR);
+ if (rv < 0) {
+ nss_MD_unix_map_default_error(errno);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+sslMutex_Destroy(sslMutex *pMutex)
+{
+ int rv;
+ do {
+ rv = sem_destroy(pMutex);
+ } while (rv < 0 && errno == EINTR);
+ if (rv < 0) {
+ nss_MD_unix_map_default_error(errno);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+sslMutex_Unlock(sslMutex *pMutex)
+{
+ int rv;
+ do {
+ rv = sem_post(pMutex);
+ } while (rv < 0 && errno == EINTR);
+ if (rv < 0) {
+ nss_MD_unix_map_default_error(errno);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+sslMutex_Lock(sslMutex *pMutex)
+{
+ int rv;
+ do {
+ rv = sem_wait(pMutex);
+ } while (rv < 0 && errno == EINTR);
+ if (rv < 0) {
+ nss_MD_unix_map_default_error(errno);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+#else
+
+SECStatus
+sslMutex_Init(sslMutex *pMutex, int shared)
+{
+ PORT_Assert(!("sslMutex_Init not implemented!"));
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return SECFailure;
+}
+
+SECStatus
+sslMutex_Destroy(sslMutex *pMutex)
+{
+ PORT_Assert(!("sslMutex_Destroy not implemented!"));
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return SECFailure;
+}
+
+SECStatus
+sslMutex_Unlock(sslMutex *pMutex)
+{
+ PORT_Assert(!("sslMutex_Unlock not implemented!"));
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return SECFailure;
+}
+
+SECStatus
+sslMutex_Lock(sslMutex *pMutex)
+{
+ PORT_Assert(!("sslMutex_Lock not implemented!"));
+ PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
+ return SECFailure;
+}
+
+#endif
diff --git a/security/nss/lib/ssl/sslmutex.h b/security/nss/lib/ssl/sslmutex.h
new file mode 100644
index 000000000..a02c48cf5
--- /dev/null
+++ b/security/nss/lib/ssl/sslmutex.h
@@ -0,0 +1,101 @@
+/*
+ * The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS
+ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 2001 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU General Public License Version 2 or later (the
+ * "GPL"), in which case the provisions of the GPL are applicable
+ * instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of the GPL and not to
+ * allow others to use your version of this file under the MPL,
+ * indicate your decision by deleting the provisions above and
+ * replace them with the notice and other provisions required by
+ * the GPL. If you do not delete the provisions above, a recipient
+ * may use your version of this file under either the MPL or the
+ * GPL.
+ *
+ * $Id$
+ */
+#ifndef __SSLMUTEX_H_
+#define __SSLMUTEX_H_ 1
+
+/* What SSL really wants is portable process-shared unnamed mutexes in
+ * shared memory, that have the property that if the process that holds
+ * them dies, they are released automatically, and that (unlike fcntl
+ * record locking) lock to the thread, not to the process.
+ * NSPR doesn't provide that.
+ * Windows has mutexes that meet that description, but they're not portable.
+ * POSIX mutexes are not automatically released when the holder dies,
+ * and other processes/threads cannot release the mutex on behalf of the
+ * dead holder.
+ * POSIX semaphores can be used to accomplish this on systems that implement
+ * process-shared unnamed POSIX semaphores, because a watchdog thread can
+ * discover and release semaphores that were held by a dead process.
+ * On systems that do not support process-shared POSIX unnamed semaphores,
+ * they can be emulated using pipes.
+ * The performance cost of doing that is not yet measured.
+ *
+ * So, this API looks a lot like POSIX pthread mutexes.
+ */
+
+#if defined(WIN32)
+
+#include <wtypes.h>
+typedef HANDLE sslMutex;
+typedef int sslPID;
+
+#elif defined(LINUX) || defined(AIX)
+
+#include <sys/types.h>
+
+typedef struct { int ps[3]; } sslMutex;
+typedef pid_t sslPID;
+
+#elif defined(XP_UNIX) /* other types of Unix */
+
+#include <sys/types.h> /* for pid_t */
+#include <semaphore.h> /* for sem_t, and sem_* functions */
+
+typedef sem_t sslMutex;
+typedef pid_t sslPID;
+
+#else
+
+/* what platform is this ?? */
+
+typedef int sslMutex;
+typedef int sslPID;
+
+#endif
+
+#include "seccomon.h"
+
+SEC_BEGIN_PROTOS
+
+extern SECStatus sslMutex_Init(sslMutex *sem, int shared);
+
+extern SECStatus sslMutex_Destroy(sslMutex *sem);
+
+extern SECStatus sslMutex_Unlock(sslMutex *sem);
+
+extern SECStatus sslMutex_Lock(sslMutex *sem);
+
+SEC_END_PROTOS
+
+#endif