Home | History | Annotate | Download | only in ssl
      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 
     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 
     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 
     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 
     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
    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
    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
    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
    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
    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
    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
    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 
    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 
    362 static SECStatus sslMutex_2LevelDestroy(sslMutex *sem)
    363 {
    364     return single_process_sslMutex_Destroy(sem);
    365 }
    366 
    367 #endif
    368 
    369 SECStatus
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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