nsprpub/pr/src/pthreads/ptsynch.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /*
michael@0 7 ** File: ptsynch.c
michael@0 8 ** Descritpion: Implemenation for thread synchronization using pthreads
michael@0 9 ** Exports: prlock.h, prcvar.h, prmon.h, prcmon.h
michael@0 10 */
michael@0 11
michael@0 12 #if defined(_PR_PTHREADS)
michael@0 13
michael@0 14 #include "primpl.h"
michael@0 15 #include "obsolete/prsem.h"
michael@0 16
michael@0 17 #include <string.h>
michael@0 18 #include <pthread.h>
michael@0 19 #include <sys/time.h>
michael@0 20
michael@0 21 static pthread_mutexattr_t _pt_mattr;
michael@0 22 static pthread_condattr_t _pt_cvar_attr;
michael@0 23
michael@0 24 #if defined(DEBUG)
michael@0 25 extern PTDebug pt_debug; /* this is shared between several modules */
michael@0 26
michael@0 27 #if defined(_PR_DCETHREADS)
michael@0 28 static pthread_t pt_zero_tid; /* a null pthread_t (pthread_t is a struct
michael@0 29 * in DCE threads) to compare with */
michael@0 30 #endif /* defined(_PR_DCETHREADS) */
michael@0 31 #endif /* defined(DEBUG) */
michael@0 32
michael@0 33 #if defined(FREEBSD)
michael@0 34 /*
michael@0 35 * On older versions of FreeBSD, pthread_mutex_trylock returns EDEADLK.
michael@0 36 * Newer versions return EBUSY. We still need to support both.
michael@0 37 */
michael@0 38 static int
michael@0 39 pt_pthread_mutex_is_locked(pthread_mutex_t *m)
michael@0 40 {
michael@0 41 int rv = pthread_mutex_trylock(m);
michael@0 42 return (EBUSY == rv || EDEADLK == rv);
michael@0 43 }
michael@0 44 #endif
michael@0 45
michael@0 46 /**************************************************************/
michael@0 47 /**************************************************************/
michael@0 48 /*****************************LOCKS****************************/
michael@0 49 /**************************************************************/
michael@0 50 /**************************************************************/
michael@0 51
michael@0 52 void _PR_InitLocks(void)
michael@0 53 {
michael@0 54 int rv;
michael@0 55 rv = _PT_PTHREAD_MUTEXATTR_INIT(&_pt_mattr);
michael@0 56 PR_ASSERT(0 == rv);
michael@0 57
michael@0 58 #ifdef LINUX
michael@0 59 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)
michael@0 60 rv = pthread_mutexattr_settype(&_pt_mattr, PTHREAD_MUTEX_ADAPTIVE_NP);
michael@0 61 PR_ASSERT(0 == rv);
michael@0 62 #endif
michael@0 63 #endif
michael@0 64
michael@0 65 rv = _PT_PTHREAD_CONDATTR_INIT(&_pt_cvar_attr);
michael@0 66 PR_ASSERT(0 == rv);
michael@0 67 }
michael@0 68
michael@0 69 static void pt_PostNotifies(PRLock *lock, PRBool unlock)
michael@0 70 {
michael@0 71 PRIntn index, rv;
michael@0 72 _PT_Notified post;
michael@0 73 _PT_Notified *notified, *prev = NULL;
michael@0 74 /*
michael@0 75 * Time to actually notify any conditions that were affected
michael@0 76 * while the lock was held. Get a copy of the list that's in
michael@0 77 * the lock structure and then zero the original. If it's
michael@0 78 * linked to other such structures, we own that storage.
michael@0 79 */
michael@0 80 post = lock->notified; /* a safe copy; we own the lock */
michael@0 81
michael@0 82 #if defined(DEBUG)
michael@0 83 memset(&lock->notified, 0, sizeof(_PT_Notified)); /* reset */
michael@0 84 #else
michael@0 85 lock->notified.length = 0; /* these are really sufficient */
michael@0 86 lock->notified.link = NULL;
michael@0 87 #endif
michael@0 88
michael@0 89 /* should (may) we release lock before notifying? */
michael@0 90 if (unlock)
michael@0 91 {
michael@0 92 rv = pthread_mutex_unlock(&lock->mutex);
michael@0 93 PR_ASSERT(0 == rv);
michael@0 94 }
michael@0 95
michael@0 96 notified = &post; /* this is where we start */
michael@0 97 do
michael@0 98 {
michael@0 99 for (index = 0; index < notified->length; ++index)
michael@0 100 {
michael@0 101 PRCondVar *cv = notified->cv[index].cv;
michael@0 102 PR_ASSERT(NULL != cv);
michael@0 103 PR_ASSERT(0 != notified->cv[index].times);
michael@0 104 if (-1 == notified->cv[index].times)
michael@0 105 {
michael@0 106 rv = pthread_cond_broadcast(&cv->cv);
michael@0 107 PR_ASSERT(0 == rv);
michael@0 108 }
michael@0 109 else
michael@0 110 {
michael@0 111 while (notified->cv[index].times-- > 0)
michael@0 112 {
michael@0 113 rv = pthread_cond_signal(&cv->cv);
michael@0 114 PR_ASSERT(0 == rv);
michael@0 115 }
michael@0 116 }
michael@0 117 #if defined(DEBUG)
michael@0 118 pt_debug.cvars_notified += 1;
michael@0 119 if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending))
michael@0 120 {
michael@0 121 pt_debug.delayed_cv_deletes += 1;
michael@0 122 PR_DestroyCondVar(cv);
michael@0 123 }
michael@0 124 #else /* defined(DEBUG) */
michael@0 125 if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending))
michael@0 126 PR_DestroyCondVar(cv);
michael@0 127 #endif /* defined(DEBUG) */
michael@0 128 }
michael@0 129 prev = notified;
michael@0 130 notified = notified->link;
michael@0 131 if (&post != prev) PR_DELETE(prev);
michael@0 132 } while (NULL != notified);
michael@0 133 } /* pt_PostNotifies */
michael@0 134
michael@0 135 PR_IMPLEMENT(PRLock*) PR_NewLock(void)
michael@0 136 {
michael@0 137 PRIntn rv;
michael@0 138 PRLock *lock;
michael@0 139
michael@0 140 if (!_pr_initialized) _PR_ImplicitInitialization();
michael@0 141
michael@0 142 lock = PR_NEWZAP(PRLock);
michael@0 143 if (lock != NULL)
michael@0 144 {
michael@0 145 rv = _PT_PTHREAD_MUTEX_INIT(lock->mutex, _pt_mattr);
michael@0 146 PR_ASSERT(0 == rv);
michael@0 147 }
michael@0 148 #if defined(DEBUG)
michael@0 149 pt_debug.locks_created += 1;
michael@0 150 #endif
michael@0 151 return lock;
michael@0 152 } /* PR_NewLock */
michael@0 153
michael@0 154 PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock)
michael@0 155 {
michael@0 156 PRIntn rv;
michael@0 157 PR_ASSERT(NULL != lock);
michael@0 158 PR_ASSERT(PR_FALSE == lock->locked);
michael@0 159 PR_ASSERT(0 == lock->notified.length);
michael@0 160 PR_ASSERT(NULL == lock->notified.link);
michael@0 161 rv = pthread_mutex_destroy(&lock->mutex);
michael@0 162 PR_ASSERT(0 == rv);
michael@0 163 #if defined(DEBUG)
michael@0 164 memset(lock, 0xaf, sizeof(PRLock));
michael@0 165 pt_debug.locks_destroyed += 1;
michael@0 166 #endif
michael@0 167 PR_Free(lock);
michael@0 168 } /* PR_DestroyLock */
michael@0 169
michael@0 170 PR_IMPLEMENT(void) PR_Lock(PRLock *lock)
michael@0 171 {
michael@0 172 /* Nb: PR_Lock must not call PR_GetCurrentThread to access the |id| or
michael@0 173 * |tid| field of the current thread's PRThread structure because
michael@0 174 * _pt_root calls PR_Lock before setting thred->id and thred->tid. */
michael@0 175 PRIntn rv;
michael@0 176 PR_ASSERT(lock != NULL);
michael@0 177 rv = pthread_mutex_lock(&lock->mutex);
michael@0 178 PR_ASSERT(0 == rv);
michael@0 179 PR_ASSERT(0 == lock->notified.length);
michael@0 180 PR_ASSERT(NULL == lock->notified.link);
michael@0 181 PR_ASSERT(PR_FALSE == lock->locked);
michael@0 182 /* Nb: the order of the next two statements is not critical to
michael@0 183 * the correctness of PR_AssertCurrentThreadOwnsLock(), but
michael@0 184 * this particular order makes the assertion more likely to
michael@0 185 * catch errors. */
michael@0 186 lock->owner = pthread_self();
michael@0 187 lock->locked = PR_TRUE;
michael@0 188 #if defined(DEBUG)
michael@0 189 pt_debug.locks_acquired += 1;
michael@0 190 #endif
michael@0 191 } /* PR_Lock */
michael@0 192
michael@0 193 PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock)
michael@0 194 {
michael@0 195 pthread_t self = pthread_self();
michael@0 196 PRIntn rv;
michael@0 197
michael@0 198 PR_ASSERT(lock != NULL);
michael@0 199 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock->mutex));
michael@0 200 PR_ASSERT(PR_TRUE == lock->locked);
michael@0 201 PR_ASSERT(pthread_equal(lock->owner, self));
michael@0 202
michael@0 203 if (!lock->locked || !pthread_equal(lock->owner, self))
michael@0 204 return PR_FAILURE;
michael@0 205
michael@0 206 lock->locked = PR_FALSE;
michael@0 207 if (0 == lock->notified.length) /* shortcut */
michael@0 208 {
michael@0 209 rv = pthread_mutex_unlock(&lock->mutex);
michael@0 210 PR_ASSERT(0 == rv);
michael@0 211 }
michael@0 212 else pt_PostNotifies(lock, PR_TRUE);
michael@0 213
michael@0 214 #if defined(DEBUG)
michael@0 215 pt_debug.locks_released += 1;
michael@0 216 #endif
michael@0 217 return PR_SUCCESS;
michael@0 218 } /* PR_Unlock */
michael@0 219
michael@0 220 PR_IMPLEMENT(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock)
michael@0 221 {
michael@0 222 /* Nb: the order of the |locked| and |owner==me| checks is not critical
michael@0 223 * to the correctness of PR_AssertCurrentThreadOwnsLock(), but
michael@0 224 * this particular order makes the assertion more likely to
michael@0 225 * catch errors. */
michael@0 226 PR_ASSERT(lock->locked && pthread_equal(lock->owner, pthread_self()));
michael@0 227 }
michael@0 228
michael@0 229 /**************************************************************/
michael@0 230 /**************************************************************/
michael@0 231 /***************************CONDITIONS*************************/
michael@0 232 /**************************************************************/
michael@0 233 /**************************************************************/
michael@0 234
michael@0 235
michael@0 236 /*
michael@0 237 * This code is used to compute the absolute time for the wakeup.
michael@0 238 * It's moderately ugly, so it's defined here and called in a
michael@0 239 * couple of places.
michael@0 240 */
michael@0 241 #define PT_NANOPERMICRO 1000UL
michael@0 242 #define PT_BILLION 1000000000UL
michael@0 243
michael@0 244 static PRIntn pt_TimedWait(
michael@0 245 pthread_cond_t *cv, pthread_mutex_t *ml, PRIntervalTime timeout)
michael@0 246 {
michael@0 247 int rv;
michael@0 248 struct timeval now;
michael@0 249 struct timespec tmo;
michael@0 250 PRUint32 ticks = PR_TicksPerSecond();
michael@0 251
michael@0 252 tmo.tv_sec = (PRInt32)(timeout / ticks);
michael@0 253 tmo.tv_nsec = (PRInt32)(timeout - (tmo.tv_sec * ticks));
michael@0 254 tmo.tv_nsec = (PRInt32)PR_IntervalToMicroseconds(PT_NANOPERMICRO * tmo.tv_nsec);
michael@0 255
michael@0 256 /* pthreads wants this in absolute time, off we go ... */
michael@0 257 (void)GETTIMEOFDAY(&now);
michael@0 258 /* that one's usecs, this one's nsecs - grrrr! */
michael@0 259 tmo.tv_sec += now.tv_sec;
michael@0 260 tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec);
michael@0 261 tmo.tv_sec += tmo.tv_nsec / PT_BILLION;
michael@0 262 tmo.tv_nsec %= PT_BILLION;
michael@0 263
michael@0 264 rv = pthread_cond_timedwait(cv, ml, &tmo);
michael@0 265
michael@0 266 /* NSPR doesn't report timeouts */
michael@0 267 #ifdef _PR_DCETHREADS
michael@0 268 if (rv == -1) return (errno == EAGAIN) ? 0 : errno;
michael@0 269 else return rv;
michael@0 270 #else
michael@0 271 return (rv == ETIMEDOUT) ? 0 : rv;
michael@0 272 #endif
michael@0 273 } /* pt_TimedWait */
michael@0 274
michael@0 275
michael@0 276 /*
michael@0 277 * Notifies just get posted to the protecting mutex. The
michael@0 278 * actual notification is done when the lock is released so that
michael@0 279 * MP systems don't contend for a lock that they can't have.
michael@0 280 */
michael@0 281 static void pt_PostNotifyToCvar(PRCondVar *cvar, PRBool broadcast)
michael@0 282 {
michael@0 283 PRIntn index = 0;
michael@0 284 _PT_Notified *notified = &cvar->lock->notified;
michael@0 285
michael@0 286 PR_ASSERT(PR_TRUE == cvar->lock->locked);
michael@0 287 PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
michael@0 288 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex));
michael@0 289
michael@0 290 while (1)
michael@0 291 {
michael@0 292 for (index = 0; index < notified->length; ++index)
michael@0 293 {
michael@0 294 if (notified->cv[index].cv == cvar)
michael@0 295 {
michael@0 296 if (broadcast)
michael@0 297 notified->cv[index].times = -1;
michael@0 298 else if (-1 != notified->cv[index].times)
michael@0 299 notified->cv[index].times += 1;
michael@0 300 return; /* we're finished */
michael@0 301 }
michael@0 302 }
michael@0 303 /* if not full, enter new CV in this array */
michael@0 304 if (notified->length < PT_CV_NOTIFIED_LENGTH) break;
michael@0 305
michael@0 306 /* if there's no link, create an empty array and link it */
michael@0 307 if (NULL == notified->link)
michael@0 308 notified->link = PR_NEWZAP(_PT_Notified);
michael@0 309 notified = notified->link;
michael@0 310 }
michael@0 311
michael@0 312 /* A brand new entry in the array */
michael@0 313 (void)PR_ATOMIC_INCREMENT(&cvar->notify_pending);
michael@0 314 notified->cv[index].times = (broadcast) ? -1 : 1;
michael@0 315 notified->cv[index].cv = cvar;
michael@0 316 notified->length += 1;
michael@0 317 } /* pt_PostNotifyToCvar */
michael@0 318
michael@0 319 PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock)
michael@0 320 {
michael@0 321 PRCondVar *cv = PR_NEW(PRCondVar);
michael@0 322 PR_ASSERT(lock != NULL);
michael@0 323 if (cv != NULL)
michael@0 324 {
michael@0 325 int rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr);
michael@0 326 PR_ASSERT(0 == rv);
michael@0 327 cv->lock = lock;
michael@0 328 cv->notify_pending = 0;
michael@0 329 #if defined(DEBUG)
michael@0 330 pt_debug.cvars_created += 1;
michael@0 331 #endif
michael@0 332 }
michael@0 333 return cv;
michael@0 334 } /* PR_NewCondVar */
michael@0 335
michael@0 336 PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar)
michael@0 337 {
michael@0 338 if (0 > PR_ATOMIC_DECREMENT(&cvar->notify_pending))
michael@0 339 {
michael@0 340 PRIntn rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv);
michael@0 341 #if defined(DEBUG)
michael@0 342 memset(cvar, 0xaf, sizeof(PRCondVar));
michael@0 343 pt_debug.cvars_destroyed += 1;
michael@0 344 #endif
michael@0 345 PR_Free(cvar);
michael@0 346 }
michael@0 347 } /* PR_DestroyCondVar */
michael@0 348
michael@0 349 PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout)
michael@0 350 {
michael@0 351 PRIntn rv;
michael@0 352 PRThread *thred = PR_GetCurrentThread();
michael@0 353
michael@0 354 PR_ASSERT(cvar != NULL);
michael@0 355 /* We'd better be locked */
michael@0 356 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex));
michael@0 357 PR_ASSERT(PR_TRUE == cvar->lock->locked);
michael@0 358 /* and it better be by us */
michael@0 359 PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
michael@0 360
michael@0 361 if (_PT_THREAD_INTERRUPTED(thred)) goto aborted;
michael@0 362
michael@0 363 /*
michael@0 364 * The thread waiting is used for PR_Interrupt
michael@0 365 */
michael@0 366 thred->waiting = cvar; /* this is where we're waiting */
michael@0 367
michael@0 368 /*
michael@0 369 * If we have pending notifies, post them now.
michael@0 370 *
michael@0 371 * This is not optimal. We're going to post these notifies
michael@0 372 * while we're holding the lock. That means on MP systems
michael@0 373 * that they are going to collide for the lock that we will
michael@0 374 * hold until we actually wait.
michael@0 375 */
michael@0 376 if (0 != cvar->lock->notified.length)
michael@0 377 pt_PostNotifies(cvar->lock, PR_FALSE);
michael@0 378
michael@0 379 /*
michael@0 380 * We're surrendering the lock, so clear out the locked field.
michael@0 381 */
michael@0 382 cvar->lock->locked = PR_FALSE;
michael@0 383
michael@0 384 if (timeout == PR_INTERVAL_NO_TIMEOUT)
michael@0 385 rv = pthread_cond_wait(&cvar->cv, &cvar->lock->mutex);
michael@0 386 else
michael@0 387 rv = pt_TimedWait(&cvar->cv, &cvar->lock->mutex, timeout);
michael@0 388
michael@0 389 /* We just got the lock back - this better be empty */
michael@0 390 PR_ASSERT(PR_FALSE == cvar->lock->locked);
michael@0 391 cvar->lock->locked = PR_TRUE;
michael@0 392 cvar->lock->owner = pthread_self();
michael@0 393
michael@0 394 PR_ASSERT(0 == cvar->lock->notified.length);
michael@0 395 thred->waiting = NULL; /* and now we're not */
michael@0 396 if (_PT_THREAD_INTERRUPTED(thred)) goto aborted;
michael@0 397 if (rv != 0)
michael@0 398 {
michael@0 399 _PR_MD_MAP_DEFAULT_ERROR(rv);
michael@0 400 return PR_FAILURE;
michael@0 401 }
michael@0 402 return PR_SUCCESS;
michael@0 403
michael@0 404 aborted:
michael@0 405 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
michael@0 406 thred->state &= ~PT_THREAD_ABORTED;
michael@0 407 return PR_FAILURE;
michael@0 408 } /* PR_WaitCondVar */
michael@0 409
michael@0 410 PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar)
michael@0 411 {
michael@0 412 PR_ASSERT(cvar != NULL);
michael@0 413 pt_PostNotifyToCvar(cvar, PR_FALSE);
michael@0 414 return PR_SUCCESS;
michael@0 415 } /* PR_NotifyCondVar */
michael@0 416
michael@0 417 PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar)
michael@0 418 {
michael@0 419 PR_ASSERT(cvar != NULL);
michael@0 420 pt_PostNotifyToCvar(cvar, PR_TRUE);
michael@0 421 return PR_SUCCESS;
michael@0 422 } /* PR_NotifyAllCondVar */
michael@0 423
michael@0 424 /**************************************************************/
michael@0 425 /**************************************************************/
michael@0 426 /***************************MONITORS***************************/
michael@0 427 /**************************************************************/
michael@0 428 /**************************************************************/
michael@0 429
michael@0 430 /*
michael@0 431 * Notifies just get posted to the monitor. The actual notification is done
michael@0 432 * when the monitor is fully exited so that MP systems don't contend for a
michael@0 433 * monitor that they can't enter.
michael@0 434 */
michael@0 435 static void pt_PostNotifyToMonitor(PRMonitor *mon, PRBool broadcast)
michael@0 436 {
michael@0 437 PR_ASSERT(NULL != mon);
michael@0 438 PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mon);
michael@0 439
michael@0 440 /* mon->notifyTimes is protected by the monitor, so we don't need to
michael@0 441 * acquire mon->lock.
michael@0 442 */
michael@0 443 if (broadcast)
michael@0 444 mon->notifyTimes = -1;
michael@0 445 else if (-1 != mon->notifyTimes)
michael@0 446 mon->notifyTimes += 1;
michael@0 447 } /* pt_PostNotifyToMonitor */
michael@0 448
michael@0 449 static void pt_PostNotifiesFromMonitor(pthread_cond_t *cv, PRIntn times)
michael@0 450 {
michael@0 451 PRIntn rv;
michael@0 452
michael@0 453 /*
michael@0 454 * Time to actually notify any waits that were affected while the monitor
michael@0 455 * was entered.
michael@0 456 */
michael@0 457 PR_ASSERT(NULL != cv);
michael@0 458 PR_ASSERT(0 != times);
michael@0 459 if (-1 == times)
michael@0 460 {
michael@0 461 rv = pthread_cond_broadcast(cv);
michael@0 462 PR_ASSERT(0 == rv);
michael@0 463 }
michael@0 464 else
michael@0 465 {
michael@0 466 while (times-- > 0)
michael@0 467 {
michael@0 468 rv = pthread_cond_signal(cv);
michael@0 469 PR_ASSERT(0 == rv);
michael@0 470 }
michael@0 471 }
michael@0 472 } /* pt_PostNotifiesFromMonitor */
michael@0 473
michael@0 474 PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void)
michael@0 475 {
michael@0 476 PRMonitor *mon;
michael@0 477 int rv;
michael@0 478
michael@0 479 if (!_pr_initialized) _PR_ImplicitInitialization();
michael@0 480
michael@0 481 mon = PR_NEWZAP(PRMonitor);
michael@0 482 if (mon == NULL)
michael@0 483 {
michael@0 484 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
michael@0 485 return NULL;
michael@0 486 }
michael@0 487
michael@0 488 rv = _PT_PTHREAD_MUTEX_INIT(mon->lock, _pt_mattr);
michael@0 489 PR_ASSERT(0 == rv);
michael@0 490 if (0 != rv)
michael@0 491 goto error1;
michael@0 492
michael@0 493 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
michael@0 494
michael@0 495 rv = _PT_PTHREAD_COND_INIT(mon->entryCV, _pt_cvar_attr);
michael@0 496 PR_ASSERT(0 == rv);
michael@0 497 if (0 != rv)
michael@0 498 goto error2;
michael@0 499
michael@0 500 rv = _PT_PTHREAD_COND_INIT(mon->waitCV, _pt_cvar_attr);
michael@0 501 PR_ASSERT(0 == rv);
michael@0 502 if (0 != rv)
michael@0 503 goto error3;
michael@0 504
michael@0 505 mon->notifyTimes = 0;
michael@0 506 mon->entryCount = 0;
michael@0 507 mon->refCount = 1;
michael@0 508 mon->name = NULL;
michael@0 509 return mon;
michael@0 510
michael@0 511 error3:
michael@0 512 pthread_cond_destroy(&mon->entryCV);
michael@0 513 error2:
michael@0 514 pthread_mutex_destroy(&mon->lock);
michael@0 515 error1:
michael@0 516 PR_Free(mon);
michael@0 517 _PR_MD_MAP_DEFAULT_ERROR(rv);
michael@0 518 return NULL;
michael@0 519 } /* PR_NewMonitor */
michael@0 520
michael@0 521 PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name)
michael@0 522 {
michael@0 523 PRMonitor* mon = PR_NewMonitor();
michael@0 524 if (mon)
michael@0 525 mon->name = name;
michael@0 526 return mon;
michael@0 527 }
michael@0 528
michael@0 529 PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon)
michael@0 530 {
michael@0 531 int rv;
michael@0 532
michael@0 533 PR_ASSERT(mon != NULL);
michael@0 534 if (PR_ATOMIC_DECREMENT(&mon->refCount) == 0)
michael@0 535 {
michael@0 536 rv = pthread_cond_destroy(&mon->waitCV); PR_ASSERT(0 == rv);
michael@0 537 rv = pthread_cond_destroy(&mon->entryCV); PR_ASSERT(0 == rv);
michael@0 538 rv = pthread_mutex_destroy(&mon->lock); PR_ASSERT(0 == rv);
michael@0 539 #if defined(DEBUG)
michael@0 540 memset(mon, 0xaf, sizeof(PRMonitor));
michael@0 541 #endif
michael@0 542 PR_Free(mon);
michael@0 543 }
michael@0 544 } /* PR_DestroyMonitor */
michael@0 545
michael@0 546 /* The GC uses this; it is quite arguably a bad interface. I'm just
michael@0 547 * duplicating it for now - XXXMB
michael@0 548 */
michael@0 549 PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon)
michael@0 550 {
michael@0 551 pthread_t self = pthread_self();
michael@0 552 PRIntn rv;
michael@0 553 PRIntn count = 0;
michael@0 554
michael@0 555 rv = pthread_mutex_lock(&mon->lock);
michael@0 556 PR_ASSERT(0 == rv);
michael@0 557 if (pthread_equal(mon->owner, self))
michael@0 558 count = mon->entryCount;
michael@0 559 rv = pthread_mutex_unlock(&mon->lock);
michael@0 560 PR_ASSERT(0 == rv);
michael@0 561 return count;
michael@0 562 }
michael@0 563
michael@0 564 PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon)
michael@0 565 {
michael@0 566 #if defined(DEBUG) || defined(FORCE_PR_ASSERT)
michael@0 567 PRIntn rv;
michael@0 568
michael@0 569 rv = pthread_mutex_lock(&mon->lock);
michael@0 570 PR_ASSERT(0 == rv);
michael@0 571 PR_ASSERT(mon->entryCount != 0 &&
michael@0 572 pthread_equal(mon->owner, pthread_self()));
michael@0 573 rv = pthread_mutex_unlock(&mon->lock);
michael@0 574 PR_ASSERT(0 == rv);
michael@0 575 #endif
michael@0 576 }
michael@0 577
michael@0 578 PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon)
michael@0 579 {
michael@0 580 pthread_t self = pthread_self();
michael@0 581 PRIntn rv;
michael@0 582
michael@0 583 PR_ASSERT(mon != NULL);
michael@0 584 rv = pthread_mutex_lock(&mon->lock);
michael@0 585 PR_ASSERT(0 == rv);
michael@0 586 if (mon->entryCount != 0)
michael@0 587 {
michael@0 588 if (pthread_equal(mon->owner, self))
michael@0 589 goto done;
michael@0 590 while (mon->entryCount != 0)
michael@0 591 {
michael@0 592 rv = pthread_cond_wait(&mon->entryCV, &mon->lock);
michael@0 593 PR_ASSERT(0 == rv);
michael@0 594 }
michael@0 595 }
michael@0 596 /* and now I have the monitor */
michael@0 597 PR_ASSERT(0 == mon->notifyTimes);
michael@0 598 PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner));
michael@0 599 _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner);
michael@0 600
michael@0 601 done:
michael@0 602 mon->entryCount += 1;
michael@0 603 rv = pthread_mutex_unlock(&mon->lock);
michael@0 604 PR_ASSERT(0 == rv);
michael@0 605 } /* PR_EnterMonitor */
michael@0 606
michael@0 607 PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon)
michael@0 608 {
michael@0 609 pthread_t self = pthread_self();
michael@0 610 PRIntn rv;
michael@0 611 PRBool notifyEntryWaiter = PR_FALSE;
michael@0 612 PRIntn notifyTimes = 0;
michael@0 613
michael@0 614 PR_ASSERT(mon != NULL);
michael@0 615 rv = pthread_mutex_lock(&mon->lock);
michael@0 616 PR_ASSERT(0 == rv);
michael@0 617 /* the entries should be > 0 and we'd better be the owner */
michael@0 618 PR_ASSERT(mon->entryCount > 0);
michael@0 619 PR_ASSERT(pthread_equal(mon->owner, self));
michael@0 620 if (mon->entryCount == 0 || !pthread_equal(mon->owner, self))
michael@0 621 {
michael@0 622 rv = pthread_mutex_unlock(&mon->lock);
michael@0 623 PR_ASSERT(0 == rv);
michael@0 624 return PR_FAILURE;
michael@0 625 }
michael@0 626
michael@0 627 mon->entryCount -= 1; /* reduce by one */
michael@0 628 if (mon->entryCount == 0)
michael@0 629 {
michael@0 630 /* and if it transitioned to zero - notify an entry waiter */
michael@0 631 /* make the owner unknown */
michael@0 632 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
michael@0 633 notifyEntryWaiter = PR_TRUE;
michael@0 634 notifyTimes = mon->notifyTimes;
michael@0 635 mon->notifyTimes = 0;
michael@0 636 /* We will access the members of 'mon' after unlocking mon->lock.
michael@0 637 * Add a reference. */
michael@0 638 PR_ATOMIC_INCREMENT(&mon->refCount);
michael@0 639 }
michael@0 640 rv = pthread_mutex_unlock(&mon->lock);
michael@0 641 PR_ASSERT(0 == rv);
michael@0 642 if (notifyEntryWaiter)
michael@0 643 {
michael@0 644 if (notifyTimes)
michael@0 645 pt_PostNotifiesFromMonitor(&mon->waitCV, notifyTimes);
michael@0 646 rv = pthread_cond_signal(&mon->entryCV);
michael@0 647 PR_ASSERT(0 == rv);
michael@0 648 /* We are done accessing the members of 'mon'. Release the
michael@0 649 * reference. */
michael@0 650 PR_DestroyMonitor(mon);
michael@0 651 }
michael@0 652 return PR_SUCCESS;
michael@0 653 } /* PR_ExitMonitor */
michael@0 654
michael@0 655 PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout)
michael@0 656 {
michael@0 657 PRStatus rv;
michael@0 658 PRUint32 saved_entries;
michael@0 659 pthread_t saved_owner;
michael@0 660
michael@0 661 PR_ASSERT(mon != NULL);
michael@0 662 rv = pthread_mutex_lock(&mon->lock);
michael@0 663 PR_ASSERT(0 == rv);
michael@0 664 /* the entries better be positive */
michael@0 665 PR_ASSERT(mon->entryCount > 0);
michael@0 666 /* and it better be owned by us */
michael@0 667 PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
michael@0 668
michael@0 669 /* tuck these away 'till later */
michael@0 670 saved_entries = mon->entryCount;
michael@0 671 mon->entryCount = 0;
michael@0 672 _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner);
michael@0 673 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
michael@0 674 /*
michael@0 675 * If we have pending notifies, post them now.
michael@0 676 *
michael@0 677 * This is not optimal. We're going to post these notifies
michael@0 678 * while we're holding the lock. That means on MP systems
michael@0 679 * that they are going to collide for the lock that we will
michael@0 680 * hold until we actually wait.
michael@0 681 */
michael@0 682 if (0 != mon->notifyTimes)
michael@0 683 {
michael@0 684 pt_PostNotifiesFromMonitor(&mon->waitCV, mon->notifyTimes);
michael@0 685 mon->notifyTimes = 0;
michael@0 686 }
michael@0 687 rv = pthread_cond_signal(&mon->entryCV);
michael@0 688 PR_ASSERT(0 == rv);
michael@0 689
michael@0 690 if (timeout == PR_INTERVAL_NO_TIMEOUT)
michael@0 691 rv = pthread_cond_wait(&mon->waitCV, &mon->lock);
michael@0 692 else
michael@0 693 rv = pt_TimedWait(&mon->waitCV, &mon->lock, timeout);
michael@0 694 PR_ASSERT(0 == rv);
michael@0 695
michael@0 696 while (mon->entryCount != 0)
michael@0 697 {
michael@0 698 rv = pthread_cond_wait(&mon->entryCV, &mon->lock);
michael@0 699 PR_ASSERT(0 == rv);
michael@0 700 }
michael@0 701 PR_ASSERT(0 == mon->notifyTimes);
michael@0 702 /* reinstate the interesting information */
michael@0 703 mon->entryCount = saved_entries;
michael@0 704 _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner);
michael@0 705
michael@0 706 rv = pthread_mutex_unlock(&mon->lock);
michael@0 707 PR_ASSERT(0 == rv);
michael@0 708 return rv;
michael@0 709 } /* PR_Wait */
michael@0 710
michael@0 711 PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon)
michael@0 712 {
michael@0 713 pt_PostNotifyToMonitor(mon, PR_FALSE);
michael@0 714 return PR_SUCCESS;
michael@0 715 } /* PR_Notify */
michael@0 716
michael@0 717 PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon)
michael@0 718 {
michael@0 719 pt_PostNotifyToMonitor(mon, PR_TRUE);
michael@0 720 return PR_SUCCESS;
michael@0 721 } /* PR_NotifyAll */
michael@0 722
michael@0 723 /**************************************************************/
michael@0 724 /**************************************************************/
michael@0 725 /**************************SEMAPHORES**************************/
michael@0 726 /**************************************************************/
michael@0 727 /**************************************************************/
michael@0 728 PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore)
michael@0 729 {
michael@0 730 static PRBool unwarned = PR_TRUE;
michael@0 731 if (unwarned) unwarned = _PR_Obsolete(
michael@0 732 "PR_PostSem", "locks & condition variables");
michael@0 733 PR_Lock(semaphore->cvar->lock);
michael@0 734 PR_NotifyCondVar(semaphore->cvar);
michael@0 735 semaphore->count += 1;
michael@0 736 PR_Unlock(semaphore->cvar->lock);
michael@0 737 } /* PR_PostSem */
michael@0 738
michael@0 739 PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *semaphore)
michael@0 740 {
michael@0 741 PRStatus status = PR_SUCCESS;
michael@0 742 static PRBool unwarned = PR_TRUE;
michael@0 743 if (unwarned) unwarned = _PR_Obsolete(
michael@0 744 "PR_WaitSem", "locks & condition variables");
michael@0 745 PR_Lock(semaphore->cvar->lock);
michael@0 746 while ((semaphore->count == 0) && (PR_SUCCESS == status))
michael@0 747 status = PR_WaitCondVar(semaphore->cvar, PR_INTERVAL_NO_TIMEOUT);
michael@0 748 if (PR_SUCCESS == status) semaphore->count -= 1;
michael@0 749 PR_Unlock(semaphore->cvar->lock);
michael@0 750 return status;
michael@0 751 } /* PR_WaitSem */
michael@0 752
michael@0 753 PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *semaphore)
michael@0 754 {
michael@0 755 static PRBool unwarned = PR_TRUE;
michael@0 756 if (unwarned) unwarned = _PR_Obsolete(
michael@0 757 "PR_DestroySem", "locks & condition variables");
michael@0 758 PR_DestroyLock(semaphore->cvar->lock);
michael@0 759 PR_DestroyCondVar(semaphore->cvar);
michael@0 760 PR_Free(semaphore);
michael@0 761 } /* PR_DestroySem */
michael@0 762
michael@0 763 PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value)
michael@0 764 {
michael@0 765 PRSemaphore *semaphore;
michael@0 766 static PRBool unwarned = PR_TRUE;
michael@0 767 if (!_pr_initialized) _PR_ImplicitInitialization();
michael@0 768
michael@0 769 if (unwarned) unwarned = _PR_Obsolete(
michael@0 770 "PR_NewSem", "locks & condition variables");
michael@0 771
michael@0 772 semaphore = PR_NEWZAP(PRSemaphore);
michael@0 773 if (NULL != semaphore)
michael@0 774 {
michael@0 775 PRLock *lock = PR_NewLock();
michael@0 776 if (NULL != lock)
michael@0 777 {
michael@0 778 semaphore->cvar = PR_NewCondVar(lock);
michael@0 779 if (NULL != semaphore->cvar)
michael@0 780 {
michael@0 781 semaphore->count = value;
michael@0 782 return semaphore;
michael@0 783 }
michael@0 784 PR_DestroyLock(lock);
michael@0 785 }
michael@0 786 PR_Free(semaphore);
michael@0 787 }
michael@0 788 return NULL;
michael@0 789 }
michael@0 790
michael@0 791 /*
michael@0 792 * Define the interprocess named semaphore functions.
michael@0 793 * There are three implementations:
michael@0 794 * 1. POSIX semaphore based;
michael@0 795 * 2. System V semaphore based;
michael@0 796 * 3. unsupported (fails with PR_NOT_IMPLEMENTED_ERROR).
michael@0 797 */
michael@0 798
michael@0 799 #ifdef _PR_HAVE_POSIX_SEMAPHORES
michael@0 800 #include <fcntl.h>
michael@0 801
michael@0 802 PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
michael@0 803 const char *name,
michael@0 804 PRIntn flags,
michael@0 805 PRIntn mode,
michael@0 806 PRUintn value)
michael@0 807 {
michael@0 808 PRSem *sem;
michael@0 809 char osname[PR_IPC_NAME_SIZE];
michael@0 810
michael@0 811 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
michael@0 812 == PR_FAILURE)
michael@0 813 {
michael@0 814 return NULL;
michael@0 815 }
michael@0 816
michael@0 817 sem = PR_NEW(PRSem);
michael@0 818 if (NULL == sem)
michael@0 819 {
michael@0 820 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
michael@0 821 return NULL;
michael@0 822 }
michael@0 823
michael@0 824 if (flags & PR_SEM_CREATE)
michael@0 825 {
michael@0 826 int oflag = O_CREAT;
michael@0 827
michael@0 828 if (flags & PR_SEM_EXCL) oflag |= O_EXCL;
michael@0 829 sem->sem = sem_open(osname, oflag, mode, value);
michael@0 830 }
michael@0 831 else
michael@0 832 {
michael@0 833 #ifdef HPUX
michael@0 834 /* Pass 0 as the mode and value arguments to work around a bug. */
michael@0 835 sem->sem = sem_open(osname, 0, 0, 0);
michael@0 836 #else
michael@0 837 sem->sem = sem_open(osname, 0);
michael@0 838 #endif
michael@0 839 }
michael@0 840 if ((sem_t *) -1 == sem->sem)
michael@0 841 {
michael@0 842 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 843 PR_Free(sem);
michael@0 844 return NULL;
michael@0 845 }
michael@0 846 return sem;
michael@0 847 }
michael@0 848
michael@0 849 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
michael@0 850 {
michael@0 851 int rv;
michael@0 852 rv = sem_wait(sem->sem);
michael@0 853 if (0 != rv)
michael@0 854 {
michael@0 855 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 856 return PR_FAILURE;
michael@0 857 }
michael@0 858 return PR_SUCCESS;
michael@0 859 }
michael@0 860
michael@0 861 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
michael@0 862 {
michael@0 863 int rv;
michael@0 864 rv = sem_post(sem->sem);
michael@0 865 if (0 != rv)
michael@0 866 {
michael@0 867 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 868 return PR_FAILURE;
michael@0 869 }
michael@0 870 return PR_SUCCESS;
michael@0 871 }
michael@0 872
michael@0 873 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
michael@0 874 {
michael@0 875 int rv;
michael@0 876 rv = sem_close(sem->sem);
michael@0 877 if (0 != rv)
michael@0 878 {
michael@0 879 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 880 return PR_FAILURE;
michael@0 881 }
michael@0 882 PR_Free(sem);
michael@0 883 return PR_SUCCESS;
michael@0 884 }
michael@0 885
michael@0 886 PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
michael@0 887 {
michael@0 888 int rv;
michael@0 889 char osname[PR_IPC_NAME_SIZE];
michael@0 890
michael@0 891 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
michael@0 892 == PR_FAILURE)
michael@0 893 {
michael@0 894 return PR_FAILURE;
michael@0 895 }
michael@0 896 rv = sem_unlink(osname);
michael@0 897 if (0 != rv)
michael@0 898 {
michael@0 899 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 900 return PR_FAILURE;
michael@0 901 }
michael@0 902 return PR_SUCCESS;
michael@0 903 }
michael@0 904
michael@0 905 #elif defined(_PR_HAVE_SYSV_SEMAPHORES)
michael@0 906
michael@0 907 #include <fcntl.h>
michael@0 908 #include <sys/sem.h>
michael@0 909
michael@0 910 /*
michael@0 911 * From the semctl(2) man page in glibc 2.0
michael@0 912 */
michael@0 913 #if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) \
michael@0 914 || defined(FREEBSD) || defined(OPENBSD) || defined(BSDI) \
michael@0 915 || defined(DARWIN) || defined(SYMBIAN)
michael@0 916 /* union semun is defined by including <sys/sem.h> */
michael@0 917 #else
michael@0 918 /* according to X/OPEN we have to define it ourselves */
michael@0 919 union semun {
michael@0 920 int val;
michael@0 921 struct semid_ds *buf;
michael@0 922 unsigned short *array;
michael@0 923 };
michael@0 924 #endif
michael@0 925
michael@0 926 /*
michael@0 927 * 'a' (97) is the final closing price of NSCP stock.
michael@0 928 */
michael@0 929 #define NSPR_IPC_KEY_ID 'a' /* the id argument for ftok() */
michael@0 930
michael@0 931 #define NSPR_SEM_MODE 0666
michael@0 932
michael@0 933 PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
michael@0 934 const char *name,
michael@0 935 PRIntn flags,
michael@0 936 PRIntn mode,
michael@0 937 PRUintn value)
michael@0 938 {
michael@0 939 PRSem *sem;
michael@0 940 key_t key;
michael@0 941 union semun arg;
michael@0 942 struct sembuf sop;
michael@0 943 struct semid_ds seminfo;
michael@0 944 #define MAX_TRIES 60
michael@0 945 PRIntn i;
michael@0 946 char osname[PR_IPC_NAME_SIZE];
michael@0 947
michael@0 948 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
michael@0 949 == PR_FAILURE)
michael@0 950 {
michael@0 951 return NULL;
michael@0 952 }
michael@0 953
michael@0 954 /* Make sure the file exists before calling ftok. */
michael@0 955 if (flags & PR_SEM_CREATE)
michael@0 956 {
michael@0 957 int osfd = open(osname, O_RDWR|O_CREAT, mode);
michael@0 958 if (-1 == osfd)
michael@0 959 {
michael@0 960 _PR_MD_MAP_OPEN_ERROR(errno);
michael@0 961 return NULL;
michael@0 962 }
michael@0 963 if (close(osfd) == -1)
michael@0 964 {
michael@0 965 _PR_MD_MAP_CLOSE_ERROR(errno);
michael@0 966 return NULL;
michael@0 967 }
michael@0 968 }
michael@0 969 key = ftok(osname, NSPR_IPC_KEY_ID);
michael@0 970 if ((key_t)-1 == key)
michael@0 971 {
michael@0 972 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 973 return NULL;
michael@0 974 }
michael@0 975
michael@0 976 sem = PR_NEW(PRSem);
michael@0 977 if (NULL == sem)
michael@0 978 {
michael@0 979 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
michael@0 980 return NULL;
michael@0 981 }
michael@0 982
michael@0 983 if (flags & PR_SEM_CREATE)
michael@0 984 {
michael@0 985 sem->semid = semget(key, 1, mode|IPC_CREAT|IPC_EXCL);
michael@0 986 if (sem->semid >= 0)
michael@0 987 {
michael@0 988 /* creator of a semaphore is responsible for initializing it */
michael@0 989 arg.val = 0;
michael@0 990 if (semctl(sem->semid, 0, SETVAL, arg) == -1)
michael@0 991 {
michael@0 992 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 993 PR_Free(sem);
michael@0 994 return NULL;
michael@0 995 }
michael@0 996 /* call semop to set sem_otime to nonzero */
michael@0 997 sop.sem_num = 0;
michael@0 998 sop.sem_op = value;
michael@0 999 sop.sem_flg = 0;
michael@0 1000 if (semop(sem->semid, &sop, 1) == -1)
michael@0 1001 {
michael@0 1002 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 1003 PR_Free(sem);
michael@0 1004 return NULL;
michael@0 1005 }
michael@0 1006 return sem;
michael@0 1007 }
michael@0 1008
michael@0 1009 if (errno != EEXIST || flags & PR_SEM_EXCL)
michael@0 1010 {
michael@0 1011 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 1012 PR_Free(sem);
michael@0 1013 return NULL;
michael@0 1014 }
michael@0 1015 }
michael@0 1016
michael@0 1017 sem->semid = semget(key, 1, NSPR_SEM_MODE);
michael@0 1018 if (sem->semid == -1)
michael@0 1019 {
michael@0 1020 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 1021 PR_Free(sem);
michael@0 1022 return NULL;
michael@0 1023 }
michael@0 1024 for (i = 0; i < MAX_TRIES; i++)
michael@0 1025 {
michael@0 1026 arg.buf = &seminfo;
michael@0 1027 semctl(sem->semid, 0, IPC_STAT, arg);
michael@0 1028 if (seminfo.sem_otime != 0) break;
michael@0 1029 sleep(1);
michael@0 1030 }
michael@0 1031 if (i == MAX_TRIES)
michael@0 1032 {
michael@0 1033 PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
michael@0 1034 PR_Free(sem);
michael@0 1035 return NULL;
michael@0 1036 }
michael@0 1037 return sem;
michael@0 1038 }
michael@0 1039
michael@0 1040 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
michael@0 1041 {
michael@0 1042 struct sembuf sop;
michael@0 1043
michael@0 1044 sop.sem_num = 0;
michael@0 1045 sop.sem_op = -1;
michael@0 1046 sop.sem_flg = 0;
michael@0 1047 if (semop(sem->semid, &sop, 1) == -1)
michael@0 1048 {
michael@0 1049 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 1050 return PR_FAILURE;
michael@0 1051 }
michael@0 1052 return PR_SUCCESS;
michael@0 1053 }
michael@0 1054
michael@0 1055 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
michael@0 1056 {
michael@0 1057 struct sembuf sop;
michael@0 1058
michael@0 1059 sop.sem_num = 0;
michael@0 1060 sop.sem_op = 1;
michael@0 1061 sop.sem_flg = 0;
michael@0 1062 if (semop(sem->semid, &sop, 1) == -1)
michael@0 1063 {
michael@0 1064 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 1065 return PR_FAILURE;
michael@0 1066 }
michael@0 1067 return PR_SUCCESS;
michael@0 1068 }
michael@0 1069
michael@0 1070 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
michael@0 1071 {
michael@0 1072 PR_Free(sem);
michael@0 1073 return PR_SUCCESS;
michael@0 1074 }
michael@0 1075
michael@0 1076 PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
michael@0 1077 {
michael@0 1078 key_t key;
michael@0 1079 int semid;
michael@0 1080 /* On some systems (e.g., glibc 2.0) semctl requires a fourth argument */
michael@0 1081 union semun unused;
michael@0 1082 char osname[PR_IPC_NAME_SIZE];
michael@0 1083
michael@0 1084 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
michael@0 1085 == PR_FAILURE)
michael@0 1086 {
michael@0 1087 return PR_FAILURE;
michael@0 1088 }
michael@0 1089 key = ftok(osname, NSPR_IPC_KEY_ID);
michael@0 1090 if ((key_t) -1 == key)
michael@0 1091 {
michael@0 1092 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 1093 return PR_FAILURE;
michael@0 1094 }
michael@0 1095 if (unlink(osname) == -1)
michael@0 1096 {
michael@0 1097 _PR_MD_MAP_UNLINK_ERROR(errno);
michael@0 1098 return PR_FAILURE;
michael@0 1099 }
michael@0 1100 semid = semget(key, 1, NSPR_SEM_MODE);
michael@0 1101 if (-1 == semid)
michael@0 1102 {
michael@0 1103 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 1104 return PR_FAILURE;
michael@0 1105 }
michael@0 1106 unused.val = 0;
michael@0 1107 if (semctl(semid, 0, IPC_RMID, unused) == -1)
michael@0 1108 {
michael@0 1109 _PR_MD_MAP_DEFAULT_ERROR(errno);
michael@0 1110 return PR_FAILURE;
michael@0 1111 }
michael@0 1112 return PR_SUCCESS;
michael@0 1113 }
michael@0 1114
michael@0 1115 #else /* neither POSIX nor System V semaphores are available */
michael@0 1116
michael@0 1117 PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
michael@0 1118 const char *name,
michael@0 1119 PRIntn flags,
michael@0 1120 PRIntn mode,
michael@0 1121 PRUintn value)
michael@0 1122 {
michael@0 1123 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
michael@0 1124 return NULL;
michael@0 1125 }
michael@0 1126
michael@0 1127 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
michael@0 1128 {
michael@0 1129 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
michael@0 1130 return PR_FAILURE;
michael@0 1131 }
michael@0 1132
michael@0 1133 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
michael@0 1134 {
michael@0 1135 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
michael@0 1136 return PR_FAILURE;
michael@0 1137 }
michael@0 1138
michael@0 1139 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
michael@0 1140 {
michael@0 1141 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
michael@0 1142 return PR_FAILURE;
michael@0 1143 }
michael@0 1144
michael@0 1145 PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
michael@0 1146 {
michael@0 1147 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
michael@0 1148 return PR_FAILURE;
michael@0 1149 }
michael@0 1150
michael@0 1151 #endif /* end of interprocess named semaphore functions */
michael@0 1152
michael@0 1153 /**************************************************************/
michael@0 1154 /**************************************************************/
michael@0 1155 /******************ROUTINES FOR DCE EMULATION******************/
michael@0 1156 /**************************************************************/
michael@0 1157 /**************************************************************/
michael@0 1158
michael@0 1159 #include "prpdce.h"
michael@0 1160
michael@0 1161 PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock)
michael@0 1162 {
michael@0 1163 PRIntn rv = pthread_mutex_trylock(&lock->mutex);
michael@0 1164 if (rv == PT_TRYLOCK_SUCCESS)
michael@0 1165 {
michael@0 1166 PR_ASSERT(PR_FALSE == lock->locked);
michael@0 1167 lock->locked = PR_TRUE;
michael@0 1168 lock->owner = pthread_self();
michael@0 1169 }
michael@0 1170 /* XXX set error code? */
michael@0 1171 return (PT_TRYLOCK_SUCCESS == rv) ? PR_SUCCESS : PR_FAILURE;
michael@0 1172 } /* PRP_TryLock */
michael@0 1173
michael@0 1174 PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void)
michael@0 1175 {
michael@0 1176 PRCondVar *cv;
michael@0 1177
michael@0 1178 if (!_pr_initialized) _PR_ImplicitInitialization();
michael@0 1179
michael@0 1180 cv = PR_NEW(PRCondVar);
michael@0 1181 if (cv != NULL)
michael@0 1182 {
michael@0 1183 int rv;
michael@0 1184 rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr);
michael@0 1185 PR_ASSERT(0 == rv);
michael@0 1186 cv->lock = _PR_NAKED_CV_LOCK;
michael@0 1187 }
michael@0 1188 return cv;
michael@0 1189 } /* PRP_NewNakedCondVar */
michael@0 1190
michael@0 1191 PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar)
michael@0 1192 {
michael@0 1193 int rv;
michael@0 1194 rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv);
michael@0 1195 #if defined(DEBUG)
michael@0 1196 memset(cvar, 0xaf, sizeof(PRCondVar));
michael@0 1197 #endif
michael@0 1198 PR_Free(cvar);
michael@0 1199 } /* PRP_DestroyNakedCondVar */
michael@0 1200
michael@0 1201 PR_IMPLEMENT(PRStatus) PRP_NakedWait(
michael@0 1202 PRCondVar *cvar, PRLock *ml, PRIntervalTime timeout)
michael@0 1203 {
michael@0 1204 PRIntn rv;
michael@0 1205 PR_ASSERT(cvar != NULL);
michael@0 1206 /* XXX do we really want to assert this in a naked wait? */
michael@0 1207 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(ml->mutex));
michael@0 1208 if (timeout == PR_INTERVAL_NO_TIMEOUT)
michael@0 1209 rv = pthread_cond_wait(&cvar->cv, &ml->mutex);
michael@0 1210 else
michael@0 1211 rv = pt_TimedWait(&cvar->cv, &ml->mutex, timeout);
michael@0 1212 if (rv != 0)
michael@0 1213 {
michael@0 1214 _PR_MD_MAP_DEFAULT_ERROR(rv);
michael@0 1215 return PR_FAILURE;
michael@0 1216 }
michael@0 1217 return PR_SUCCESS;
michael@0 1218 } /* PRP_NakedWait */
michael@0 1219
michael@0 1220 PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar)
michael@0 1221 {
michael@0 1222 int rv;
michael@0 1223 PR_ASSERT(cvar != NULL);
michael@0 1224 rv = pthread_cond_signal(&cvar->cv);
michael@0 1225 PR_ASSERT(0 == rv);
michael@0 1226 return PR_SUCCESS;
michael@0 1227 } /* PRP_NakedNotify */
michael@0 1228
michael@0 1229 PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar)
michael@0 1230 {
michael@0 1231 int rv;
michael@0 1232 PR_ASSERT(cvar != NULL);
michael@0 1233 rv = pthread_cond_broadcast(&cvar->cv);
michael@0 1234 PR_ASSERT(0 == rv);
michael@0 1235 return PR_SUCCESS;
michael@0 1236 } /* PRP_NakedBroadcast */
michael@0 1237
michael@0 1238 #endif /* defined(_PR_PTHREADS) */
michael@0 1239
michael@0 1240 /* ptsynch.c */

mercurial