1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/pthreads/ptsynch.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1240 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 +** File: ptsynch.c 1.11 +** Descritpion: Implemenation for thread synchronization using pthreads 1.12 +** Exports: prlock.h, prcvar.h, prmon.h, prcmon.h 1.13 +*/ 1.14 + 1.15 +#if defined(_PR_PTHREADS) 1.16 + 1.17 +#include "primpl.h" 1.18 +#include "obsolete/prsem.h" 1.19 + 1.20 +#include <string.h> 1.21 +#include <pthread.h> 1.22 +#include <sys/time.h> 1.23 + 1.24 +static pthread_mutexattr_t _pt_mattr; 1.25 +static pthread_condattr_t _pt_cvar_attr; 1.26 + 1.27 +#if defined(DEBUG) 1.28 +extern PTDebug pt_debug; /* this is shared between several modules */ 1.29 + 1.30 +#if defined(_PR_DCETHREADS) 1.31 +static pthread_t pt_zero_tid; /* a null pthread_t (pthread_t is a struct 1.32 + * in DCE threads) to compare with */ 1.33 +#endif /* defined(_PR_DCETHREADS) */ 1.34 +#endif /* defined(DEBUG) */ 1.35 + 1.36 +#if defined(FREEBSD) 1.37 +/* 1.38 + * On older versions of FreeBSD, pthread_mutex_trylock returns EDEADLK. 1.39 + * Newer versions return EBUSY. We still need to support both. 1.40 + */ 1.41 +static int 1.42 +pt_pthread_mutex_is_locked(pthread_mutex_t *m) 1.43 +{ 1.44 + int rv = pthread_mutex_trylock(m); 1.45 + return (EBUSY == rv || EDEADLK == rv); 1.46 +} 1.47 +#endif 1.48 + 1.49 +/**************************************************************/ 1.50 +/**************************************************************/ 1.51 +/*****************************LOCKS****************************/ 1.52 +/**************************************************************/ 1.53 +/**************************************************************/ 1.54 + 1.55 +void _PR_InitLocks(void) 1.56 +{ 1.57 + int rv; 1.58 + rv = _PT_PTHREAD_MUTEXATTR_INIT(&_pt_mattr); 1.59 + PR_ASSERT(0 == rv); 1.60 + 1.61 +#ifdef LINUX 1.62 +#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) 1.63 + rv = pthread_mutexattr_settype(&_pt_mattr, PTHREAD_MUTEX_ADAPTIVE_NP); 1.64 + PR_ASSERT(0 == rv); 1.65 +#endif 1.66 +#endif 1.67 + 1.68 + rv = _PT_PTHREAD_CONDATTR_INIT(&_pt_cvar_attr); 1.69 + PR_ASSERT(0 == rv); 1.70 +} 1.71 + 1.72 +static void pt_PostNotifies(PRLock *lock, PRBool unlock) 1.73 +{ 1.74 + PRIntn index, rv; 1.75 + _PT_Notified post; 1.76 + _PT_Notified *notified, *prev = NULL; 1.77 + /* 1.78 + * Time to actually notify any conditions that were affected 1.79 + * while the lock was held. Get a copy of the list that's in 1.80 + * the lock structure and then zero the original. If it's 1.81 + * linked to other such structures, we own that storage. 1.82 + */ 1.83 + post = lock->notified; /* a safe copy; we own the lock */ 1.84 + 1.85 +#if defined(DEBUG) 1.86 + memset(&lock->notified, 0, sizeof(_PT_Notified)); /* reset */ 1.87 +#else 1.88 + lock->notified.length = 0; /* these are really sufficient */ 1.89 + lock->notified.link = NULL; 1.90 +#endif 1.91 + 1.92 + /* should (may) we release lock before notifying? */ 1.93 + if (unlock) 1.94 + { 1.95 + rv = pthread_mutex_unlock(&lock->mutex); 1.96 + PR_ASSERT(0 == rv); 1.97 + } 1.98 + 1.99 + notified = &post; /* this is where we start */ 1.100 + do 1.101 + { 1.102 + for (index = 0; index < notified->length; ++index) 1.103 + { 1.104 + PRCondVar *cv = notified->cv[index].cv; 1.105 + PR_ASSERT(NULL != cv); 1.106 + PR_ASSERT(0 != notified->cv[index].times); 1.107 + if (-1 == notified->cv[index].times) 1.108 + { 1.109 + rv = pthread_cond_broadcast(&cv->cv); 1.110 + PR_ASSERT(0 == rv); 1.111 + } 1.112 + else 1.113 + { 1.114 + while (notified->cv[index].times-- > 0) 1.115 + { 1.116 + rv = pthread_cond_signal(&cv->cv); 1.117 + PR_ASSERT(0 == rv); 1.118 + } 1.119 + } 1.120 +#if defined(DEBUG) 1.121 + pt_debug.cvars_notified += 1; 1.122 + if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending)) 1.123 + { 1.124 + pt_debug.delayed_cv_deletes += 1; 1.125 + PR_DestroyCondVar(cv); 1.126 + } 1.127 +#else /* defined(DEBUG) */ 1.128 + if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending)) 1.129 + PR_DestroyCondVar(cv); 1.130 +#endif /* defined(DEBUG) */ 1.131 + } 1.132 + prev = notified; 1.133 + notified = notified->link; 1.134 + if (&post != prev) PR_DELETE(prev); 1.135 + } while (NULL != notified); 1.136 +} /* pt_PostNotifies */ 1.137 + 1.138 +PR_IMPLEMENT(PRLock*) PR_NewLock(void) 1.139 +{ 1.140 + PRIntn rv; 1.141 + PRLock *lock; 1.142 + 1.143 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.144 + 1.145 + lock = PR_NEWZAP(PRLock); 1.146 + if (lock != NULL) 1.147 + { 1.148 + rv = _PT_PTHREAD_MUTEX_INIT(lock->mutex, _pt_mattr); 1.149 + PR_ASSERT(0 == rv); 1.150 + } 1.151 +#if defined(DEBUG) 1.152 + pt_debug.locks_created += 1; 1.153 +#endif 1.154 + return lock; 1.155 +} /* PR_NewLock */ 1.156 + 1.157 +PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock) 1.158 +{ 1.159 + PRIntn rv; 1.160 + PR_ASSERT(NULL != lock); 1.161 + PR_ASSERT(PR_FALSE == lock->locked); 1.162 + PR_ASSERT(0 == lock->notified.length); 1.163 + PR_ASSERT(NULL == lock->notified.link); 1.164 + rv = pthread_mutex_destroy(&lock->mutex); 1.165 + PR_ASSERT(0 == rv); 1.166 +#if defined(DEBUG) 1.167 + memset(lock, 0xaf, sizeof(PRLock)); 1.168 + pt_debug.locks_destroyed += 1; 1.169 +#endif 1.170 + PR_Free(lock); 1.171 +} /* PR_DestroyLock */ 1.172 + 1.173 +PR_IMPLEMENT(void) PR_Lock(PRLock *lock) 1.174 +{ 1.175 + /* Nb: PR_Lock must not call PR_GetCurrentThread to access the |id| or 1.176 + * |tid| field of the current thread's PRThread structure because 1.177 + * _pt_root calls PR_Lock before setting thred->id and thred->tid. */ 1.178 + PRIntn rv; 1.179 + PR_ASSERT(lock != NULL); 1.180 + rv = pthread_mutex_lock(&lock->mutex); 1.181 + PR_ASSERT(0 == rv); 1.182 + PR_ASSERT(0 == lock->notified.length); 1.183 + PR_ASSERT(NULL == lock->notified.link); 1.184 + PR_ASSERT(PR_FALSE == lock->locked); 1.185 + /* Nb: the order of the next two statements is not critical to 1.186 + * the correctness of PR_AssertCurrentThreadOwnsLock(), but 1.187 + * this particular order makes the assertion more likely to 1.188 + * catch errors. */ 1.189 + lock->owner = pthread_self(); 1.190 + lock->locked = PR_TRUE; 1.191 +#if defined(DEBUG) 1.192 + pt_debug.locks_acquired += 1; 1.193 +#endif 1.194 +} /* PR_Lock */ 1.195 + 1.196 +PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock) 1.197 +{ 1.198 + pthread_t self = pthread_self(); 1.199 + PRIntn rv; 1.200 + 1.201 + PR_ASSERT(lock != NULL); 1.202 + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock->mutex)); 1.203 + PR_ASSERT(PR_TRUE == lock->locked); 1.204 + PR_ASSERT(pthread_equal(lock->owner, self)); 1.205 + 1.206 + if (!lock->locked || !pthread_equal(lock->owner, self)) 1.207 + return PR_FAILURE; 1.208 + 1.209 + lock->locked = PR_FALSE; 1.210 + if (0 == lock->notified.length) /* shortcut */ 1.211 + { 1.212 + rv = pthread_mutex_unlock(&lock->mutex); 1.213 + PR_ASSERT(0 == rv); 1.214 + } 1.215 + else pt_PostNotifies(lock, PR_TRUE); 1.216 + 1.217 +#if defined(DEBUG) 1.218 + pt_debug.locks_released += 1; 1.219 +#endif 1.220 + return PR_SUCCESS; 1.221 +} /* PR_Unlock */ 1.222 + 1.223 +PR_IMPLEMENT(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock) 1.224 +{ 1.225 + /* Nb: the order of the |locked| and |owner==me| checks is not critical 1.226 + * to the correctness of PR_AssertCurrentThreadOwnsLock(), but 1.227 + * this particular order makes the assertion more likely to 1.228 + * catch errors. */ 1.229 + PR_ASSERT(lock->locked && pthread_equal(lock->owner, pthread_self())); 1.230 +} 1.231 + 1.232 +/**************************************************************/ 1.233 +/**************************************************************/ 1.234 +/***************************CONDITIONS*************************/ 1.235 +/**************************************************************/ 1.236 +/**************************************************************/ 1.237 + 1.238 + 1.239 +/* 1.240 + * This code is used to compute the absolute time for the wakeup. 1.241 + * It's moderately ugly, so it's defined here and called in a 1.242 + * couple of places. 1.243 + */ 1.244 +#define PT_NANOPERMICRO 1000UL 1.245 +#define PT_BILLION 1000000000UL 1.246 + 1.247 +static PRIntn pt_TimedWait( 1.248 + pthread_cond_t *cv, pthread_mutex_t *ml, PRIntervalTime timeout) 1.249 +{ 1.250 + int rv; 1.251 + struct timeval now; 1.252 + struct timespec tmo; 1.253 + PRUint32 ticks = PR_TicksPerSecond(); 1.254 + 1.255 + tmo.tv_sec = (PRInt32)(timeout / ticks); 1.256 + tmo.tv_nsec = (PRInt32)(timeout - (tmo.tv_sec * ticks)); 1.257 + tmo.tv_nsec = (PRInt32)PR_IntervalToMicroseconds(PT_NANOPERMICRO * tmo.tv_nsec); 1.258 + 1.259 + /* pthreads wants this in absolute time, off we go ... */ 1.260 + (void)GETTIMEOFDAY(&now); 1.261 + /* that one's usecs, this one's nsecs - grrrr! */ 1.262 + tmo.tv_sec += now.tv_sec; 1.263 + tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec); 1.264 + tmo.tv_sec += tmo.tv_nsec / PT_BILLION; 1.265 + tmo.tv_nsec %= PT_BILLION; 1.266 + 1.267 + rv = pthread_cond_timedwait(cv, ml, &tmo); 1.268 + 1.269 + /* NSPR doesn't report timeouts */ 1.270 +#ifdef _PR_DCETHREADS 1.271 + if (rv == -1) return (errno == EAGAIN) ? 0 : errno; 1.272 + else return rv; 1.273 +#else 1.274 + return (rv == ETIMEDOUT) ? 0 : rv; 1.275 +#endif 1.276 +} /* pt_TimedWait */ 1.277 + 1.278 + 1.279 +/* 1.280 + * Notifies just get posted to the protecting mutex. The 1.281 + * actual notification is done when the lock is released so that 1.282 + * MP systems don't contend for a lock that they can't have. 1.283 + */ 1.284 +static void pt_PostNotifyToCvar(PRCondVar *cvar, PRBool broadcast) 1.285 +{ 1.286 + PRIntn index = 0; 1.287 + _PT_Notified *notified = &cvar->lock->notified; 1.288 + 1.289 + PR_ASSERT(PR_TRUE == cvar->lock->locked); 1.290 + PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); 1.291 + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex)); 1.292 + 1.293 + while (1) 1.294 + { 1.295 + for (index = 0; index < notified->length; ++index) 1.296 + { 1.297 + if (notified->cv[index].cv == cvar) 1.298 + { 1.299 + if (broadcast) 1.300 + notified->cv[index].times = -1; 1.301 + else if (-1 != notified->cv[index].times) 1.302 + notified->cv[index].times += 1; 1.303 + return; /* we're finished */ 1.304 + } 1.305 + } 1.306 + /* if not full, enter new CV in this array */ 1.307 + if (notified->length < PT_CV_NOTIFIED_LENGTH) break; 1.308 + 1.309 + /* if there's no link, create an empty array and link it */ 1.310 + if (NULL == notified->link) 1.311 + notified->link = PR_NEWZAP(_PT_Notified); 1.312 + notified = notified->link; 1.313 + } 1.314 + 1.315 + /* A brand new entry in the array */ 1.316 + (void)PR_ATOMIC_INCREMENT(&cvar->notify_pending); 1.317 + notified->cv[index].times = (broadcast) ? -1 : 1; 1.318 + notified->cv[index].cv = cvar; 1.319 + notified->length += 1; 1.320 +} /* pt_PostNotifyToCvar */ 1.321 + 1.322 +PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock) 1.323 +{ 1.324 + PRCondVar *cv = PR_NEW(PRCondVar); 1.325 + PR_ASSERT(lock != NULL); 1.326 + if (cv != NULL) 1.327 + { 1.328 + int rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); 1.329 + PR_ASSERT(0 == rv); 1.330 + cv->lock = lock; 1.331 + cv->notify_pending = 0; 1.332 +#if defined(DEBUG) 1.333 + pt_debug.cvars_created += 1; 1.334 +#endif 1.335 + } 1.336 + return cv; 1.337 +} /* PR_NewCondVar */ 1.338 + 1.339 +PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar) 1.340 +{ 1.341 + if (0 > PR_ATOMIC_DECREMENT(&cvar->notify_pending)) 1.342 + { 1.343 + PRIntn rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv); 1.344 +#if defined(DEBUG) 1.345 + memset(cvar, 0xaf, sizeof(PRCondVar)); 1.346 + pt_debug.cvars_destroyed += 1; 1.347 +#endif 1.348 + PR_Free(cvar); 1.349 + } 1.350 +} /* PR_DestroyCondVar */ 1.351 + 1.352 +PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout) 1.353 +{ 1.354 + PRIntn rv; 1.355 + PRThread *thred = PR_GetCurrentThread(); 1.356 + 1.357 + PR_ASSERT(cvar != NULL); 1.358 + /* We'd better be locked */ 1.359 + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex)); 1.360 + PR_ASSERT(PR_TRUE == cvar->lock->locked); 1.361 + /* and it better be by us */ 1.362 + PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); 1.363 + 1.364 + if (_PT_THREAD_INTERRUPTED(thred)) goto aborted; 1.365 + 1.366 + /* 1.367 + * The thread waiting is used for PR_Interrupt 1.368 + */ 1.369 + thred->waiting = cvar; /* this is where we're waiting */ 1.370 + 1.371 + /* 1.372 + * If we have pending notifies, post them now. 1.373 + * 1.374 + * This is not optimal. We're going to post these notifies 1.375 + * while we're holding the lock. That means on MP systems 1.376 + * that they are going to collide for the lock that we will 1.377 + * hold until we actually wait. 1.378 + */ 1.379 + if (0 != cvar->lock->notified.length) 1.380 + pt_PostNotifies(cvar->lock, PR_FALSE); 1.381 + 1.382 + /* 1.383 + * We're surrendering the lock, so clear out the locked field. 1.384 + */ 1.385 + cvar->lock->locked = PR_FALSE; 1.386 + 1.387 + if (timeout == PR_INTERVAL_NO_TIMEOUT) 1.388 + rv = pthread_cond_wait(&cvar->cv, &cvar->lock->mutex); 1.389 + else 1.390 + rv = pt_TimedWait(&cvar->cv, &cvar->lock->mutex, timeout); 1.391 + 1.392 + /* We just got the lock back - this better be empty */ 1.393 + PR_ASSERT(PR_FALSE == cvar->lock->locked); 1.394 + cvar->lock->locked = PR_TRUE; 1.395 + cvar->lock->owner = pthread_self(); 1.396 + 1.397 + PR_ASSERT(0 == cvar->lock->notified.length); 1.398 + thred->waiting = NULL; /* and now we're not */ 1.399 + if (_PT_THREAD_INTERRUPTED(thred)) goto aborted; 1.400 + if (rv != 0) 1.401 + { 1.402 + _PR_MD_MAP_DEFAULT_ERROR(rv); 1.403 + return PR_FAILURE; 1.404 + } 1.405 + return PR_SUCCESS; 1.406 + 1.407 +aborted: 1.408 + PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); 1.409 + thred->state &= ~PT_THREAD_ABORTED; 1.410 + return PR_FAILURE; 1.411 +} /* PR_WaitCondVar */ 1.412 + 1.413 +PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar) 1.414 +{ 1.415 + PR_ASSERT(cvar != NULL); 1.416 + pt_PostNotifyToCvar(cvar, PR_FALSE); 1.417 + return PR_SUCCESS; 1.418 +} /* PR_NotifyCondVar */ 1.419 + 1.420 +PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar) 1.421 +{ 1.422 + PR_ASSERT(cvar != NULL); 1.423 + pt_PostNotifyToCvar(cvar, PR_TRUE); 1.424 + return PR_SUCCESS; 1.425 +} /* PR_NotifyAllCondVar */ 1.426 + 1.427 +/**************************************************************/ 1.428 +/**************************************************************/ 1.429 +/***************************MONITORS***************************/ 1.430 +/**************************************************************/ 1.431 +/**************************************************************/ 1.432 + 1.433 +/* 1.434 + * Notifies just get posted to the monitor. The actual notification is done 1.435 + * when the monitor is fully exited so that MP systems don't contend for a 1.436 + * monitor that they can't enter. 1.437 + */ 1.438 +static void pt_PostNotifyToMonitor(PRMonitor *mon, PRBool broadcast) 1.439 +{ 1.440 + PR_ASSERT(NULL != mon); 1.441 + PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mon); 1.442 + 1.443 + /* mon->notifyTimes is protected by the monitor, so we don't need to 1.444 + * acquire mon->lock. 1.445 + */ 1.446 + if (broadcast) 1.447 + mon->notifyTimes = -1; 1.448 + else if (-1 != mon->notifyTimes) 1.449 + mon->notifyTimes += 1; 1.450 +} /* pt_PostNotifyToMonitor */ 1.451 + 1.452 +static void pt_PostNotifiesFromMonitor(pthread_cond_t *cv, PRIntn times) 1.453 +{ 1.454 + PRIntn rv; 1.455 + 1.456 + /* 1.457 + * Time to actually notify any waits that were affected while the monitor 1.458 + * was entered. 1.459 + */ 1.460 + PR_ASSERT(NULL != cv); 1.461 + PR_ASSERT(0 != times); 1.462 + if (-1 == times) 1.463 + { 1.464 + rv = pthread_cond_broadcast(cv); 1.465 + PR_ASSERT(0 == rv); 1.466 + } 1.467 + else 1.468 + { 1.469 + while (times-- > 0) 1.470 + { 1.471 + rv = pthread_cond_signal(cv); 1.472 + PR_ASSERT(0 == rv); 1.473 + } 1.474 + } 1.475 +} /* pt_PostNotifiesFromMonitor */ 1.476 + 1.477 +PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void) 1.478 +{ 1.479 + PRMonitor *mon; 1.480 + int rv; 1.481 + 1.482 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.483 + 1.484 + mon = PR_NEWZAP(PRMonitor); 1.485 + if (mon == NULL) 1.486 + { 1.487 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.488 + return NULL; 1.489 + } 1.490 + 1.491 + rv = _PT_PTHREAD_MUTEX_INIT(mon->lock, _pt_mattr); 1.492 + PR_ASSERT(0 == rv); 1.493 + if (0 != rv) 1.494 + goto error1; 1.495 + 1.496 + _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); 1.497 + 1.498 + rv = _PT_PTHREAD_COND_INIT(mon->entryCV, _pt_cvar_attr); 1.499 + PR_ASSERT(0 == rv); 1.500 + if (0 != rv) 1.501 + goto error2; 1.502 + 1.503 + rv = _PT_PTHREAD_COND_INIT(mon->waitCV, _pt_cvar_attr); 1.504 + PR_ASSERT(0 == rv); 1.505 + if (0 != rv) 1.506 + goto error3; 1.507 + 1.508 + mon->notifyTimes = 0; 1.509 + mon->entryCount = 0; 1.510 + mon->refCount = 1; 1.511 + mon->name = NULL; 1.512 + return mon; 1.513 + 1.514 +error3: 1.515 + pthread_cond_destroy(&mon->entryCV); 1.516 +error2: 1.517 + pthread_mutex_destroy(&mon->lock); 1.518 +error1: 1.519 + PR_Free(mon); 1.520 + _PR_MD_MAP_DEFAULT_ERROR(rv); 1.521 + return NULL; 1.522 +} /* PR_NewMonitor */ 1.523 + 1.524 +PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) 1.525 +{ 1.526 + PRMonitor* mon = PR_NewMonitor(); 1.527 + if (mon) 1.528 + mon->name = name; 1.529 + return mon; 1.530 +} 1.531 + 1.532 +PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon) 1.533 +{ 1.534 + int rv; 1.535 + 1.536 + PR_ASSERT(mon != NULL); 1.537 + if (PR_ATOMIC_DECREMENT(&mon->refCount) == 0) 1.538 + { 1.539 + rv = pthread_cond_destroy(&mon->waitCV); PR_ASSERT(0 == rv); 1.540 + rv = pthread_cond_destroy(&mon->entryCV); PR_ASSERT(0 == rv); 1.541 + rv = pthread_mutex_destroy(&mon->lock); PR_ASSERT(0 == rv); 1.542 +#if defined(DEBUG) 1.543 + memset(mon, 0xaf, sizeof(PRMonitor)); 1.544 +#endif 1.545 + PR_Free(mon); 1.546 + } 1.547 +} /* PR_DestroyMonitor */ 1.548 + 1.549 +/* The GC uses this; it is quite arguably a bad interface. I'm just 1.550 + * duplicating it for now - XXXMB 1.551 + */ 1.552 +PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon) 1.553 +{ 1.554 + pthread_t self = pthread_self(); 1.555 + PRIntn rv; 1.556 + PRIntn count = 0; 1.557 + 1.558 + rv = pthread_mutex_lock(&mon->lock); 1.559 + PR_ASSERT(0 == rv); 1.560 + if (pthread_equal(mon->owner, self)) 1.561 + count = mon->entryCount; 1.562 + rv = pthread_mutex_unlock(&mon->lock); 1.563 + PR_ASSERT(0 == rv); 1.564 + return count; 1.565 +} 1.566 + 1.567 +PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon) 1.568 +{ 1.569 +#if defined(DEBUG) || defined(FORCE_PR_ASSERT) 1.570 + PRIntn rv; 1.571 + 1.572 + rv = pthread_mutex_lock(&mon->lock); 1.573 + PR_ASSERT(0 == rv); 1.574 + PR_ASSERT(mon->entryCount != 0 && 1.575 + pthread_equal(mon->owner, pthread_self())); 1.576 + rv = pthread_mutex_unlock(&mon->lock); 1.577 + PR_ASSERT(0 == rv); 1.578 +#endif 1.579 +} 1.580 + 1.581 +PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon) 1.582 +{ 1.583 + pthread_t self = pthread_self(); 1.584 + PRIntn rv; 1.585 + 1.586 + PR_ASSERT(mon != NULL); 1.587 + rv = pthread_mutex_lock(&mon->lock); 1.588 + PR_ASSERT(0 == rv); 1.589 + if (mon->entryCount != 0) 1.590 + { 1.591 + if (pthread_equal(mon->owner, self)) 1.592 + goto done; 1.593 + while (mon->entryCount != 0) 1.594 + { 1.595 + rv = pthread_cond_wait(&mon->entryCV, &mon->lock); 1.596 + PR_ASSERT(0 == rv); 1.597 + } 1.598 + } 1.599 + /* and now I have the monitor */ 1.600 + PR_ASSERT(0 == mon->notifyTimes); 1.601 + PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner)); 1.602 + _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner); 1.603 + 1.604 +done: 1.605 + mon->entryCount += 1; 1.606 + rv = pthread_mutex_unlock(&mon->lock); 1.607 + PR_ASSERT(0 == rv); 1.608 +} /* PR_EnterMonitor */ 1.609 + 1.610 +PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon) 1.611 +{ 1.612 + pthread_t self = pthread_self(); 1.613 + PRIntn rv; 1.614 + PRBool notifyEntryWaiter = PR_FALSE; 1.615 + PRIntn notifyTimes = 0; 1.616 + 1.617 + PR_ASSERT(mon != NULL); 1.618 + rv = pthread_mutex_lock(&mon->lock); 1.619 + PR_ASSERT(0 == rv); 1.620 + /* the entries should be > 0 and we'd better be the owner */ 1.621 + PR_ASSERT(mon->entryCount > 0); 1.622 + PR_ASSERT(pthread_equal(mon->owner, self)); 1.623 + if (mon->entryCount == 0 || !pthread_equal(mon->owner, self)) 1.624 + { 1.625 + rv = pthread_mutex_unlock(&mon->lock); 1.626 + PR_ASSERT(0 == rv); 1.627 + return PR_FAILURE; 1.628 + } 1.629 + 1.630 + mon->entryCount -= 1; /* reduce by one */ 1.631 + if (mon->entryCount == 0) 1.632 + { 1.633 + /* and if it transitioned to zero - notify an entry waiter */ 1.634 + /* make the owner unknown */ 1.635 + _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); 1.636 + notifyEntryWaiter = PR_TRUE; 1.637 + notifyTimes = mon->notifyTimes; 1.638 + mon->notifyTimes = 0; 1.639 + /* We will access the members of 'mon' after unlocking mon->lock. 1.640 + * Add a reference. */ 1.641 + PR_ATOMIC_INCREMENT(&mon->refCount); 1.642 + } 1.643 + rv = pthread_mutex_unlock(&mon->lock); 1.644 + PR_ASSERT(0 == rv); 1.645 + if (notifyEntryWaiter) 1.646 + { 1.647 + if (notifyTimes) 1.648 + pt_PostNotifiesFromMonitor(&mon->waitCV, notifyTimes); 1.649 + rv = pthread_cond_signal(&mon->entryCV); 1.650 + PR_ASSERT(0 == rv); 1.651 + /* We are done accessing the members of 'mon'. Release the 1.652 + * reference. */ 1.653 + PR_DestroyMonitor(mon); 1.654 + } 1.655 + return PR_SUCCESS; 1.656 +} /* PR_ExitMonitor */ 1.657 + 1.658 +PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout) 1.659 +{ 1.660 + PRStatus rv; 1.661 + PRUint32 saved_entries; 1.662 + pthread_t saved_owner; 1.663 + 1.664 + PR_ASSERT(mon != NULL); 1.665 + rv = pthread_mutex_lock(&mon->lock); 1.666 + PR_ASSERT(0 == rv); 1.667 + /* the entries better be positive */ 1.668 + PR_ASSERT(mon->entryCount > 0); 1.669 + /* and it better be owned by us */ 1.670 + PR_ASSERT(pthread_equal(mon->owner, pthread_self())); 1.671 + 1.672 + /* tuck these away 'till later */ 1.673 + saved_entries = mon->entryCount; 1.674 + mon->entryCount = 0; 1.675 + _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner); 1.676 + _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); 1.677 + /* 1.678 + * If we have pending notifies, post them now. 1.679 + * 1.680 + * This is not optimal. We're going to post these notifies 1.681 + * while we're holding the lock. That means on MP systems 1.682 + * that they are going to collide for the lock that we will 1.683 + * hold until we actually wait. 1.684 + */ 1.685 + if (0 != mon->notifyTimes) 1.686 + { 1.687 + pt_PostNotifiesFromMonitor(&mon->waitCV, mon->notifyTimes); 1.688 + mon->notifyTimes = 0; 1.689 + } 1.690 + rv = pthread_cond_signal(&mon->entryCV); 1.691 + PR_ASSERT(0 == rv); 1.692 + 1.693 + if (timeout == PR_INTERVAL_NO_TIMEOUT) 1.694 + rv = pthread_cond_wait(&mon->waitCV, &mon->lock); 1.695 + else 1.696 + rv = pt_TimedWait(&mon->waitCV, &mon->lock, timeout); 1.697 + PR_ASSERT(0 == rv); 1.698 + 1.699 + while (mon->entryCount != 0) 1.700 + { 1.701 + rv = pthread_cond_wait(&mon->entryCV, &mon->lock); 1.702 + PR_ASSERT(0 == rv); 1.703 + } 1.704 + PR_ASSERT(0 == mon->notifyTimes); 1.705 + /* reinstate the interesting information */ 1.706 + mon->entryCount = saved_entries; 1.707 + _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner); 1.708 + 1.709 + rv = pthread_mutex_unlock(&mon->lock); 1.710 + PR_ASSERT(0 == rv); 1.711 + return rv; 1.712 +} /* PR_Wait */ 1.713 + 1.714 +PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon) 1.715 +{ 1.716 + pt_PostNotifyToMonitor(mon, PR_FALSE); 1.717 + return PR_SUCCESS; 1.718 +} /* PR_Notify */ 1.719 + 1.720 +PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon) 1.721 +{ 1.722 + pt_PostNotifyToMonitor(mon, PR_TRUE); 1.723 + return PR_SUCCESS; 1.724 +} /* PR_NotifyAll */ 1.725 + 1.726 +/**************************************************************/ 1.727 +/**************************************************************/ 1.728 +/**************************SEMAPHORES**************************/ 1.729 +/**************************************************************/ 1.730 +/**************************************************************/ 1.731 +PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore) 1.732 +{ 1.733 + static PRBool unwarned = PR_TRUE; 1.734 + if (unwarned) unwarned = _PR_Obsolete( 1.735 + "PR_PostSem", "locks & condition variables"); 1.736 + PR_Lock(semaphore->cvar->lock); 1.737 + PR_NotifyCondVar(semaphore->cvar); 1.738 + semaphore->count += 1; 1.739 + PR_Unlock(semaphore->cvar->lock); 1.740 +} /* PR_PostSem */ 1.741 + 1.742 +PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *semaphore) 1.743 +{ 1.744 + PRStatus status = PR_SUCCESS; 1.745 + static PRBool unwarned = PR_TRUE; 1.746 + if (unwarned) unwarned = _PR_Obsolete( 1.747 + "PR_WaitSem", "locks & condition variables"); 1.748 + PR_Lock(semaphore->cvar->lock); 1.749 + while ((semaphore->count == 0) && (PR_SUCCESS == status)) 1.750 + status = PR_WaitCondVar(semaphore->cvar, PR_INTERVAL_NO_TIMEOUT); 1.751 + if (PR_SUCCESS == status) semaphore->count -= 1; 1.752 + PR_Unlock(semaphore->cvar->lock); 1.753 + return status; 1.754 +} /* PR_WaitSem */ 1.755 + 1.756 +PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *semaphore) 1.757 +{ 1.758 + static PRBool unwarned = PR_TRUE; 1.759 + if (unwarned) unwarned = _PR_Obsolete( 1.760 + "PR_DestroySem", "locks & condition variables"); 1.761 + PR_DestroyLock(semaphore->cvar->lock); 1.762 + PR_DestroyCondVar(semaphore->cvar); 1.763 + PR_Free(semaphore); 1.764 +} /* PR_DestroySem */ 1.765 + 1.766 +PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value) 1.767 +{ 1.768 + PRSemaphore *semaphore; 1.769 + static PRBool unwarned = PR_TRUE; 1.770 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.771 + 1.772 + if (unwarned) unwarned = _PR_Obsolete( 1.773 + "PR_NewSem", "locks & condition variables"); 1.774 + 1.775 + semaphore = PR_NEWZAP(PRSemaphore); 1.776 + if (NULL != semaphore) 1.777 + { 1.778 + PRLock *lock = PR_NewLock(); 1.779 + if (NULL != lock) 1.780 + { 1.781 + semaphore->cvar = PR_NewCondVar(lock); 1.782 + if (NULL != semaphore->cvar) 1.783 + { 1.784 + semaphore->count = value; 1.785 + return semaphore; 1.786 + } 1.787 + PR_DestroyLock(lock); 1.788 + } 1.789 + PR_Free(semaphore); 1.790 + } 1.791 + return NULL; 1.792 +} 1.793 + 1.794 +/* 1.795 + * Define the interprocess named semaphore functions. 1.796 + * There are three implementations: 1.797 + * 1. POSIX semaphore based; 1.798 + * 2. System V semaphore based; 1.799 + * 3. unsupported (fails with PR_NOT_IMPLEMENTED_ERROR). 1.800 + */ 1.801 + 1.802 +#ifdef _PR_HAVE_POSIX_SEMAPHORES 1.803 +#include <fcntl.h> 1.804 + 1.805 +PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( 1.806 + const char *name, 1.807 + PRIntn flags, 1.808 + PRIntn mode, 1.809 + PRUintn value) 1.810 +{ 1.811 + PRSem *sem; 1.812 + char osname[PR_IPC_NAME_SIZE]; 1.813 + 1.814 + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) 1.815 + == PR_FAILURE) 1.816 + { 1.817 + return NULL; 1.818 + } 1.819 + 1.820 + sem = PR_NEW(PRSem); 1.821 + if (NULL == sem) 1.822 + { 1.823 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.824 + return NULL; 1.825 + } 1.826 + 1.827 + if (flags & PR_SEM_CREATE) 1.828 + { 1.829 + int oflag = O_CREAT; 1.830 + 1.831 + if (flags & PR_SEM_EXCL) oflag |= O_EXCL; 1.832 + sem->sem = sem_open(osname, oflag, mode, value); 1.833 + } 1.834 + else 1.835 + { 1.836 +#ifdef HPUX 1.837 + /* Pass 0 as the mode and value arguments to work around a bug. */ 1.838 + sem->sem = sem_open(osname, 0, 0, 0); 1.839 +#else 1.840 + sem->sem = sem_open(osname, 0); 1.841 +#endif 1.842 + } 1.843 + if ((sem_t *) -1 == sem->sem) 1.844 + { 1.845 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.846 + PR_Free(sem); 1.847 + return NULL; 1.848 + } 1.849 + return sem; 1.850 +} 1.851 + 1.852 +PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) 1.853 +{ 1.854 + int rv; 1.855 + rv = sem_wait(sem->sem); 1.856 + if (0 != rv) 1.857 + { 1.858 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.859 + return PR_FAILURE; 1.860 + } 1.861 + return PR_SUCCESS; 1.862 +} 1.863 + 1.864 +PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) 1.865 +{ 1.866 + int rv; 1.867 + rv = sem_post(sem->sem); 1.868 + if (0 != rv) 1.869 + { 1.870 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.871 + return PR_FAILURE; 1.872 + } 1.873 + return PR_SUCCESS; 1.874 +} 1.875 + 1.876 +PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) 1.877 +{ 1.878 + int rv; 1.879 + rv = sem_close(sem->sem); 1.880 + if (0 != rv) 1.881 + { 1.882 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.883 + return PR_FAILURE; 1.884 + } 1.885 + PR_Free(sem); 1.886 + return PR_SUCCESS; 1.887 +} 1.888 + 1.889 +PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) 1.890 +{ 1.891 + int rv; 1.892 + char osname[PR_IPC_NAME_SIZE]; 1.893 + 1.894 + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) 1.895 + == PR_FAILURE) 1.896 + { 1.897 + return PR_FAILURE; 1.898 + } 1.899 + rv = sem_unlink(osname); 1.900 + if (0 != rv) 1.901 + { 1.902 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.903 + return PR_FAILURE; 1.904 + } 1.905 + return PR_SUCCESS; 1.906 +} 1.907 + 1.908 +#elif defined(_PR_HAVE_SYSV_SEMAPHORES) 1.909 + 1.910 +#include <fcntl.h> 1.911 +#include <sys/sem.h> 1.912 + 1.913 +/* 1.914 + * From the semctl(2) man page in glibc 2.0 1.915 + */ 1.916 +#if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) \ 1.917 + || defined(FREEBSD) || defined(OPENBSD) || defined(BSDI) \ 1.918 + || defined(DARWIN) || defined(SYMBIAN) 1.919 +/* union semun is defined by including <sys/sem.h> */ 1.920 +#else 1.921 +/* according to X/OPEN we have to define it ourselves */ 1.922 +union semun { 1.923 + int val; 1.924 + struct semid_ds *buf; 1.925 + unsigned short *array; 1.926 +}; 1.927 +#endif 1.928 + 1.929 +/* 1.930 + * 'a' (97) is the final closing price of NSCP stock. 1.931 + */ 1.932 +#define NSPR_IPC_KEY_ID 'a' /* the id argument for ftok() */ 1.933 + 1.934 +#define NSPR_SEM_MODE 0666 1.935 + 1.936 +PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( 1.937 + const char *name, 1.938 + PRIntn flags, 1.939 + PRIntn mode, 1.940 + PRUintn value) 1.941 +{ 1.942 + PRSem *sem; 1.943 + key_t key; 1.944 + union semun arg; 1.945 + struct sembuf sop; 1.946 + struct semid_ds seminfo; 1.947 +#define MAX_TRIES 60 1.948 + PRIntn i; 1.949 + char osname[PR_IPC_NAME_SIZE]; 1.950 + 1.951 + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) 1.952 + == PR_FAILURE) 1.953 + { 1.954 + return NULL; 1.955 + } 1.956 + 1.957 + /* Make sure the file exists before calling ftok. */ 1.958 + if (flags & PR_SEM_CREATE) 1.959 + { 1.960 + int osfd = open(osname, O_RDWR|O_CREAT, mode); 1.961 + if (-1 == osfd) 1.962 + { 1.963 + _PR_MD_MAP_OPEN_ERROR(errno); 1.964 + return NULL; 1.965 + } 1.966 + if (close(osfd) == -1) 1.967 + { 1.968 + _PR_MD_MAP_CLOSE_ERROR(errno); 1.969 + return NULL; 1.970 + } 1.971 + } 1.972 + key = ftok(osname, NSPR_IPC_KEY_ID); 1.973 + if ((key_t)-1 == key) 1.974 + { 1.975 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.976 + return NULL; 1.977 + } 1.978 + 1.979 + sem = PR_NEW(PRSem); 1.980 + if (NULL == sem) 1.981 + { 1.982 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.983 + return NULL; 1.984 + } 1.985 + 1.986 + if (flags & PR_SEM_CREATE) 1.987 + { 1.988 + sem->semid = semget(key, 1, mode|IPC_CREAT|IPC_EXCL); 1.989 + if (sem->semid >= 0) 1.990 + { 1.991 + /* creator of a semaphore is responsible for initializing it */ 1.992 + arg.val = 0; 1.993 + if (semctl(sem->semid, 0, SETVAL, arg) == -1) 1.994 + { 1.995 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.996 + PR_Free(sem); 1.997 + return NULL; 1.998 + } 1.999 + /* call semop to set sem_otime to nonzero */ 1.1000 + sop.sem_num = 0; 1.1001 + sop.sem_op = value; 1.1002 + sop.sem_flg = 0; 1.1003 + if (semop(sem->semid, &sop, 1) == -1) 1.1004 + { 1.1005 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.1006 + PR_Free(sem); 1.1007 + return NULL; 1.1008 + } 1.1009 + return sem; 1.1010 + } 1.1011 + 1.1012 + if (errno != EEXIST || flags & PR_SEM_EXCL) 1.1013 + { 1.1014 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.1015 + PR_Free(sem); 1.1016 + return NULL; 1.1017 + } 1.1018 + } 1.1019 + 1.1020 + sem->semid = semget(key, 1, NSPR_SEM_MODE); 1.1021 + if (sem->semid == -1) 1.1022 + { 1.1023 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.1024 + PR_Free(sem); 1.1025 + return NULL; 1.1026 + } 1.1027 + for (i = 0; i < MAX_TRIES; i++) 1.1028 + { 1.1029 + arg.buf = &seminfo; 1.1030 + semctl(sem->semid, 0, IPC_STAT, arg); 1.1031 + if (seminfo.sem_otime != 0) break; 1.1032 + sleep(1); 1.1033 + } 1.1034 + if (i == MAX_TRIES) 1.1035 + { 1.1036 + PR_SetError(PR_IO_TIMEOUT_ERROR, 0); 1.1037 + PR_Free(sem); 1.1038 + return NULL; 1.1039 + } 1.1040 + return sem; 1.1041 +} 1.1042 + 1.1043 +PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) 1.1044 +{ 1.1045 + struct sembuf sop; 1.1046 + 1.1047 + sop.sem_num = 0; 1.1048 + sop.sem_op = -1; 1.1049 + sop.sem_flg = 0; 1.1050 + if (semop(sem->semid, &sop, 1) == -1) 1.1051 + { 1.1052 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.1053 + return PR_FAILURE; 1.1054 + } 1.1055 + return PR_SUCCESS; 1.1056 +} 1.1057 + 1.1058 +PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) 1.1059 +{ 1.1060 + struct sembuf sop; 1.1061 + 1.1062 + sop.sem_num = 0; 1.1063 + sop.sem_op = 1; 1.1064 + sop.sem_flg = 0; 1.1065 + if (semop(sem->semid, &sop, 1) == -1) 1.1066 + { 1.1067 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.1068 + return PR_FAILURE; 1.1069 + } 1.1070 + return PR_SUCCESS; 1.1071 +} 1.1072 + 1.1073 +PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) 1.1074 +{ 1.1075 + PR_Free(sem); 1.1076 + return PR_SUCCESS; 1.1077 +} 1.1078 + 1.1079 +PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) 1.1080 +{ 1.1081 + key_t key; 1.1082 + int semid; 1.1083 + /* On some systems (e.g., glibc 2.0) semctl requires a fourth argument */ 1.1084 + union semun unused; 1.1085 + char osname[PR_IPC_NAME_SIZE]; 1.1086 + 1.1087 + if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) 1.1088 + == PR_FAILURE) 1.1089 + { 1.1090 + return PR_FAILURE; 1.1091 + } 1.1092 + key = ftok(osname, NSPR_IPC_KEY_ID); 1.1093 + if ((key_t) -1 == key) 1.1094 + { 1.1095 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.1096 + return PR_FAILURE; 1.1097 + } 1.1098 + if (unlink(osname) == -1) 1.1099 + { 1.1100 + _PR_MD_MAP_UNLINK_ERROR(errno); 1.1101 + return PR_FAILURE; 1.1102 + } 1.1103 + semid = semget(key, 1, NSPR_SEM_MODE); 1.1104 + if (-1 == semid) 1.1105 + { 1.1106 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.1107 + return PR_FAILURE; 1.1108 + } 1.1109 + unused.val = 0; 1.1110 + if (semctl(semid, 0, IPC_RMID, unused) == -1) 1.1111 + { 1.1112 + _PR_MD_MAP_DEFAULT_ERROR(errno); 1.1113 + return PR_FAILURE; 1.1114 + } 1.1115 + return PR_SUCCESS; 1.1116 +} 1.1117 + 1.1118 +#else /* neither POSIX nor System V semaphores are available */ 1.1119 + 1.1120 +PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( 1.1121 + const char *name, 1.1122 + PRIntn flags, 1.1123 + PRIntn mode, 1.1124 + PRUintn value) 1.1125 +{ 1.1126 + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 1.1127 + return NULL; 1.1128 +} 1.1129 + 1.1130 +PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) 1.1131 +{ 1.1132 + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 1.1133 + return PR_FAILURE; 1.1134 +} 1.1135 + 1.1136 +PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) 1.1137 +{ 1.1138 + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 1.1139 + return PR_FAILURE; 1.1140 +} 1.1141 + 1.1142 +PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) 1.1143 +{ 1.1144 + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 1.1145 + return PR_FAILURE; 1.1146 +} 1.1147 + 1.1148 +PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) 1.1149 +{ 1.1150 + PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 1.1151 + return PR_FAILURE; 1.1152 +} 1.1153 + 1.1154 +#endif /* end of interprocess named semaphore functions */ 1.1155 + 1.1156 +/**************************************************************/ 1.1157 +/**************************************************************/ 1.1158 +/******************ROUTINES FOR DCE EMULATION******************/ 1.1159 +/**************************************************************/ 1.1160 +/**************************************************************/ 1.1161 + 1.1162 +#include "prpdce.h" 1.1163 + 1.1164 +PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock) 1.1165 +{ 1.1166 + PRIntn rv = pthread_mutex_trylock(&lock->mutex); 1.1167 + if (rv == PT_TRYLOCK_SUCCESS) 1.1168 + { 1.1169 + PR_ASSERT(PR_FALSE == lock->locked); 1.1170 + lock->locked = PR_TRUE; 1.1171 + lock->owner = pthread_self(); 1.1172 + } 1.1173 + /* XXX set error code? */ 1.1174 + return (PT_TRYLOCK_SUCCESS == rv) ? PR_SUCCESS : PR_FAILURE; 1.1175 +} /* PRP_TryLock */ 1.1176 + 1.1177 +PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void) 1.1178 +{ 1.1179 + PRCondVar *cv; 1.1180 + 1.1181 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.1182 + 1.1183 + cv = PR_NEW(PRCondVar); 1.1184 + if (cv != NULL) 1.1185 + { 1.1186 + int rv; 1.1187 + rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); 1.1188 + PR_ASSERT(0 == rv); 1.1189 + cv->lock = _PR_NAKED_CV_LOCK; 1.1190 + } 1.1191 + return cv; 1.1192 +} /* PRP_NewNakedCondVar */ 1.1193 + 1.1194 +PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar) 1.1195 +{ 1.1196 + int rv; 1.1197 + rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv); 1.1198 +#if defined(DEBUG) 1.1199 + memset(cvar, 0xaf, sizeof(PRCondVar)); 1.1200 +#endif 1.1201 + PR_Free(cvar); 1.1202 +} /* PRP_DestroyNakedCondVar */ 1.1203 + 1.1204 +PR_IMPLEMENT(PRStatus) PRP_NakedWait( 1.1205 + PRCondVar *cvar, PRLock *ml, PRIntervalTime timeout) 1.1206 +{ 1.1207 + PRIntn rv; 1.1208 + PR_ASSERT(cvar != NULL); 1.1209 + /* XXX do we really want to assert this in a naked wait? */ 1.1210 + PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(ml->mutex)); 1.1211 + if (timeout == PR_INTERVAL_NO_TIMEOUT) 1.1212 + rv = pthread_cond_wait(&cvar->cv, &ml->mutex); 1.1213 + else 1.1214 + rv = pt_TimedWait(&cvar->cv, &ml->mutex, timeout); 1.1215 + if (rv != 0) 1.1216 + { 1.1217 + _PR_MD_MAP_DEFAULT_ERROR(rv); 1.1218 + return PR_FAILURE; 1.1219 + } 1.1220 + return PR_SUCCESS; 1.1221 +} /* PRP_NakedWait */ 1.1222 + 1.1223 +PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar) 1.1224 +{ 1.1225 + int rv; 1.1226 + PR_ASSERT(cvar != NULL); 1.1227 + rv = pthread_cond_signal(&cvar->cv); 1.1228 + PR_ASSERT(0 == rv); 1.1229 + return PR_SUCCESS; 1.1230 +} /* PRP_NakedNotify */ 1.1231 + 1.1232 +PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar) 1.1233 +{ 1.1234 + int rv; 1.1235 + PR_ASSERT(cvar != NULL); 1.1236 + rv = pthread_cond_broadcast(&cvar->cv); 1.1237 + PR_ASSERT(0 == rv); 1.1238 + return PR_SUCCESS; 1.1239 +} /* PRP_NakedBroadcast */ 1.1240 + 1.1241 +#endif /* defined(_PR_PTHREADS) */ 1.1242 + 1.1243 +/* ptsynch.c */