--- /dev/null
+/*
+ * Copyright (c) 2003-2006,2008,2010-2012 Apple Inc. All Rights Reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ * nsprPortX.c - minimal platform dependent NSPR functions to enable
+ * use of DER libraries
+ */
+
+#ifndef _NSPR_PORT_X_H_
+#define _NSPR_PORT_X_H_
+
+#include "prmem.h"
+#include "prlock.h"
+#include "prerror.h"
+#include "prinit.h"
+#include "prbit.h"
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+
+// MARK: *** Memory ***
+
+NSPR_API(void *) PR_Malloc(PRSize size)
+{
+ return malloc(size ? size : 1);
+}
+NSPR_API(void *) PR_Calloc(PRSize nelem, PRSize elsize)
+{
+ return calloc(nelem, elsize);
+}
+NSPR_API(void *) PR_Realloc(void *ptr, PRSize size)
+{
+ return realloc(ptr, size);
+}
+NSPR_API(void) PR_Free(void *ptr)
+{
+ return free(ptr);
+}
+
+// MARK: *** locks ***
+
+NSPR_API(PRLock*) PR_NewLock(void)
+{
+ pthread_mutex_t *pm = PR_Malloc(sizeof(pthread_mutex_t));
+ if(pm == NULL) {
+ return NULL;
+ }
+ if(pthread_mutex_init(pm, NULL)) {
+ PR_Free(pm);
+ return NULL;
+ }
+ return (PRLock*)pm;
+}
+
+NSPR_API(void) PR_DestroyLock(PRLock *lock)
+{
+ if(lock == NULL) {
+ return;
+ }
+ pthread_mutex_destroy((pthread_mutex_t *)lock);
+ PR_Free(lock);
+}
+
+NSPR_API(void) PR_Lock(PRLock *lock)
+{
+ if(lock == NULL) {
+ return;
+ }
+ pthread_mutex_lock((pthread_mutex_t *)lock);
+}
+
+NSPR_API(PRStatus) PR_Unlock(PRLock *lock)
+{
+ if(lock == NULL) {
+ return PR_FAILURE;
+ }
+ pthread_mutex_unlock((pthread_mutex_t *)lock);
+ return PR_SUCCESS;
+}
+
+// MARK: *** get/set error ***
+
+/*
+ * key for pthread_{set,get}specific and a lock to ensure it gets
+ * created once
+ */
+static pthread_key_t PR_threadKey;
+static int PR_threadKeyInitFlag; // we have a PR_threadKey
+static int PR_threadKeyErrorFlag; // unable to create PR_threadKey
+static pthread_mutex_t PR_threadKeyLock = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * The thing that gets stored on a per-thread basis. A pointer to
+ * this is associated with key PR_threadKey. Mallocd in
+ * PR_getThreadErrInfo(); freed directly by free() as
+ * PR_threadKey's destructor.
+ */
+typedef struct {
+ PRInt32 osError;
+ PRErrorCode prError;
+} PR_threadErrInfo;
+
+/*
+ * One-time init of PR_threadKey, returns nonzero on error.
+ * Does not attempt to init PR_threadKey if doCreate is false and
+ * a previous call to this routine resulted in error (i.e., this
+ * is the GetXError() following a failed SetError()).
+ */
+static PRInt32 PR_initThreadKey(
+ int doCreate)
+{
+ PRInt32 prtn = 0;
+ if(PR_threadKeyInitFlag) {
+ /* thread safe since we never clear this flag; we're ready to go */
+ return 0;
+ }
+ pthread_mutex_lock(&PR_threadKeyLock);
+ if(PR_threadKeyErrorFlag && !doCreate) {
+ /* no error to get because the last SetXError failed */
+ prtn = PR_IO_ERROR;
+ }
+ else if(!PR_threadKeyInitFlag) {
+ prtn = pthread_key_create(&PR_threadKey, free);
+ if(prtn) {
+ /* out of pthread_key_t's */
+ PR_threadKeyErrorFlag = 1;
+ }
+ else {
+ PR_threadKeyErrorFlag = 0; // in case of retry */
+ PR_threadKeyInitFlag = 1; // success
+ }
+ }
+ pthread_mutex_unlock(&PR_threadKeyLock);
+ return prtn;
+}
+
+/*
+ * Get current thread's PR_threadErrInfo. Create one if doCreate is
+ * true and one does not exist.
+ *
+ * -- A nonzero *threadKeyError on return indicates that we can
+ * not create a pthread_key_t; in this case we return NULL.
+ * -- Note that NULL return with zero threadKeyError and zero
+ * doCreate indicates "no per-thread error set yet", which is
+ * not an error.
+ */
+static PR_threadErrInfo *PR_getThreadErrInfo(
+ int doCreate,
+ PRInt32 *threadKeyError) // RETURNED, an OSStatus
+{
+ *threadKeyError = PR_initThreadKey(doCreate);
+ if(*threadKeyError) {
+ return NULL;
+ }
+ PR_threadErrInfo *errInfo = pthread_getspecific(PR_threadKey);
+ if((errInfo == NULL) && doCreate) {
+ errInfo = (PR_threadErrInfo *)malloc(sizeof(*errInfo));
+ if(errInfo == NULL) {
+ /*
+ * malloc failure, retriable failure of this routine (not
+ * a PR_threadKeyErrorFlag style error).
+ * Note that this is *not* detected in a subsequent
+ * GetXError() call, but it will allow for somewhat
+ * graceful recovery in case some memory gets freed
+ * up.
+ */
+ *threadKeyError = PR_OUT_OF_MEMORY_ERROR;
+ }
+ else {
+ memset(errInfo, 0, sizeof(*errInfo));
+ pthread_setspecific(PR_threadKey, errInfo);
+ }
+ }
+ return errInfo;
+}
+
+PR_IMPLEMENT(PRErrorCode) PR_GetError(void)
+{
+ PRInt32 prtn;
+ PR_threadErrInfo *errInfo = PR_getThreadErrInfo(0, &prtn);
+ if(errInfo == NULL) {
+ /* no error set or per-thread logic uninitialized */
+ if(prtn) {
+ return PR_INSUFFICIENT_RESOURCES_ERROR;
+ }
+ else {
+ return 0;
+ }
+ }
+ else {
+ return errInfo->prError;
+ }
+}
+
+PR_IMPLEMENT(PRInt32) PR_GetOSError(void)
+{
+ PRInt32 prtn;
+ PR_threadErrInfo *errInfo = PR_getThreadErrInfo(0, &prtn);
+ if(errInfo == NULL) {
+ /* no error set or per-thread logic uninitialized */
+ return prtn;
+ }
+ else {
+ return errInfo->osError;
+ }
+}
+
+PR_IMPLEMENT(void) PR_SetError(PRErrorCode code, PRInt32 osErr)
+{
+ PRInt32 prtn;
+ PR_threadErrInfo *errInfo = PR_getThreadErrInfo(1, &prtn);
+ if(errInfo != NULL) {
+ errInfo->osError = osErr;
+ errInfo->prError = code;
+ }
+ /* else per-thread logic uninitialized */
+}
+
+// MARK: *** misc. ***
+
+/*
+** Compute the log of the least power of 2 greater than or equal to n
+*/
+NSPR_API(PRIntn) PR_CeilingLog2(PRUint32 i)
+{
+ PRIntn r;
+ PR_CEILING_LOG2(r,i);
+ return r;
+}
+
+#endif /* _NSPR_PORT_X_H_ */