Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(941)

Unified Diff: nspr/pr/src/pthreads/ptsynch.c

Issue 200653003: Update to NSPR 4.10.4. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « nspr/pr/src/pthreads/ptio.c ('k') | nspr/pr/src/pthreads/ptthread.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: nspr/pr/src/pthreads/ptsynch.c
===================================================================
--- nspr/pr/src/pthreads/ptsynch.c (revision 257452)
+++ nspr/pr/src/pthreads/ptsynch.c (working copy)
@@ -169,6 +169,9 @@
PR_IMPLEMENT(void) PR_Lock(PRLock *lock)
{
+ /* Nb: PR_Lock must not call PR_GetCurrentThread to access the |id| or
+ * |tid| field of the current thread's PRThread structure because
+ * _pt_root calls PR_Lock before setting thred->id and thred->tid. */
PRIntn rv;
PR_ASSERT(lock != NULL);
rv = pthread_mutex_lock(&lock->mutex);
@@ -189,14 +192,15 @@
PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock)
{
+ pthread_t self = pthread_self();
PRIntn rv;
PR_ASSERT(lock != NULL);
PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock->mutex));
PR_ASSERT(PR_TRUE == lock->locked);
- PR_ASSERT(pthread_equal(lock->owner, pthread_self()));
+ PR_ASSERT(pthread_equal(lock->owner, self));
- if (!lock->locked || !pthread_equal(lock->owner, pthread_self()))
+ if (!lock->locked || !pthread_equal(lock->owner, self))
return PR_FAILURE;
lock->locked = PR_FALSE;
@@ -293,7 +297,7 @@
notified->cv[index].times = -1;
else if (-1 != notified->cv[index].times)
notified->cv[index].times += 1;
- goto finished; /* we're finished */
+ return; /* we're finished */
}
}
/* if not full, enter new CV in this array */
@@ -310,10 +314,6 @@
notified->cv[index].times = (broadcast) ? -1 : 1;
notified->cv[index].cv = cvar;
notified->length += 1;
-
-finished:
- PR_ASSERT(PR_TRUE == cvar->lock->locked);
- PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
} /* pt_PostNotifyToCvar */
PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock)
@@ -427,54 +427,95 @@
/**************************************************************/
/**************************************************************/
+/*
+ * Notifies just get posted to the monitor. The actual notification is done
+ * when the monitor is fully exited so that MP systems don't contend for a
+ * monitor that they can't enter.
+ */
+static void pt_PostNotifyToMonitor(PRMonitor *mon, PRBool broadcast)
+{
+ PR_ASSERT(NULL != mon);
+ PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mon);
+
+ /* mon->notifyTimes is protected by the monitor, so we don't need to
+ * acquire mon->lock.
+ */
+ if (broadcast)
+ mon->notifyTimes = -1;
+ else if (-1 != mon->notifyTimes)
+ mon->notifyTimes += 1;
+} /* pt_PostNotifyToMonitor */
+
+static void pt_PostNotifiesFromMonitor(pthread_cond_t *cv, PRIntn times)
+{
+ PRIntn rv;
+
+ /*
+ * Time to actually notify any waits that were affected while the monitor
+ * was entered.
+ */
+ PR_ASSERT(NULL != cv);
+ PR_ASSERT(0 != times);
+ if (-1 == times)
+ {
+ rv = pthread_cond_broadcast(cv);
+ PR_ASSERT(0 == rv);
+ }
+ else
+ {
+ while (times-- > 0)
+ {
+ rv = pthread_cond_signal(cv);
+ PR_ASSERT(0 == rv);
+ }
+ }
+} /* pt_PostNotifiesFromMonitor */
+
PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void)
{
PRMonitor *mon;
- PRCondVar *cvar;
int rv;
if (!_pr_initialized) _PR_ImplicitInitialization();
- cvar = PR_NEWZAP(PRCondVar);
- if (NULL == cvar)
- {
- PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
- return NULL;
- }
mon = PR_NEWZAP(PRMonitor);
if (mon == NULL)
{
- PR_Free(cvar);
PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
return NULL;
}
- rv = _PT_PTHREAD_MUTEX_INIT(mon->lock.mutex, _pt_mattr);
+ rv = _PT_PTHREAD_MUTEX_INIT(mon->lock, _pt_mattr);
PR_ASSERT(0 == rv);
if (0 != rv)
- {
- PR_Free(mon);
- PR_Free(cvar);
- PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
- return NULL;
- }
+ goto error1;
_PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
- mon->cvar = cvar;
- rv = _PT_PTHREAD_COND_INIT(mon->cvar->cv, _pt_cvar_attr);
+ rv = _PT_PTHREAD_COND_INIT(mon->entryCV, _pt_cvar_attr);
PR_ASSERT(0 == rv);
+ if (0 != rv)
+ goto error2;
+
+ rv = _PT_PTHREAD_COND_INIT(mon->waitCV, _pt_cvar_attr);
+ PR_ASSERT(0 == rv);
+ if (0 != rv)
+ goto error3;
+
+ mon->notifyTimes = 0;
mon->entryCount = 0;
- mon->cvar->lock = &mon->lock;
- if (0 != rv)
- {
- pthread_mutex_destroy(&mon->lock.mutex);
- PR_Free(mon);
- PR_Free(cvar);
- PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
- return NULL;
- }
+ mon->refCount = 1;
+ mon->name = NULL;
return mon;
+
+error3:
+ pthread_cond_destroy(&mon->entryCV);
+error2:
+ pthread_mutex_destroy(&mon->lock);
+error1:
+ PR_Free(mon);
+ PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
+ return NULL;
} /* PR_NewMonitor */
PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name)
@@ -488,89 +529,141 @@
PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon)
{
int rv;
+
PR_ASSERT(mon != NULL);
- PR_DestroyCondVar(mon->cvar);
- rv = pthread_mutex_destroy(&mon->lock.mutex); PR_ASSERT(0 == rv);
+ if (PR_ATOMIC_DECREMENT(&mon->refCount) == 0)
+ {
+ rv = pthread_cond_destroy(&mon->waitCV); PR_ASSERT(0 == rv);
+ rv = pthread_cond_destroy(&mon->entryCV); PR_ASSERT(0 == rv);
+ rv = pthread_mutex_destroy(&mon->lock); PR_ASSERT(0 == rv);
#if defined(DEBUG)
memset(mon, 0xaf, sizeof(PRMonitor));
#endif
- PR_Free(mon);
+ PR_Free(mon);
+ }
} /* PR_DestroyMonitor */
-
/* The GC uses this; it is quite arguably a bad interface. I'm just
* duplicating it for now - XXXMB
*/
PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon)
{
pthread_t self = pthread_self();
+ PRIntn rv;
+ PRIntn count = 0;
+
+ rv = pthread_mutex_lock(&mon->lock);
+ PR_ASSERT(0 == rv);
if (pthread_equal(mon->owner, self))
- return mon->entryCount;
- return 0;
+ count = mon->entryCount;
+ rv = pthread_mutex_unlock(&mon->lock);
+ PR_ASSERT(0 == rv);
+ return count;
}
PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon)
{
- PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(&mon->lock);
+#if defined(DEBUG) || defined(FORCE_PR_ASSERT)
+ PRIntn rv;
+
+ rv = pthread_mutex_lock(&mon->lock);
+ PR_ASSERT(0 == rv);
+ PR_ASSERT(mon->entryCount != 0 &&
+ pthread_equal(mon->owner, pthread_self()));
+ rv = pthread_mutex_unlock(&mon->lock);
+ PR_ASSERT(0 == rv);
+#endif
}
PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon)
{
pthread_t self = pthread_self();
+ PRIntn rv;
PR_ASSERT(mon != NULL);
- /*
- * This is safe only if mon->owner (a pthread_t) can be
- * read in one instruction. Perhaps mon->owner should be
- * a "PRThread *"?
- */
- if (!pthread_equal(mon->owner, self))
+ rv = pthread_mutex_lock(&mon->lock);
+ PR_ASSERT(0 == rv);
+ if (mon->entryCount != 0)
{
- PR_Lock(&mon->lock);
- /* and now I have the lock */
- PR_ASSERT(0 == mon->entryCount);
- PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner));
- _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner);
+ if (pthread_equal(mon->owner, self))
+ goto done;
+ while (mon->entryCount != 0)
+ {
+ rv = pthread_cond_wait(&mon->entryCV, &mon->lock);
+ PR_ASSERT(0 == rv);
+ }
}
+ /* and now I have the monitor */
+ PR_ASSERT(0 == mon->notifyTimes);
+ PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner));
+ _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner);
+
+done:
mon->entryCount += 1;
+ rv = pthread_mutex_unlock(&mon->lock);
+ PR_ASSERT(0 == rv);
} /* PR_EnterMonitor */
PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon)
{
pthread_t self = pthread_self();
+ PRIntn rv;
+ PRBool notifyEntryWaiter = PR_FALSE;
+ PRIntn notifyTimes = 0;
PR_ASSERT(mon != NULL);
- /* The lock better be that - locked */
- PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
- /* we'd better be the owner */
+ rv = pthread_mutex_lock(&mon->lock);
+ PR_ASSERT(0 == rv);
+ /* the entries should be > 0 and we'd better be the owner */
+ PR_ASSERT(mon->entryCount > 0);
PR_ASSERT(pthread_equal(mon->owner, self));
- if (!pthread_equal(mon->owner, self))
+ if (mon->entryCount == 0 || !pthread_equal(mon->owner, self))
+ {
+ rv = pthread_mutex_unlock(&mon->lock);
+ PR_ASSERT(0 == rv);
return PR_FAILURE;
+ }
- /* if it's locked and we have it, then the entries should be > 0 */
- PR_ASSERT(mon->entryCount > 0);
mon->entryCount -= 1; /* reduce by one */
if (mon->entryCount == 0)
{
- /* and if it transitioned to zero - unlock */
- _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); /* make the owner unknown */
- PR_Unlock(&mon->lock);
+ /* and if it transitioned to zero - notify an entry waiter */
+ /* make the owner unknown */
+ _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
+ notifyEntryWaiter = PR_TRUE;
+ notifyTimes = mon->notifyTimes;
+ mon->notifyTimes = 0;
+ /* We will access the members of 'mon' after unlocking mon->lock.
+ * Add a reference. */
+ PR_ATOMIC_INCREMENT(&mon->refCount);
}
+ rv = pthread_mutex_unlock(&mon->lock);
+ PR_ASSERT(0 == rv);
+ if (notifyEntryWaiter)
+ {
+ if (notifyTimes)
+ pt_PostNotifiesFromMonitor(&mon->waitCV, notifyTimes);
+ rv = pthread_cond_signal(&mon->entryCV);
+ PR_ASSERT(0 == rv);
+ /* We are done accessing the members of 'mon'. Release the
+ * reference. */
+ PR_DestroyMonitor(mon);
+ }
return PR_SUCCESS;
} /* PR_ExitMonitor */
PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout)
{
PRStatus rv;
- PRInt16 saved_entries;
+ PRUint32 saved_entries;
pthread_t saved_owner;
PR_ASSERT(mon != NULL);
- /* we'd better be locked */
- PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
- /* and the entries better be positive */
+ rv = pthread_mutex_lock(&mon->lock);
+ PR_ASSERT(0 == rv);
+ /* the entries better be positive */
PR_ASSERT(mon->entryCount > 0);
- /* and it better be by us */
+ /* and it better be owned by us */
PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
/* tuck these away 'till later */
@@ -578,43 +671,52 @@
mon->entryCount = 0;
_PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner);
_PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
-
- rv = PR_WaitCondVar(mon->cvar, timeout);
+ /*
+ * If we have pending notifies, post them now.
+ *
+ * This is not optimal. We're going to post these notifies
+ * while we're holding the lock. That means on MP systems
+ * that they are going to collide for the lock that we will
+ * hold until we actually wait.
+ */
+ if (0 != mon->notifyTimes)
+ {
+ pt_PostNotifiesFromMonitor(&mon->waitCV, mon->notifyTimes);
+ mon->notifyTimes = 0;
+ }
+ rv = pthread_cond_signal(&mon->entryCV);
+ PR_ASSERT(0 == rv);
- /* reinstate the intresting information */
+ if (timeout == PR_INTERVAL_NO_TIMEOUT)
+ rv = pthread_cond_wait(&mon->waitCV, &mon->lock);
+ else
+ rv = pt_TimedWait(&mon->waitCV, &mon->lock, timeout);
+ PR_ASSERT(0 == rv);
+
+ while (mon->entryCount != 0)
+ {
+ rv = pthread_cond_wait(&mon->entryCV, &mon->lock);
+ PR_ASSERT(0 == rv);
+ }
+ PR_ASSERT(0 == mon->notifyTimes);
+ /* reinstate the interesting information */
mon->entryCount = saved_entries;
_PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner);
+ rv = pthread_mutex_unlock(&mon->lock);
+ PR_ASSERT(0 == rv);
return rv;
} /* PR_Wait */
PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon)
{
- PR_ASSERT(NULL != mon);
- /* we'd better be locked */
- PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
- /* and the entries better be positive */
- PR_ASSERT(mon->entryCount > 0);
- /* and it better be by us */
- PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
-
- pt_PostNotifyToCvar(mon->cvar, PR_FALSE);
-
+ pt_PostNotifyToMonitor(mon, PR_FALSE);
return PR_SUCCESS;
} /* PR_Notify */
PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon)
{
- PR_ASSERT(mon != NULL);
- /* we'd better be locked */
- PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
- /* and the entries better be positive */
- PR_ASSERT(mon->entryCount > 0);
- /* and it better be by us */
- PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
-
- pt_PostNotifyToCvar(mon->cvar, PR_TRUE);
-
+ pt_PostNotifyToMonitor(mon, PR_TRUE);
return PR_SUCCESS;
} /* PR_NotifyAll */
« no previous file with comments | « nspr/pr/src/pthreads/ptio.c ('k') | nspr/pr/src/pthreads/ptthread.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698