1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /* This ifdef should match the one in sslsnce.c */
7 #if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
12 static SECStatus
single_process_sslMutex_Init(sslMutex
* pMutex
)
14 PR_ASSERT(pMutex
!= 0 && pMutex
->u
.sslLock
== 0 );
16 pMutex
->u
.sslLock
= PR_NewLock();
17 if (!pMutex
->u
.sslLock
) {
23 static SECStatus
single_process_sslMutex_Destroy(sslMutex
* pMutex
)
25 PR_ASSERT(pMutex
!= 0);
26 PR_ASSERT(pMutex
->u
.sslLock
!= 0);
27 if (!pMutex
->u
.sslLock
) {
28 PORT_SetError(PR_INVALID_ARGUMENT_ERROR
);
31 PR_DestroyLock(pMutex
->u
.sslLock
);
35 static SECStatus
single_process_sslMutex_Unlock(sslMutex
* pMutex
)
37 PR_ASSERT(pMutex
!= 0 );
38 PR_ASSERT(pMutex
->u
.sslLock
!=0);
39 if (!pMutex
->u
.sslLock
) {
40 PORT_SetError(PR_INVALID_ARGUMENT_ERROR
);
43 PR_Unlock(pMutex
->u
.sslLock
);
47 static SECStatus
single_process_sslMutex_Lock(sslMutex
* pMutex
)
49 PR_ASSERT(pMutex
!= 0);
50 PR_ASSERT(pMutex
->u
.sslLock
!= 0 );
51 if (!pMutex
->u
.sslLock
) {
52 PORT_SetError(PR_INVALID_ARGUMENT_ERROR
);
55 PR_Lock(pMutex
->u
.sslLock
);
59 #if defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD)
68 #define SSL_MUTEX_MAGIC 0xfeedfd
69 #define NONBLOCKING_POSTS 1 /* maybe this is faster */
74 #define FNONBLOCK O_NONBLOCK
78 setNonBlocking(int fd
, int nonBlocking
)
83 flags
= fcntl(fd
, F_GETFL
, 0);
90 err
= fcntl(fd
, F_SETFL
, flags
);
96 sslMutex_Init(sslMutex
*pMutex
, int shared
)
100 pMutex
->isMultiProcess
= (PRBool
)(shared
!= 0);
102 return single_process_sslMutex_Init(pMutex
);
104 pMutex
->u
.pipeStr
.mPipes
[0] = -1;
105 pMutex
->u
.pipeStr
.mPipes
[1] = -1;
106 pMutex
->u
.pipeStr
.mPipes
[2] = -1;
107 pMutex
->u
.pipeStr
.nWaiters
= 0;
109 err
= pipe(pMutex
->u
.pipeStr
.mPipes
);
111 nss_MD_unix_map_default_error(errno
);
114 #if NONBLOCKING_POSTS
115 err
= setNonBlocking(pMutex
->u
.pipeStr
.mPipes
[1], 1);
120 pMutex
->u
.pipeStr
.mPipes
[2] = SSL_MUTEX_MAGIC
;
122 #if defined(LINUX) && defined(i386)
123 /* Pipe starts out empty */
126 /* Pipe starts with one byte. */
127 return sslMutex_Unlock(pMutex
);
131 nss_MD_unix_map_default_error(errno
);
132 close(pMutex
->u
.pipeStr
.mPipes
[0]);
133 close(pMutex
->u
.pipeStr
.mPipes
[1]);
138 sslMutex_Destroy(sslMutex
*pMutex
, PRBool processLocal
)
140 if (PR_FALSE
== pMutex
->isMultiProcess
) {
141 return single_process_sslMutex_Destroy(pMutex
);
143 if (pMutex
->u
.pipeStr
.mPipes
[2] != SSL_MUTEX_MAGIC
) {
144 PORT_SetError(PR_INVALID_ARGUMENT_ERROR
);
147 close(pMutex
->u
.pipeStr
.mPipes
[0]);
148 close(pMutex
->u
.pipeStr
.mPipes
[1]);
154 pMutex
->u
.pipeStr
.mPipes
[0] = -1;
155 pMutex
->u
.pipeStr
.mPipes
[1] = -1;
156 pMutex
->u
.pipeStr
.mPipes
[2] = -1;
157 pMutex
->u
.pipeStr
.nWaiters
= 0;
162 #if defined(LINUX) && defined(i386)
163 /* No memory barrier needed for this platform */
165 /* nWaiters includes the holder of the lock (if any) and the number
166 ** threads waiting for it. After incrementing nWaiters, if the count
167 ** is exactly 1, then you have the lock and may proceed. If the
168 ** count is greater than 1, then you must wait on the pipe.
173 sslMutex_Unlock(sslMutex
*pMutex
)
176 if (PR_FALSE
== pMutex
->isMultiProcess
) {
177 return single_process_sslMutex_Unlock(pMutex
);
180 if (pMutex
->u
.pipeStr
.mPipes
[2] != SSL_MUTEX_MAGIC
) {
181 PORT_SetError(PR_INVALID_ARGUMENT_ERROR
);
184 /* Do Memory Barrier here. */
185 newValue
= PR_ATOMIC_DECREMENT(&pMutex
->u
.pipeStr
.nWaiters
);
190 cc
= write(pMutex
->u
.pipeStr
.mPipes
[1], &c
, 1);
191 } while (cc
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
194 nss_MD_unix_map_default_error(errno
);
196 PORT_SetError(PR_UNKNOWN_ERROR
);
204 sslMutex_Lock(sslMutex
*pMutex
)
207 if (PR_FALSE
== pMutex
->isMultiProcess
) {
208 return single_process_sslMutex_Lock(pMutex
);
211 if (pMutex
->u
.pipeStr
.mPipes
[2] != SSL_MUTEX_MAGIC
) {
212 PORT_SetError(PR_INVALID_ARGUMENT_ERROR
);
215 newValue
= PR_ATOMIC_INCREMENT(&pMutex
->u
.pipeStr
.nWaiters
);
216 /* Do Memory Barrier here. */
221 cc
= read(pMutex
->u
.pipeStr
.mPipes
[0], &c
, 1);
222 } while (cc
< 0 && errno
== EINTR
);
225 nss_MD_unix_map_default_error(errno
);
227 PORT_SetError(PR_UNKNOWN_ERROR
);
236 /* Using Atomic operations requires the use of a memory barrier instruction
237 ** on PowerPC, Sparc, and Alpha. NSPR's PR_Atomic functions do not perform
238 ** them, and NSPR does not provide a function that does them (e.g. PR_Barrier).
239 ** So, we don't use them on those platforms.
243 sslMutex_Unlock(sslMutex
*pMutex
)
248 if (PR_FALSE
== pMutex
->isMultiProcess
) {
249 return single_process_sslMutex_Unlock(pMutex
);
252 if (pMutex
->u
.pipeStr
.mPipes
[2] != SSL_MUTEX_MAGIC
) {
253 PORT_SetError(PR_INVALID_ARGUMENT_ERROR
);
257 cc
= write(pMutex
->u
.pipeStr
.mPipes
[1], &c
, 1);
258 } while (cc
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
261 nss_MD_unix_map_default_error(errno
);
263 PORT_SetError(PR_UNKNOWN_ERROR
);
271 sslMutex_Lock(sslMutex
*pMutex
)
276 if (PR_FALSE
== pMutex
->isMultiProcess
) {
277 return single_process_sslMutex_Lock(pMutex
);
280 if (pMutex
->u
.pipeStr
.mPipes
[2] != SSL_MUTEX_MAGIC
) {
281 PORT_SetError(PR_INVALID_ARGUMENT_ERROR
);
286 cc
= read(pMutex
->u
.pipeStr
.mPipes
[0], &c
, 1);
287 } while (cc
< 0 && errno
== EINTR
);
290 nss_MD_unix_map_default_error(errno
);
292 PORT_SetError(PR_UNKNOWN_ERROR
);
303 #include "win32err.h"
305 /* on Windows, we need to find the optimal type of locking mechanism to use
309 1) single-process, use a PRLock, as for all other platforms
310 2) Win95 multi-process, use a Win32 mutex
311 3) on WINNT multi-process, use a PRLock + a Win32 mutex
317 SECStatus
sslMutex_2LevelInit(sslMutex
*sem
)
319 /* the following adds a PRLock to sslMutex . This is done in each
320 process of a multi-process server and is only needed on WINNT, if
321 using fibers. We can't tell if native threads or fibers are used, so
322 we always do it on WINNT
326 /* we need to reset the sslLock in the children or the single_process init
327 function below will assert */
328 sem
->u
.sslLock
= NULL
;
330 return single_process_sslMutex_Init(sem
);
333 static SECStatus
sslMutex_2LevelDestroy(sslMutex
*sem
)
335 return single_process_sslMutex_Destroy(sem
);
341 sslMutex_Init(sslMutex
*pMutex
, int shared
)
347 SECURITY_ATTRIBUTES attributes
=
348 { sizeof(SECURITY_ATTRIBUTES
), NULL
, TRUE
};
350 PR_ASSERT(pMutex
!= 0 && (pMutex
->u
.sslMutx
== 0 ||
351 pMutex
->u
.sslMutx
== INVALID_HANDLE_VALUE
) );
353 pMutex
->isMultiProcess
= (PRBool
)(shared
!= 0);
355 if (PR_FALSE
== pMutex
->isMultiProcess
) {
356 return single_process_sslMutex_Init(pMutex
);
360 /* we need a lock on WINNT for fibers in the parent process */
361 retvalue
= sslMutex_2LevelInit(pMutex
);
362 if (SECSuccess
!= retvalue
)
366 if (!pMutex
|| ((hMutex
= pMutex
->u
.sslMutx
) != 0 &&
367 hMutex
!= INVALID_HANDLE_VALUE
)) {
368 PORT_SetError(PR_INVALID_ARGUMENT_ERROR
);
371 attributes
.bInheritHandle
= (shared
? TRUE
: FALSE
);
372 hMutex
= CreateMutex(&attributes
, FALSE
, NULL
);
373 if (hMutex
== NULL
) {
374 hMutex
= INVALID_HANDLE_VALUE
;
375 nss_MD_win32_map_default_error(GetLastError());
378 pMutex
->u
.sslMutx
= hMutex
;
383 sslMutex_Destroy(sslMutex
*pMutex
, PRBool processLocal
)
387 int retvalue
= SECSuccess
;
389 PR_ASSERT(pMutex
!= 0);
390 if (PR_FALSE
== pMutex
->isMultiProcess
) {
391 return single_process_sslMutex_Destroy(pMutex
);
394 /* multi-process mode */
396 /* on NT, get rid of the PRLock used for fibers within a process */
397 retvalue
= sslMutex_2LevelDestroy(pMutex
);
400 PR_ASSERT( pMutex
->u
.sslMutx
!= 0 &&
401 pMutex
->u
.sslMutx
!= INVALID_HANDLE_VALUE
);
402 if (!pMutex
|| (hMutex
= pMutex
->u
.sslMutx
) == 0
403 || hMutex
== INVALID_HANDLE_VALUE
) {
404 PORT_SetError(PR_INVALID_ARGUMENT_ERROR
);
408 rv
= CloseHandle(hMutex
); /* ignore error */
409 if (!processLocal
&& rv
) {
410 pMutex
->u
.sslMutx
= hMutex
= INVALID_HANDLE_VALUE
;
413 nss_MD_win32_map_default_error(GetLastError());
414 retvalue
= SECFailure
;
420 sslMutex_Unlock(sslMutex
*pMutex
)
422 BOOL success
= FALSE
;
425 PR_ASSERT(pMutex
!= 0 );
426 if (PR_FALSE
== pMutex
->isMultiProcess
) {
427 return single_process_sslMutex_Unlock(pMutex
);
430 PR_ASSERT(pMutex
->u
.sslMutx
!= 0 &&
431 pMutex
->u
.sslMutx
!= INVALID_HANDLE_VALUE
);
432 if (!pMutex
|| (hMutex
= pMutex
->u
.sslMutx
) == 0 ||
433 hMutex
== INVALID_HANDLE_VALUE
) {
434 PORT_SetError(PR_INVALID_ARGUMENT_ERROR
);
437 success
= ReleaseMutex(hMutex
);
439 nss_MD_win32_map_default_error(GetLastError());
443 return single_process_sslMutex_Unlock(pMutex
);
444 /* release PRLock for other fibers in the process */
451 sslMutex_Lock(sslMutex
*pMutex
)
457 SECStatus retvalue
= SECSuccess
;
458 PR_ASSERT(pMutex
!= 0);
460 if (PR_FALSE
== pMutex
->isMultiProcess
) {
461 return single_process_sslMutex_Lock(pMutex
);
464 /* lock first to preserve from other threads/fibers
465 in the same process */
466 retvalue
= single_process_sslMutex_Lock(pMutex
);
468 PR_ASSERT(pMutex
->u
.sslMutx
!= 0 &&
469 pMutex
->u
.sslMutx
!= INVALID_HANDLE_VALUE
);
470 if (!pMutex
|| (hMutex
= pMutex
->u
.sslMutx
) == 0 ||
471 hMutex
== INVALID_HANDLE_VALUE
) {
472 PORT_SetError(PR_INVALID_ARGUMENT_ERROR
);
473 return SECFailure
; /* what else ? */
475 /* acquire the mutex to be the only owner accross all other processes */
476 event
= WaitForSingleObject(hMutex
, INFINITE
);
484 #if defined(WAIT_IO_COMPLETION)
485 case WAIT_IO_COMPLETION
:
487 default: /* should never happen. nothing we can do. */
488 PR_ASSERT(!("WaitForSingleObject returned invalid value."));
489 PORT_SetError(PR_UNKNOWN_ERROR
);
493 case WAIT_FAILED
: /* failure returns this */
495 lastError
= GetLastError(); /* for debugging */
496 nss_MD_win32_map_default_error(lastError
);
500 if (! (SECSuccess
== retvalue
&& SECSuccess
== rv
)) {
507 #elif defined(XP_UNIX)
510 #include "unix_err.h"
513 sslMutex_Init(sslMutex
*pMutex
, int shared
)
517 pMutex
->isMultiProcess
= (PRBool
)(shared
!= 0);
519 return single_process_sslMutex_Init(pMutex
);
522 rv
= sem_init(&pMutex
->u
.sem
, shared
, 1);
523 } while (rv
< 0 && errno
== EINTR
);
525 nss_MD_unix_map_default_error(errno
);
532 sslMutex_Destroy(sslMutex
*pMutex
, PRBool processLocal
)
535 if (PR_FALSE
== pMutex
->isMultiProcess
) {
536 return single_process_sslMutex_Destroy(pMutex
);
539 /* semaphores are global resources. See SEM_DESTROY(3) man page */
544 rv
= sem_destroy(&pMutex
->u
.sem
);
545 } while (rv
< 0 && errno
== EINTR
);
547 nss_MD_unix_map_default_error(errno
);
554 sslMutex_Unlock(sslMutex
*pMutex
)
557 if (PR_FALSE
== pMutex
->isMultiProcess
) {
558 return single_process_sslMutex_Unlock(pMutex
);
561 rv
= sem_post(&pMutex
->u
.sem
);
562 } while (rv
< 0 && errno
== EINTR
);
564 nss_MD_unix_map_default_error(errno
);
571 sslMutex_Lock(sslMutex
*pMutex
)
574 if (PR_FALSE
== pMutex
->isMultiProcess
) {
575 return single_process_sslMutex_Lock(pMutex
);
578 rv
= sem_wait(&pMutex
->u
.sem
);
579 } while (rv
< 0 && errno
== EINTR
);
581 nss_MD_unix_map_default_error(errno
);
590 sslMutex_Init(sslMutex
*pMutex
, int shared
)
593 pMutex
->isMultiProcess
= (PRBool
)(shared
!= 0);
595 return single_process_sslMutex_Init(pMutex
);
597 PORT_Assert(!("sslMutex_Init not implemented for multi-process applications !"));
598 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR
);
603 sslMutex_Destroy(sslMutex
*pMutex
, PRBool processLocal
)
606 if (PR_FALSE
== pMutex
->isMultiProcess
) {
607 return single_process_sslMutex_Destroy(pMutex
);
609 PORT_Assert(!("sslMutex_Destroy not implemented for multi-process applications !"));
610 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR
);
615 sslMutex_Unlock(sslMutex
*pMutex
)
618 if (PR_FALSE
== pMutex
->isMultiProcess
) {
619 return single_process_sslMutex_Unlock(pMutex
);
621 PORT_Assert(!("sslMutex_Unlock not implemented for multi-process applications !"));
622 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR
);
627 sslMutex_Lock(sslMutex
*pMutex
)
630 if (PR_FALSE
== pMutex
->isMultiProcess
) {
631 return single_process_sslMutex_Lock(pMutex
);
633 PORT_Assert(!("sslMutex_Lock not implemented for multi-process applications !"));
634 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR
);