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

Unified Diff: nspr/pr/src/threads/prmon.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/threads/combined/prulock.c ('k') | patches/nspr-darwin.patch » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: nspr/pr/src/threads/prmon.c
===================================================================
--- nspr/pr/src/threads/prmon.c (revision 257452)
+++ nspr/pr/src/threads/prmon.c (working copy)
@@ -8,32 +8,90 @@
/************************************************************************/
/*
+ * 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 _PR_PostNotifyToMonitor(PRMonitor *mon, PRBool broadcast)
+{
+ PR_ASSERT(mon != NULL);
+ 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 (mon->notifyTimes != -1)
+ mon->notifyTimes += 1;
+}
+
+static void _PR_PostNotifiesFromMonitor(PRCondVar *cv, PRIntn times)
+{
+ PRStatus rv;
+
+ /*
+ * Time to actually notify any waits that were affected while the monitor
+ * was entered.
+ */
+ PR_ASSERT(cv != NULL);
+ PR_ASSERT(times != 0);
+ if (times == -1) {
+ rv = PR_NotifyAllCondVar(cv);
+ PR_ASSERT(rv == PR_SUCCESS);
+ } else {
+ while (times-- > 0) {
+ rv = PR_NotifyCondVar(cv);
+ PR_ASSERT(rv == PR_SUCCESS);
+ }
+ }
+}
+
+/*
** Create a new monitor.
*/
PR_IMPLEMENT(PRMonitor*) PR_NewMonitor()
{
PRMonitor *mon;
- PRCondVar *cvar;
- PRLock *lock;
+ PRStatus rv;
+ if (!_pr_initialized) _PR_ImplicitInitialization();
+
mon = PR_NEWZAP(PRMonitor);
- if (mon) {
- lock = PR_NewLock();
- if (!lock) {
- PR_DELETE(mon);
- return 0;
- }
+ if (mon == NULL) {
+ PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
+ return NULL;
+ }
- cvar = PR_NewCondVar(lock);
- if (!cvar) {
- PR_DestroyLock(lock);
- PR_DELETE(mon);
- return 0;
- }
- mon->cvar = cvar;
- mon->name = NULL;
- }
+ rv = _PR_InitLock(&mon->lock);
+ PR_ASSERT(rv == PR_SUCCESS);
+ if (rv != PR_SUCCESS)
+ goto error1;
+
+ mon->owner = NULL;
+
+ rv = _PR_InitCondVar(&mon->entryCV, &mon->lock);
+ PR_ASSERT(rv == PR_SUCCESS);
+ if (rv != PR_SUCCESS)
+ goto error2;
+
+ rv = _PR_InitCondVar(&mon->waitCV, &mon->lock);
+ PR_ASSERT(rv == PR_SUCCESS);
+ if (rv != PR_SUCCESS)
+ goto error3;
+
+ mon->notifyTimes = 0;
+ mon->entryCount = 0;
+ mon->name = NULL;
return mon;
+
+error3:
+ _PR_FreeCondVar(&mon->entryCV);
+error2:
+ _PR_FreeLock(&mon->lock);
+error1:
+ PR_Free(mon);
+ return NULL;
}
PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name)
@@ -51,9 +109,14 @@
*/
PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon)
{
- PR_DestroyLock(mon->cvar->lock);
- PR_DestroyCondVar(mon->cvar);
- PR_DELETE(mon);
+ PR_ASSERT(mon != NULL);
+ _PR_FreeCondVar(&mon->waitCV);
+ _PR_FreeCondVar(&mon->entryCV);
+ _PR_FreeLock(&mon->lock);
+#if defined(DEBUG)
+ memset(mon, 0xaf, sizeof(PRMonitor));
+#endif
+ PR_Free(mon);
}
/*
@@ -61,12 +124,28 @@
*/
PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon)
{
- if (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) {
- mon->entryCount++;
- } else {
- PR_Lock(mon->cvar->lock);
- mon->entryCount = 1;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRStatus rv;
+
+ PR_ASSERT(mon != NULL);
+ PR_Lock(&mon->lock);
+ if (mon->entryCount != 0) {
+ if (mon->owner == me)
+ goto done;
+ while (mon->entryCount != 0) {
+ rv = PR_WaitCondVar(&mon->entryCV, PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(rv == PR_SUCCESS);
+ }
}
+ /* and now I have the monitor */
+ PR_ASSERT(mon->notifyTimes == 0);
+ PR_ASSERT(mon->owner == NULL);
+ mon->owner = me;
+
+done:
+ mon->entryCount += 1;
+ rv = PR_Unlock(&mon->lock);
+ PR_ASSERT(rv == PR_SUCCESS);
}
/*
@@ -76,16 +155,28 @@
*/
PR_IMPLEMENT(PRBool) PR_TestAndEnterMonitor(PRMonitor *mon)
{
- if (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) {
- mon->entryCount++;
- return PR_TRUE;
- } else {
- if (PR_TestAndLock(mon->cvar->lock)) {
- mon->entryCount = 1;
- return PR_TRUE;
- }
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRStatus rv;
+
+ PR_ASSERT(mon != NULL);
+ PR_Lock(&mon->lock);
+ if (mon->entryCount != 0) {
+ if (mon->owner == me)
+ goto done;
+ rv = PR_Unlock(&mon->lock);
+ PR_ASSERT(rv == PR_SUCCESS);
+ return PR_FALSE;
}
- return PR_FALSE;
+ /* and now I have the monitor */
+ PR_ASSERT(mon->notifyTimes == 0);
+ PR_ASSERT(mon->owner == NULL);
+ mon->owner = me;
+
+done:
+ mon->entryCount += 1;
+ rv = PR_Unlock(&mon->lock);
+ PR_ASSERT(rv == PR_SUCCESS);
+ return PR_TRUE;
}
/*
@@ -93,12 +184,36 @@
*/
PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon)
{
- if (mon->cvar->lock->owner != _PR_MD_CURRENT_THREAD()) {
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRStatus rv;
+
+ PR_ASSERT(mon != NULL);
+ PR_Lock(&mon->lock);
+ /* the entries should be > 0 and we'd better be the owner */
+ PR_ASSERT(mon->entryCount > 0);
+ PR_ASSERT(mon->owner == me);
+ if (mon->entryCount == 0 || mon->owner != me)
+ {
+ rv = PR_Unlock(&mon->lock);
+ PR_ASSERT(rv == PR_SUCCESS);
return PR_FAILURE;
}
- if (--mon->entryCount == 0) {
- return PR_Unlock(mon->cvar->lock);
+
+ mon->entryCount -= 1; /* reduce by one */
+ if (mon->entryCount == 0)
+ {
+ /* and if it transitioned to zero - notify an entry waiter */
+ /* make the owner unknown */
+ mon->owner = NULL;
+ if (mon->notifyTimes != 0) {
+ _PR_PostNotifiesFromMonitor(&mon->waitCV, mon->notifyTimes);
+ mon->notifyTimes = 0;
+ }
+ rv = PR_NotifyCondVar(&mon->entryCV);
+ PR_ASSERT(rv == PR_SUCCESS);
}
+ rv = PR_Unlock(&mon->lock);
+ PR_ASSERT(rv == PR_SUCCESS);
return PR_SUCCESS;
}
@@ -108,17 +223,29 @@
*/
PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon)
{
- return (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) ?
- mon->entryCount : 0;
+ PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRStatus rv;
+ PRIntn count = 0;
+
+ PR_Lock(&mon->lock);
+ if (mon->owner == me)
+ count = mon->entryCount;
+ rv = PR_Unlock(&mon->lock);
+ PR_ASSERT(rv == PR_SUCCESS);
+ return count;
}
-/*
-** If the current thread is in |mon|, this assertion is guaranteed to
-** succeed. Otherwise, the behavior of this function is undefined.
-*/
PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon)
{
- PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(mon->cvar->lock);
+#if defined(DEBUG) || defined(FORCE_PR_ASSERT)
+ PRStatus rv;
+
+ PR_Lock(&mon->lock);
+ PR_ASSERT(mon->entryCount != 0 &&
+ mon->owner == _PR_MD_CURRENT_THREAD());
+ rv = PR_Unlock(&mon->lock);
+ PR_ASSERT(rv == PR_SUCCESS);
+#endif
}
/*
@@ -135,25 +262,50 @@
**
** Returns PR_FAILURE if the caller has not locked the lock associated
** with the condition variable.
-** This routine can return PR_PENDING_INTERRUPT if the waiting thread
+** This routine can return PR_PENDING_INTERRUPT_ERROR if the waiting thread
** has been interrupted.
*/
PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks)
{
- PRUintn entryCount;
- PRStatus status;
- PRThread *me = _PR_MD_CURRENT_THREAD();
+ PRStatus rv;
+ PRUint32 saved_entries;
+ PRThread *saved_owner;
- if (mon->cvar->lock->owner != me) return PR_FAILURE;
+ PR_ASSERT(mon != NULL);
+ PR_Lock(&mon->lock);
+ /* the entries better be positive */
+ PR_ASSERT(mon->entryCount > 0);
+ /* and it better be owned by us */
+ PR_ASSERT(mon->owner == _PR_MD_CURRENT_THREAD()); /* XXX return failure */
- entryCount = mon->entryCount;
+ /* tuck these away 'till later */
+ saved_entries = mon->entryCount;
mon->entryCount = 0;
+ saved_owner = mon->owner;
+ mon->owner = NULL;
+ /* If we have pending notifies, post them now. */
+ if (mon->notifyTimes != 0) {
+ _PR_PostNotifiesFromMonitor(&mon->waitCV, mon->notifyTimes);
+ mon->notifyTimes = 0;
+ }
+ rv = PR_NotifyCondVar(&mon->entryCV);
+ PR_ASSERT(rv == PR_SUCCESS);
- status = _PR_WaitCondVar(me, mon->cvar, mon->cvar->lock, ticks);
+ rv = PR_WaitCondVar(&mon->waitCV, ticks);
+ PR_ASSERT(rv == PR_SUCCESS);
- mon->entryCount = entryCount;
+ while (mon->entryCount != 0) {
+ rv = PR_WaitCondVar(&mon->entryCV, PR_INTERVAL_NO_TIMEOUT);
+ PR_ASSERT(rv == PR_SUCCESS);
+ }
+ PR_ASSERT(mon->notifyTimes == 0);
+ /* reinstate the interesting information */
+ mon->entryCount = saved_entries;
+ mon->owner = saved_owner;
- return status;
+ rv = PR_Unlock(&mon->lock);
+ PR_ASSERT(rv == PR_SUCCESS);
+ return rv;
}
/*
@@ -163,9 +315,7 @@
*/
PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon)
{
- PRThread *me = _PR_MD_CURRENT_THREAD();
- if (mon->cvar->lock->owner != me) return PR_FAILURE;
- PR_NotifyCondVar(mon->cvar);
+ _PR_PostNotifyToMonitor(mon, PR_FALSE);
return PR_SUCCESS;
}
@@ -176,9 +326,7 @@
*/
PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon)
{
- PRThread *me = _PR_MD_CURRENT_THREAD();
- if (mon->cvar->lock->owner != me) return PR_FAILURE;
- PR_NotifyAllCondVar(mon->cvar);
+ _PR_PostNotifyToMonitor(mon, PR_TRUE);
return PR_SUCCESS;
}
@@ -188,10 +336,9 @@
{
PRUint32 nb;
- if (mon->cvar->lock->owner) {
+ if (mon->owner) {
nb = PR_snprintf(buf, buflen, "[%p] owner=%d[%p] count=%ld",
- mon, mon->cvar->lock->owner->id,
- mon->cvar->lock->owner, mon->entryCount);
+ mon, mon->owner->id, mon->owner, mon->entryCount);
} else {
nb = PR_snprintf(buf, buflen, "[%p]", mon);
}
« no previous file with comments | « nspr/pr/src/threads/combined/prulock.c ('k') | patches/nspr-darwin.patch » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698