Revert "Merged all Chromoting Host code into remoting_core.dll (Windows)."
[chromium-blink-merge.git] / net / third_party / nss / ssl / sslmutex.c
blob6b6c9c9378c31e309c87365d7fa979b25e445e2c
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/. */
4 /* $Id: sslmutex.c,v 1.28 2012/04/25 14:50:12 gerv%gerv.net Exp $ */
6 #include "seccomon.h"
7 /* This ifdef should match the one in sslsnce.c */
8 #if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
10 #include "sslmutex.h"
11 #include "prerr.h"
13 static SECStatus single_process_sslMutex_Init(sslMutex* pMutex)
15 PR_ASSERT(pMutex != 0 && pMutex->u.sslLock == 0 );
17 pMutex->u.sslLock = PR_NewLock();
18 if (!pMutex->u.sslLock) {
19 return SECFailure;
21 return SECSuccess;
24 static SECStatus single_process_sslMutex_Destroy(sslMutex* pMutex)
26 PR_ASSERT(pMutex != 0);
27 PR_ASSERT(pMutex->u.sslLock!= 0);
28 if (!pMutex->u.sslLock) {
29 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
30 return SECFailure;
32 PR_DestroyLock(pMutex->u.sslLock);
33 return SECSuccess;
36 static SECStatus single_process_sslMutex_Unlock(sslMutex* pMutex)
38 PR_ASSERT(pMutex != 0 );
39 PR_ASSERT(pMutex->u.sslLock !=0);
40 if (!pMutex->u.sslLock) {
41 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
42 return SECFailure;
44 PR_Unlock(pMutex->u.sslLock);
45 return SECSuccess;
48 static SECStatus single_process_sslMutex_Lock(sslMutex* pMutex)
50 PR_ASSERT(pMutex != 0);
51 PR_ASSERT(pMutex->u.sslLock != 0 );
52 if (!pMutex->u.sslLock) {
53 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
54 return SECFailure;
56 PR_Lock(pMutex->u.sslLock);
57 return SECSuccess;
60 #if defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD)
62 #include <unistd.h>
63 #include <fcntl.h>
64 #include <string.h>
65 #include <errno.h>
66 #include "unix_err.h"
67 #include "pratom.h"
69 #define SSL_MUTEX_MAGIC 0xfeedfd
70 #define NONBLOCKING_POSTS 1 /* maybe this is faster */
72 #if NONBLOCKING_POSTS
74 #ifndef FNONBLOCK
75 #define FNONBLOCK O_NONBLOCK
76 #endif
78 static int
79 setNonBlocking(int fd, int nonBlocking)
81 int flags;
82 int err;
84 flags = fcntl(fd, F_GETFL, 0);
85 if (0 > flags)
86 return flags;
87 if (nonBlocking)
88 flags |= FNONBLOCK;
89 else
90 flags &= ~FNONBLOCK;
91 err = fcntl(fd, F_SETFL, flags);
92 return err;
94 #endif
96 SECStatus
97 sslMutex_Init(sslMutex *pMutex, int shared)
99 int err;
100 PR_ASSERT(pMutex);
101 pMutex->isMultiProcess = (PRBool)(shared != 0);
102 if (!shared) {
103 return single_process_sslMutex_Init(pMutex);
105 pMutex->u.pipeStr.mPipes[0] = -1;
106 pMutex->u.pipeStr.mPipes[1] = -1;
107 pMutex->u.pipeStr.mPipes[2] = -1;
108 pMutex->u.pipeStr.nWaiters = 0;
110 err = pipe(pMutex->u.pipeStr.mPipes);
111 if (err) {
112 nss_MD_unix_map_default_error(errno);
113 return err;
115 #if NONBLOCKING_POSTS
116 err = setNonBlocking(pMutex->u.pipeStr.mPipes[1], 1);
117 if (err)
118 goto loser;
119 #endif
121 pMutex->u.pipeStr.mPipes[2] = SSL_MUTEX_MAGIC;
123 #if defined(LINUX) && defined(i386)
124 /* Pipe starts out empty */
125 return SECSuccess;
126 #else
127 /* Pipe starts with one byte. */
128 return sslMutex_Unlock(pMutex);
129 #endif
131 loser:
132 nss_MD_unix_map_default_error(errno);
133 close(pMutex->u.pipeStr.mPipes[0]);
134 close(pMutex->u.pipeStr.mPipes[1]);
135 return SECFailure;
138 SECStatus
139 sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
141 if (PR_FALSE == pMutex->isMultiProcess) {
142 return single_process_sslMutex_Destroy(pMutex);
144 if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
145 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
146 return SECFailure;
148 close(pMutex->u.pipeStr.mPipes[0]);
149 close(pMutex->u.pipeStr.mPipes[1]);
151 if (processLocal) {
152 return SECSuccess;
155 pMutex->u.pipeStr.mPipes[0] = -1;
156 pMutex->u.pipeStr.mPipes[1] = -1;
157 pMutex->u.pipeStr.mPipes[2] = -1;
158 pMutex->u.pipeStr.nWaiters = 0;
160 return SECSuccess;
163 #if defined(LINUX) && defined(i386)
164 /* No memory barrier needed for this platform */
166 /* nWaiters includes the holder of the lock (if any) and the number
167 ** threads waiting for it. After incrementing nWaiters, if the count
168 ** is exactly 1, then you have the lock and may proceed. If the
169 ** count is greater than 1, then you must wait on the pipe.
173 SECStatus
174 sslMutex_Unlock(sslMutex *pMutex)
176 PRInt32 newValue;
177 if (PR_FALSE == pMutex->isMultiProcess) {
178 return single_process_sslMutex_Unlock(pMutex);
181 if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
182 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
183 return SECFailure;
185 /* Do Memory Barrier here. */
186 newValue = PR_ATOMIC_DECREMENT(&pMutex->u.pipeStr.nWaiters);
187 if (newValue > 0) {
188 int cc;
189 char c = 1;
190 do {
191 cc = write(pMutex->u.pipeStr.mPipes[1], &c, 1);
192 } while (cc < 0 && (errno == EINTR || errno == EAGAIN));
193 if (cc != 1) {
194 if (cc < 0)
195 nss_MD_unix_map_default_error(errno);
196 else
197 PORT_SetError(PR_UNKNOWN_ERROR);
198 return SECFailure;
201 return SECSuccess;
204 SECStatus
205 sslMutex_Lock(sslMutex *pMutex)
207 PRInt32 newValue;
208 if (PR_FALSE == pMutex->isMultiProcess) {
209 return single_process_sslMutex_Lock(pMutex);
212 if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
213 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
214 return SECFailure;
216 newValue = PR_ATOMIC_INCREMENT(&pMutex->u.pipeStr.nWaiters);
217 /* Do Memory Barrier here. */
218 if (newValue > 1) {
219 int cc;
220 char c;
221 do {
222 cc = read(pMutex->u.pipeStr.mPipes[0], &c, 1);
223 } while (cc < 0 && errno == EINTR);
224 if (cc != 1) {
225 if (cc < 0)
226 nss_MD_unix_map_default_error(errno);
227 else
228 PORT_SetError(PR_UNKNOWN_ERROR);
229 return SECFailure;
232 return SECSuccess;
235 #else
237 /* Using Atomic operations requires the use of a memory barrier instruction
238 ** on PowerPC, Sparc, and Alpha. NSPR's PR_Atomic functions do not perform
239 ** them, and NSPR does not provide a function that does them (e.g. PR_Barrier).
240 ** So, we don't use them on those platforms.
243 SECStatus
244 sslMutex_Unlock(sslMutex *pMutex)
246 int cc;
247 char c = 1;
249 if (PR_FALSE == pMutex->isMultiProcess) {
250 return single_process_sslMutex_Unlock(pMutex);
253 if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
254 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
255 return SECFailure;
257 do {
258 cc = write(pMutex->u.pipeStr.mPipes[1], &c, 1);
259 } while (cc < 0 && (errno == EINTR || errno == EAGAIN));
260 if (cc != 1) {
261 if (cc < 0)
262 nss_MD_unix_map_default_error(errno);
263 else
264 PORT_SetError(PR_UNKNOWN_ERROR);
265 return SECFailure;
268 return SECSuccess;
271 SECStatus
272 sslMutex_Lock(sslMutex *pMutex)
274 int cc;
275 char c;
277 if (PR_FALSE == pMutex->isMultiProcess) {
278 return single_process_sslMutex_Lock(pMutex);
281 if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
282 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
283 return SECFailure;
286 do {
287 cc = read(pMutex->u.pipeStr.mPipes[0], &c, 1);
288 } while (cc < 0 && errno == EINTR);
289 if (cc != 1) {
290 if (cc < 0)
291 nss_MD_unix_map_default_error(errno);
292 else
293 PORT_SetError(PR_UNKNOWN_ERROR);
294 return SECFailure;
297 return SECSuccess;
300 #endif
302 #elif defined(WIN32)
304 #include "win32err.h"
306 /* on Windows, we need to find the optimal type of locking mechanism to use
307 for the sslMutex.
309 There are 3 cases :
310 1) single-process, use a PRLock, as for all other platforms
311 2) Win95 multi-process, use a Win32 mutex
312 3) on WINNT multi-process, use a PRLock + a Win32 mutex
316 #ifdef WINNT
318 SECStatus sslMutex_2LevelInit(sslMutex *sem)
320 /* the following adds a PRLock to sslMutex . This is done in each
321 process of a multi-process server and is only needed on WINNT, if
322 using fibers. We can't tell if native threads or fibers are used, so
323 we always do it on WINNT
325 PR_ASSERT(sem);
326 if (sem) {
327 /* we need to reset the sslLock in the children or the single_process init
328 function below will assert */
329 sem->u.sslLock = NULL;
331 return single_process_sslMutex_Init(sem);
334 static SECStatus sslMutex_2LevelDestroy(sslMutex *sem)
336 return single_process_sslMutex_Destroy(sem);
339 #endif
341 SECStatus
342 sslMutex_Init(sslMutex *pMutex, int shared)
344 #ifdef WINNT
345 SECStatus retvalue;
346 #endif
347 HANDLE hMutex;
348 SECURITY_ATTRIBUTES attributes =
349 { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
351 PR_ASSERT(pMutex != 0 && (pMutex->u.sslMutx == 0 ||
352 pMutex->u.sslMutx == INVALID_HANDLE_VALUE) );
354 pMutex->isMultiProcess = (PRBool)(shared != 0);
356 if (PR_FALSE == pMutex->isMultiProcess) {
357 return single_process_sslMutex_Init(pMutex);
360 #ifdef WINNT
361 /* we need a lock on WINNT for fibers in the parent process */
362 retvalue = sslMutex_2LevelInit(pMutex);
363 if (SECSuccess != retvalue)
364 return SECFailure;
365 #endif
367 if (!pMutex || ((hMutex = pMutex->u.sslMutx) != 0 &&
368 hMutex != INVALID_HANDLE_VALUE)) {
369 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
370 return SECFailure;
372 attributes.bInheritHandle = (shared ? TRUE : FALSE);
373 hMutex = CreateMutex(&attributes, FALSE, NULL);
374 if (hMutex == NULL) {
375 hMutex = INVALID_HANDLE_VALUE;
376 nss_MD_win32_map_default_error(GetLastError());
377 return SECFailure;
379 pMutex->u.sslMutx = hMutex;
380 return SECSuccess;
383 SECStatus
384 sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
386 HANDLE hMutex;
387 int rv;
388 int retvalue = SECSuccess;
390 PR_ASSERT(pMutex != 0);
391 if (PR_FALSE == pMutex->isMultiProcess) {
392 return single_process_sslMutex_Destroy(pMutex);
395 /* multi-process mode */
396 #ifdef WINNT
397 /* on NT, get rid of the PRLock used for fibers within a process */
398 retvalue = sslMutex_2LevelDestroy(pMutex);
399 #endif
401 PR_ASSERT( pMutex->u.sslMutx != 0 &&
402 pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
403 if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0
404 || hMutex == INVALID_HANDLE_VALUE) {
405 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
406 return SECFailure;
409 rv = CloseHandle(hMutex); /* ignore error */
410 if (!processLocal && rv) {
411 pMutex->u.sslMutx = hMutex = INVALID_HANDLE_VALUE;
413 if (!rv) {
414 nss_MD_win32_map_default_error(GetLastError());
415 retvalue = SECFailure;
417 return retvalue;
420 int
421 sslMutex_Unlock(sslMutex *pMutex)
423 BOOL success = FALSE;
424 HANDLE hMutex;
426 PR_ASSERT(pMutex != 0 );
427 if (PR_FALSE == pMutex->isMultiProcess) {
428 return single_process_sslMutex_Unlock(pMutex);
431 PR_ASSERT(pMutex->u.sslMutx != 0 &&
432 pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
433 if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 ||
434 hMutex == INVALID_HANDLE_VALUE) {
435 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
436 return SECFailure;
438 success = ReleaseMutex(hMutex);
439 if (!success) {
440 nss_MD_win32_map_default_error(GetLastError());
441 return SECFailure;
443 #ifdef WINNT
444 return single_process_sslMutex_Unlock(pMutex);
445 /* release PRLock for other fibers in the process */
446 #else
447 return SECSuccess;
448 #endif
451 int
452 sslMutex_Lock(sslMutex *pMutex)
454 HANDLE hMutex;
455 DWORD event;
456 DWORD lastError;
457 SECStatus rv;
458 SECStatus retvalue = SECSuccess;
459 PR_ASSERT(pMutex != 0);
461 if (PR_FALSE == pMutex->isMultiProcess) {
462 return single_process_sslMutex_Lock(pMutex);
464 #ifdef WINNT
465 /* lock first to preserve from other threads/fibers
466 in the same process */
467 retvalue = single_process_sslMutex_Lock(pMutex);
468 #endif
469 PR_ASSERT(pMutex->u.sslMutx != 0 &&
470 pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
471 if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 ||
472 hMutex == INVALID_HANDLE_VALUE) {
473 PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
474 return SECFailure; /* what else ? */
476 /* acquire the mutex to be the only owner accross all other processes */
477 event = WaitForSingleObject(hMutex, INFINITE);
478 switch (event) {
479 case WAIT_OBJECT_0:
480 case WAIT_ABANDONED:
481 rv = SECSuccess;
482 break;
484 case WAIT_TIMEOUT:
485 #if defined(WAIT_IO_COMPLETION)
486 case WAIT_IO_COMPLETION:
487 #endif
488 default: /* should never happen. nothing we can do. */
489 PR_ASSERT(!("WaitForSingleObject returned invalid value."));
490 PORT_SetError(PR_UNKNOWN_ERROR);
491 rv = SECFailure;
492 break;
494 case WAIT_FAILED: /* failure returns this */
495 rv = SECFailure;
496 lastError = GetLastError(); /* for debugging */
497 nss_MD_win32_map_default_error(lastError);
498 break;
501 if (! (SECSuccess == retvalue && SECSuccess == rv)) {
502 return SECFailure;
505 return SECSuccess;
508 #elif defined(XP_UNIX)
510 #include <errno.h>
511 #include "unix_err.h"
513 SECStatus
514 sslMutex_Init(sslMutex *pMutex, int shared)
516 int rv;
517 PR_ASSERT(pMutex);
518 pMutex->isMultiProcess = (PRBool)(shared != 0);
519 if (!shared) {
520 return single_process_sslMutex_Init(pMutex);
522 do {
523 rv = sem_init(&pMutex->u.sem, shared, 1);
524 } while (rv < 0 && errno == EINTR);
525 if (rv < 0) {
526 nss_MD_unix_map_default_error(errno);
527 return SECFailure;
529 return SECSuccess;
532 SECStatus
533 sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
535 int rv;
536 if (PR_FALSE == pMutex->isMultiProcess) {
537 return single_process_sslMutex_Destroy(pMutex);
540 /* semaphores are global resources. See SEM_DESTROY(3) man page */
541 if (processLocal) {
542 return SECSuccess;
544 do {
545 rv = sem_destroy(&pMutex->u.sem);
546 } while (rv < 0 && errno == EINTR);
547 if (rv < 0) {
548 nss_MD_unix_map_default_error(errno);
549 return SECFailure;
551 return SECSuccess;
554 SECStatus
555 sslMutex_Unlock(sslMutex *pMutex)
557 int rv;
558 if (PR_FALSE == pMutex->isMultiProcess) {
559 return single_process_sslMutex_Unlock(pMutex);
561 do {
562 rv = sem_post(&pMutex->u.sem);
563 } while (rv < 0 && errno == EINTR);
564 if (rv < 0) {
565 nss_MD_unix_map_default_error(errno);
566 return SECFailure;
568 return SECSuccess;
571 SECStatus
572 sslMutex_Lock(sslMutex *pMutex)
574 int rv;
575 if (PR_FALSE == pMutex->isMultiProcess) {
576 return single_process_sslMutex_Lock(pMutex);
578 do {
579 rv = sem_wait(&pMutex->u.sem);
580 } while (rv < 0 && errno == EINTR);
581 if (rv < 0) {
582 nss_MD_unix_map_default_error(errno);
583 return SECFailure;
585 return SECSuccess;
588 #else
590 SECStatus
591 sslMutex_Init(sslMutex *pMutex, int shared)
593 PR_ASSERT(pMutex);
594 pMutex->isMultiProcess = (PRBool)(shared != 0);
595 if (!shared) {
596 return single_process_sslMutex_Init(pMutex);
598 PORT_Assert(!("sslMutex_Init not implemented for multi-process applications !"));
599 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
600 return SECFailure;
603 SECStatus
604 sslMutex_Destroy(sslMutex *pMutex, PRBool processLocal)
606 PR_ASSERT(pMutex);
607 if (PR_FALSE == pMutex->isMultiProcess) {
608 return single_process_sslMutex_Destroy(pMutex);
610 PORT_Assert(!("sslMutex_Destroy not implemented for multi-process applications !"));
611 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
612 return SECFailure;
615 SECStatus
616 sslMutex_Unlock(sslMutex *pMutex)
618 PR_ASSERT(pMutex);
619 if (PR_FALSE == pMutex->isMultiProcess) {
620 return single_process_sslMutex_Unlock(pMutex);
622 PORT_Assert(!("sslMutex_Unlock not implemented for multi-process applications !"));
623 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
624 return SECFailure;
627 SECStatus
628 sslMutex_Lock(sslMutex *pMutex)
630 PR_ASSERT(pMutex);
631 if (PR_FALSE == pMutex->isMultiProcess) {
632 return single_process_sslMutex_Lock(pMutex);
634 PORT_Assert(!("sslMutex_Lock not implemented for multi-process applications !"));
635 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
636 return SECFailure;
639 #endif
641 #endif