• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is the Netscape security libraries.
15  *
16  * The Initial Developer of the Original Code is
17  * Netscape Communications Corporation.
18  * Portions created by the Initial Developer are Copyright (C) 2001
19  * the Initial Developer. All Rights Reserved.
20  *
21  * Contributor(s):
22  *
23  * Alternatively, the contents of this file may be used under the terms of
24  * either the GNU General Public License Version 2 or later (the "GPL"), or
25  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26  * in which case the provisions of the GPL or the LGPL are applicable instead
27  * of those above. If you wish to allow use of your version of this file only
28  * under the terms of either the GPL or the LGPL, and not to allow others to
29  * use your version of this file under the terms of the MPL, indicate your
30  * decision by deleting the provisions above and replace them with the notice
31  * and other provisions required by the GPL or the LGPL. If you do not delete
32  * the provisions above, a recipient may use your version of this file under
33  * the terms of any one of the MPL, the GPL or the LGPL.
34  *
35  * ***** END LICENSE BLOCK ***** */
36 /* $Id: sslmutex.c,v 1.24 2009/06/05 02:34:14 nelson%bolyard.com Exp $ */
37 
38 #include "seccomon.h"
39 /* This ifdef should match the one in sslsnce.c */
40 #if defined(XP_UNIX) || defined(XP_WIN32) || defined (XP_OS2) || defined(XP_BEOS)
41 
42 #include "sslmutex.h"
43 #include "prerr.h"
44 
single_process_sslMutex_Init(sslMutex * pMutex)45 static SECStatus single_process_sslMutex_Init(sslMutex* pMutex)
46 {
47     PR_ASSERT(pMutex != 0 && pMutex->u.sslLock == 0 );
48 
49     pMutex->u.sslLock = PR_NewLock();
50     if (!pMutex->u.sslLock) {
51         return SECFailure;
52     }
53     return SECSuccess;
54 }
55 
single_process_sslMutex_Destroy(sslMutex * pMutex)56 static SECStatus single_process_sslMutex_Destroy(sslMutex* pMutex)
57 {
58     PR_ASSERT(pMutex != 0);
59     PR_ASSERT(pMutex->u.sslLock!= 0);
60     if (!pMutex->u.sslLock) {
61         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
62         return SECFailure;
63     }
64     PR_DestroyLock(pMutex->u.sslLock);
65     return SECSuccess;
66 }
67 
single_process_sslMutex_Unlock(sslMutex * pMutex)68 static SECStatus single_process_sslMutex_Unlock(sslMutex* pMutex)
69 {
70     PR_ASSERT(pMutex != 0 );
71     PR_ASSERT(pMutex->u.sslLock !=0);
72     if (!pMutex->u.sslLock) {
73         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
74         return SECFailure;
75     }
76     PR_Unlock(pMutex->u.sslLock);
77     return SECSuccess;
78 }
79 
single_process_sslMutex_Lock(sslMutex * pMutex)80 static SECStatus single_process_sslMutex_Lock(sslMutex* pMutex)
81 {
82     PR_ASSERT(pMutex != 0);
83     PR_ASSERT(pMutex->u.sslLock != 0 );
84     if (!pMutex->u.sslLock) {
85         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
86         return SECFailure;
87     }
88     PR_Lock(pMutex->u.sslLock);
89     return SECSuccess;
90 }
91 
92 #if defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD)
93 
94 #include <unistd.h>
95 #include <fcntl.h>
96 #include <string.h>
97 #include <errno.h>
98 #include "unix_err.h"
99 #include "pratom.h"
100 
101 #define SSL_MUTEX_MAGIC 0xfeedfd
102 #define NONBLOCKING_POSTS 1	/* maybe this is faster */
103 
104 #if NONBLOCKING_POSTS
105 
106 #ifndef FNONBLOCK
107 #define FNONBLOCK O_NONBLOCK
108 #endif
109 
110 static int
setNonBlocking(int fd,int nonBlocking)111 setNonBlocking(int fd, int nonBlocking)
112 {
113     int flags;
114     int err;
115 
116     flags = fcntl(fd, F_GETFL, 0);
117     if (0 > flags)
118 	return flags;
119     if (nonBlocking)
120 	flags |= FNONBLOCK;
121     else
122 	flags &= ~FNONBLOCK;
123     err = fcntl(fd, F_SETFL, flags);
124     return err;
125 }
126 #endif
127 
128 SECStatus
sslMutex_Init(sslMutex * pMutex,int shared)129 sslMutex_Init(sslMutex *pMutex, int shared)
130 {
131     int  err;
132     PR_ASSERT(pMutex);
133     pMutex->isMultiProcess = (PRBool)(shared != 0);
134     if (!shared) {
135         return single_process_sslMutex_Init(pMutex);
136     }
137     pMutex->u.pipeStr.mPipes[0] = -1;
138     pMutex->u.pipeStr.mPipes[1] = -1;
139     pMutex->u.pipeStr.mPipes[2] = -1;
140     pMutex->u.pipeStr.nWaiters  =  0;
141 
142     err = pipe(pMutex->u.pipeStr.mPipes);
143     if (err) {
144 	nss_MD_unix_map_default_error(errno);
145 	return err;
146     }
147 #if NONBLOCKING_POSTS
148     err = setNonBlocking(pMutex->u.pipeStr.mPipes[1], 1);
149     if (err)
150 	goto loser;
151 #endif
152 
153     pMutex->u.pipeStr.mPipes[2] = SSL_MUTEX_MAGIC;
154 
155 #if defined(LINUX) && defined(i386)
156     /* Pipe starts out empty */
157     return SECSuccess;
158 #else
159     /* Pipe starts with one byte. */
160     return sslMutex_Unlock(pMutex);
161 #endif
162 
163 loser:
164     nss_MD_unix_map_default_error(errno);
165     close(pMutex->u.pipeStr.mPipes[0]);
166     close(pMutex->u.pipeStr.mPipes[1]);
167     return SECFailure;
168 }
169 
170 SECStatus
sslMutex_Destroy(sslMutex * pMutex)171 sslMutex_Destroy(sslMutex *pMutex)
172 {
173     if (PR_FALSE == pMutex->isMultiProcess) {
174         return single_process_sslMutex_Destroy(pMutex);
175     }
176     if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
177 	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
178 	return SECFailure;
179     }
180     close(pMutex->u.pipeStr.mPipes[0]);
181     close(pMutex->u.pipeStr.mPipes[1]);
182 
183     pMutex->u.pipeStr.mPipes[0] = -1;
184     pMutex->u.pipeStr.mPipes[1] = -1;
185     pMutex->u.pipeStr.mPipes[2] = -1;
186     pMutex->u.pipeStr.nWaiters  =  0;
187 
188     return SECSuccess;
189 }
190 
191 #if defined(LINUX) && defined(i386)
192 /* No memory barrier needed for this platform */
193 
194 /* nWaiters includes the holder of the lock (if any) and the number
195 ** threads waiting for it.  After incrementing nWaiters, if the count
196 ** is exactly 1, then you have the lock and may proceed.  If the
197 ** count is greater than 1, then you must wait on the pipe.
198 */
199 
200 
201 SECStatus
sslMutex_Unlock(sslMutex * pMutex)202 sslMutex_Unlock(sslMutex *pMutex)
203 {
204     PRInt32 newValue;
205     if (PR_FALSE == pMutex->isMultiProcess) {
206         return single_process_sslMutex_Unlock(pMutex);
207     }
208 
209     if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
210 	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
211 	return SECFailure;
212     }
213     /* Do Memory Barrier here. */
214     newValue = PR_AtomicDecrement(&pMutex->u.pipeStr.nWaiters);
215     if (newValue > 0) {
216 	int  cc;
217 	char c  = 1;
218 	do {
219 	    cc = write(pMutex->u.pipeStr.mPipes[1], &c, 1);
220 	} while (cc < 0 && (errno == EINTR || errno == EAGAIN));
221 	if (cc != 1) {
222 	    if (cc < 0)
223 		nss_MD_unix_map_default_error(errno);
224 	    else
225 		PORT_SetError(PR_UNKNOWN_ERROR);
226 	    return SECFailure;
227 	}
228     }
229     return SECSuccess;
230 }
231 
232 SECStatus
sslMutex_Lock(sslMutex * pMutex)233 sslMutex_Lock(sslMutex *pMutex)
234 {
235     PRInt32 newValue;
236     if (PR_FALSE == pMutex->isMultiProcess) {
237         return single_process_sslMutex_Lock(pMutex);
238     }
239 
240     if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
241 	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
242 	return SECFailure;
243     }
244     newValue = PR_AtomicIncrement(&pMutex->u.pipeStr.nWaiters);
245     /* Do Memory Barrier here. */
246     if (newValue > 1) {
247 	int   cc;
248 	char  c;
249 	do {
250 	    cc = read(pMutex->u.pipeStr.mPipes[0], &c, 1);
251 	} while (cc < 0 && errno == EINTR);
252 	if (cc != 1) {
253 	    if (cc < 0)
254 		nss_MD_unix_map_default_error(errno);
255 	    else
256 		PORT_SetError(PR_UNKNOWN_ERROR);
257 	    return SECFailure;
258 	}
259     }
260     return SECSuccess;
261 }
262 
263 #else
264 
265 /* Using Atomic operations requires the use of a memory barrier instruction
266 ** on PowerPC, Sparc, and Alpha.  NSPR's PR_Atomic functions do not perform
267 ** them, and NSPR does not provide a function that does them (e.g. PR_Barrier).
268 ** So, we don't use them on those platforms.
269 */
270 
271 SECStatus
sslMutex_Unlock(sslMutex * pMutex)272 sslMutex_Unlock(sslMutex *pMutex)
273 {
274     int  cc;
275     char c  = 1;
276 
277     if (PR_FALSE == pMutex->isMultiProcess) {
278         return single_process_sslMutex_Unlock(pMutex);
279     }
280 
281     if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
282 	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
283 	return SECFailure;
284     }
285     do {
286 	cc = write(pMutex->u.pipeStr.mPipes[1], &c, 1);
287     } while (cc < 0 && (errno == EINTR || errno == EAGAIN));
288     if (cc != 1) {
289 	if (cc < 0)
290 	    nss_MD_unix_map_default_error(errno);
291 	else
292 	    PORT_SetError(PR_UNKNOWN_ERROR);
293 	return SECFailure;
294     }
295 
296     return SECSuccess;
297 }
298 
299 SECStatus
sslMutex_Lock(sslMutex * pMutex)300 sslMutex_Lock(sslMutex *pMutex)
301 {
302     int   cc;
303     char  c;
304 
305     if (PR_FALSE == pMutex->isMultiProcess) {
306         return single_process_sslMutex_Lock(pMutex);
307     }
308 
309     if (pMutex->u.pipeStr.mPipes[2] != SSL_MUTEX_MAGIC) {
310 	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
311 	return SECFailure;
312     }
313 
314     do {
315 	cc = read(pMutex->u.pipeStr.mPipes[0], &c, 1);
316     } while (cc < 0 && errno == EINTR);
317     if (cc != 1) {
318 	if (cc < 0)
319 	    nss_MD_unix_map_default_error(errno);
320 	else
321 	    PORT_SetError(PR_UNKNOWN_ERROR);
322 	return SECFailure;
323     }
324 
325     return SECSuccess;
326 }
327 
328 #endif
329 
330 #elif defined(WIN32)
331 
332 #include "win32err.h"
333 
334 /* on Windows, we need to find the optimal type of locking mechanism to use
335  for the sslMutex.
336 
337  There are 3 cases :
338  1) single-process, use a PRLock, as for all other platforms
339  2) Win95 multi-process, use a Win32 mutex
340  3) on WINNT multi-process, use a PRLock + a Win32 mutex
341 
342 */
343 
344 #ifdef WINNT
345 
sslMutex_2LevelInit(sslMutex * sem)346 SECStatus sslMutex_2LevelInit(sslMutex *sem)
347 {
348     /*  the following adds a PRLock to sslMutex . This is done in each
349         process of a multi-process server and is only needed on WINNT, if
350         using fibers. We can't tell if native threads or fibers are used, so
351         we always do it on WINNT
352     */
353     PR_ASSERT(sem);
354     if (sem) {
355         /* we need to reset the sslLock in the children or the single_process init
356            function below will assert */
357         sem->u.sslLock = NULL;
358     }
359     return single_process_sslMutex_Init(sem);
360 }
361 
sslMutex_2LevelDestroy(sslMutex * sem)362 static SECStatus sslMutex_2LevelDestroy(sslMutex *sem)
363 {
364     return single_process_sslMutex_Destroy(sem);
365 }
366 
367 #endif
368 
369 SECStatus
sslMutex_Init(sslMutex * pMutex,int shared)370 sslMutex_Init(sslMutex *pMutex, int shared)
371 {
372 #ifdef WINNT
373     SECStatus retvalue;
374 #endif
375     HANDLE hMutex;
376     SECURITY_ATTRIBUTES attributes =
377                                 { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
378 
379     PR_ASSERT(pMutex != 0 && (pMutex->u.sslMutx == 0 ||
380               pMutex->u.sslMutx == INVALID_HANDLE_VALUE) );
381 
382     pMutex->isMultiProcess = (PRBool)(shared != 0);
383 
384     if (PR_FALSE == pMutex->isMultiProcess) {
385         return single_process_sslMutex_Init(pMutex);
386     }
387 
388 #ifdef WINNT
389     /*  we need a lock on WINNT for fibers in the parent process */
390     retvalue = sslMutex_2LevelInit(pMutex);
391     if (SECSuccess != retvalue)
392         return SECFailure;
393 #endif
394 
395     if (!pMutex || ((hMutex = pMutex->u.sslMutx) != 0 &&
396         hMutex != INVALID_HANDLE_VALUE)) {
397         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
398         return SECFailure;
399     }
400     attributes.bInheritHandle = (shared ? TRUE : FALSE);
401     hMutex = CreateMutex(&attributes, FALSE, NULL);
402     if (hMutex == NULL) {
403         hMutex = INVALID_HANDLE_VALUE;
404         nss_MD_win32_map_default_error(GetLastError());
405         return SECFailure;
406     }
407     pMutex->u.sslMutx = hMutex;
408     return SECSuccess;
409 }
410 
411 SECStatus
sslMutex_Destroy(sslMutex * pMutex)412 sslMutex_Destroy(sslMutex *pMutex)
413 {
414     HANDLE hMutex;
415     int    rv;
416     int retvalue = SECSuccess;
417 
418     PR_ASSERT(pMutex != 0);
419     if (PR_FALSE == pMutex->isMultiProcess) {
420         return single_process_sslMutex_Destroy(pMutex);
421     }
422 
423     /*  multi-process mode */
424 #ifdef WINNT
425     /* on NT, get rid of the PRLock used for fibers within a process */
426     retvalue = sslMutex_2LevelDestroy(pMutex);
427 #endif
428 
429     PR_ASSERT( pMutex->u.sslMutx != 0 &&
430                pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
431     if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0
432         || hMutex == INVALID_HANDLE_VALUE) {
433         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
434         return SECFailure;
435     }
436 
437     rv = CloseHandle(hMutex); /* ignore error */
438     if (rv) {
439         pMutex->u.sslMutx = hMutex = INVALID_HANDLE_VALUE;
440     } else {
441         nss_MD_win32_map_default_error(GetLastError());
442         retvalue = SECFailure;
443     }
444     return retvalue;
445 }
446 
447 int
sslMutex_Unlock(sslMutex * pMutex)448 sslMutex_Unlock(sslMutex *pMutex)
449 {
450     BOOL   success = FALSE;
451     HANDLE hMutex;
452 
453     PR_ASSERT(pMutex != 0 );
454     if (PR_FALSE == pMutex->isMultiProcess) {
455         return single_process_sslMutex_Unlock(pMutex);
456     }
457 
458     PR_ASSERT(pMutex->u.sslMutx != 0 &&
459               pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
460     if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 ||
461         hMutex == INVALID_HANDLE_VALUE) {
462         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
463         return SECFailure;
464     }
465     success = ReleaseMutex(hMutex);
466     if (!success) {
467         nss_MD_win32_map_default_error(GetLastError());
468         return SECFailure;
469     }
470 #ifdef WINNT
471     return single_process_sslMutex_Unlock(pMutex);
472     /* release PRLock for other fibers in the process */
473 #else
474     return SECSuccess;
475 #endif
476 }
477 
478 int
sslMutex_Lock(sslMutex * pMutex)479 sslMutex_Lock(sslMutex *pMutex)
480 {
481     HANDLE    hMutex;
482     DWORD     event;
483     DWORD     lastError;
484     SECStatus rv;
485     SECStatus retvalue = SECSuccess;
486     PR_ASSERT(pMutex != 0);
487 
488     if (PR_FALSE == pMutex->isMultiProcess) {
489         return single_process_sslMutex_Lock(pMutex);
490     }
491 #ifdef WINNT
492     /* lock first to preserve from other threads/fibers
493        in the same process */
494     retvalue = single_process_sslMutex_Lock(pMutex);
495 #endif
496     PR_ASSERT(pMutex->u.sslMutx != 0 &&
497               pMutex->u.sslMutx != INVALID_HANDLE_VALUE);
498     if (!pMutex || (hMutex = pMutex->u.sslMutx) == 0 ||
499         hMutex == INVALID_HANDLE_VALUE) {
500         PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
501         return SECFailure;      /* what else ? */
502     }
503     /* acquire the mutex to be the only owner accross all other processes */
504     event = WaitForSingleObject(hMutex, INFINITE);
505     switch (event) {
506     case WAIT_OBJECT_0:
507     case WAIT_ABANDONED:
508         rv = SECSuccess;
509         break;
510 
511     case WAIT_TIMEOUT:
512 #if defined(WAIT_IO_COMPLETION)
513     case WAIT_IO_COMPLETION:
514 #endif
515     default:            /* should never happen. nothing we can do. */
516         PR_ASSERT(!("WaitForSingleObject returned invalid value."));
517 	PORT_SetError(PR_UNKNOWN_ERROR);
518 	rv = SECFailure;
519 	break;
520 
521     case WAIT_FAILED:           /* failure returns this */
522         rv = SECFailure;
523         lastError = GetLastError();     /* for debugging */
524         nss_MD_win32_map_default_error(lastError);
525         break;
526     }
527 
528     if (! (SECSuccess == retvalue && SECSuccess == rv)) {
529         return SECFailure;
530     }
531 
532     return SECSuccess;
533 }
534 
535 #elif defined(XP_UNIX)
536 
537 #include <errno.h>
538 #include "unix_err.h"
539 
540 SECStatus
sslMutex_Init(sslMutex * pMutex,int shared)541 sslMutex_Init(sslMutex *pMutex, int shared)
542 {
543     int rv;
544     PR_ASSERT(pMutex);
545     pMutex->isMultiProcess = (PRBool)(shared != 0);
546     if (!shared) {
547         return single_process_sslMutex_Init(pMutex);
548     }
549     do {
550         rv = sem_init(&pMutex->u.sem, shared, 1);
551     } while (rv < 0 && errno == EINTR);
552     if (rv < 0) {
553         nss_MD_unix_map_default_error(errno);
554         return SECFailure;
555     }
556     return SECSuccess;
557 }
558 
559 SECStatus
sslMutex_Destroy(sslMutex * pMutex)560 sslMutex_Destroy(sslMutex *pMutex)
561 {
562     int rv;
563     if (PR_FALSE == pMutex->isMultiProcess) {
564         return single_process_sslMutex_Destroy(pMutex);
565     }
566     do {
567 	rv = sem_destroy(&pMutex->u.sem);
568     } while (rv < 0 && errno == EINTR);
569     if (rv < 0) {
570 	nss_MD_unix_map_default_error(errno);
571 	return SECFailure;
572     }
573     return SECSuccess;
574 }
575 
576 SECStatus
sslMutex_Unlock(sslMutex * pMutex)577 sslMutex_Unlock(sslMutex *pMutex)
578 {
579     int rv;
580     if (PR_FALSE == pMutex->isMultiProcess) {
581         return single_process_sslMutex_Unlock(pMutex);
582     }
583     do {
584 	rv = sem_post(&pMutex->u.sem);
585     } while (rv < 0 && errno == EINTR);
586     if (rv < 0) {
587 	nss_MD_unix_map_default_error(errno);
588 	return SECFailure;
589     }
590     return SECSuccess;
591 }
592 
593 SECStatus
sslMutex_Lock(sslMutex * pMutex)594 sslMutex_Lock(sslMutex *pMutex)
595 {
596     int rv;
597     if (PR_FALSE == pMutex->isMultiProcess) {
598         return single_process_sslMutex_Lock(pMutex);
599     }
600     do {
601 	rv = sem_wait(&pMutex->u.sem);
602     } while (rv < 0 && errno == EINTR);
603     if (rv < 0) {
604 	nss_MD_unix_map_default_error(errno);
605 	return SECFailure;
606     }
607     return SECSuccess;
608 }
609 
610 #else
611 
612 SECStatus
sslMutex_Init(sslMutex * pMutex,int shared)613 sslMutex_Init(sslMutex *pMutex, int shared)
614 {
615     PR_ASSERT(pMutex);
616     pMutex->isMultiProcess = (PRBool)(shared != 0);
617     if (!shared) {
618         return single_process_sslMutex_Init(pMutex);
619     }
620     PORT_Assert(!("sslMutex_Init not implemented for multi-process applications !"));
621     PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
622     return SECFailure;
623 }
624 
625 SECStatus
sslMutex_Destroy(sslMutex * pMutex)626 sslMutex_Destroy(sslMutex *pMutex)
627 {
628     PR_ASSERT(pMutex);
629     if (PR_FALSE == pMutex->isMultiProcess) {
630         return single_process_sslMutex_Destroy(pMutex);
631     }
632     PORT_Assert(!("sslMutex_Destroy not implemented for multi-process applications !"));
633     PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
634     return SECFailure;
635 }
636 
637 SECStatus
sslMutex_Unlock(sslMutex * pMutex)638 sslMutex_Unlock(sslMutex *pMutex)
639 {
640     PR_ASSERT(pMutex);
641     if (PR_FALSE == pMutex->isMultiProcess) {
642         return single_process_sslMutex_Unlock(pMutex);
643     }
644     PORT_Assert(!("sslMutex_Unlock not implemented for multi-process applications !"));
645     PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
646     return SECFailure;
647 }
648 
649 SECStatus
sslMutex_Lock(sslMutex * pMutex)650 sslMutex_Lock(sslMutex *pMutex)
651 {
652     PR_ASSERT(pMutex);
653     if (PR_FALSE == pMutex->isMultiProcess) {
654         return single_process_sslMutex_Lock(pMutex);
655     }
656     PORT_Assert(!("sslMutex_Lock not implemented for multi-process applications !"));
657     PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
658     return SECFailure;
659 }
660 
661 #endif
662 
663 #endif
664