[PATCH 4/6] nptl: Revert TPP updates on pthread_mutex_*lock failure (bug 34546)

Florian Weimer <[email protected]>
Newsgroups gmane.comp.lib.glibc.alpha
Message-ID <d21729e2333efa8a9545ed65bf4b743389cd6bc9.1787168028.git.fweimer@redhat.com>
Also fix __pthread_tpp_change_priority to undo changes to the priomap
array if any of the scheduler system calls fail.
---
 nptl/pthread_mutex_lock.c      | 12 +++++-------
 nptl/pthread_mutex_timedlock.c | 21 +++++++--------------
 nptl/pthread_mutex_trylock.c   | 12 +++++-------
 nptl/tpp.c                     | 19 +++++++++++++++++++
 sysdeps/nptl/pthreadP.h        |  4 ++++
 5 files changed, 40 insertions(+), 28 deletions(-)

diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c
index a697f2b6ca..82ffc4204f 100644
--- a/nptl/pthread_mutex_lock.c
+++ b/nptl/pthread_mutex_lock.c
@@ -534,15 +534,13 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)
 			  >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
 
 	    if (__pthread_current_priority () > ceiling)
-	      {
-		if (oldprio != -1)
-		  __pthread_tpp_change_priority (oldprio, -1);
-		return EINVAL;
-	      }
+	      return __pthread_mutex_priority_error (EINVAL, oldprio);
 
 	    int retval = __pthread_tpp_change_priority (oldprio, ceiling);
-	    if (retval)
-	      return retval;
+	    if (retval != 0)
+	      /* Undo the adjustment from the previous loop iteration
+		 (if any, first iteration has -1 and skips adjustment).  */
+	      return __pthread_mutex_priority_error (retval, oldprio);
 
 	    ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
 	    oldprio = ceiling;
diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c
index 3b8bb1ddfd..2a44108736 100644
--- a/nptl/pthread_mutex_timedlock.c
+++ b/nptl/pthread_mutex_timedlock.c
@@ -468,17 +468,13 @@ __pthread_mutex_clocklock_common (pthread_mutex_t *mutex,
 			  >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
 
 	    if (__pthread_current_priority () > ceiling)
-	      {
-		result = EINVAL;
-	      failpp:
-		if (oldprio != -1)
-		  __pthread_tpp_change_priority (oldprio, -1);
-		return result;
-	      }
+	      return __pthread_mutex_priority_error (EINVAL, oldprio);
 
 	    result = __pthread_tpp_change_priority (oldprio, ceiling);
-	    if (result)
-	      return result;
+	    if (result != 0)
+	      /* Undo the adjustment from the previous loop iteration
+		 (if any, first iteration has -1 and skips adjustment).  */
+	      return __pthread_mutex_priority_error (result, oldprio);
 
 	    ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
 	    oldprio = ceiling;
@@ -504,16 +500,13 @@ __pthread_mutex_clocklock_common (pthread_mutex_t *mutex,
 		  {
 		    /* Reject invalid timeouts.  */
 		    if (! valid_nanoseconds (abstime->tv_nsec))
-		      {
-			result = EINVAL;
-			goto failpp;
-		      }
+		      return __pthread_mutex_priority_error (EINVAL, oldprio);
 
 		    int e = __futex_abstimed_wait64 (
 		      (unsigned int *) &mutex->__data.__lock, ceilval | 2,
 		      clockid, abstime, PTHREAD_MUTEX_PSHARED (mutex));
 		    if (e == ETIMEDOUT || e == EOVERFLOW)
-		      return e;
+		      return __pthread_mutex_priority_error (e, oldprio);
 		  }
 	      }
 	    while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
diff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c
index 236b3228dd..15786fda09 100644
--- a/nptl/pthread_mutex_trylock.c
+++ b/nptl/pthread_mutex_trylock.c
@@ -396,15 +396,13 @@ ___pthread_mutex_trylock (pthread_mutex_t *mutex)
 			  >> PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
 
 	    if (__pthread_current_priority () > ceiling)
-	      {
-		if (oldprio != -1)
-		  __pthread_tpp_change_priority (oldprio, -1);
-		return EINVAL;
-	      }
+	      return __pthread_mutex_priority_error (EINVAL, oldprio);
 
 	    int retval = __pthread_tpp_change_priority (oldprio, ceiling);
-	    if (retval)
-	      return retval;
+	    if (retval != 0)
+	      /* Undo the adjustment from the previous loop iteration
+		 (if any, first iteration has -1 and skips adjustment).  */
+	      return __pthread_mutex_priority_error (retval, oldprio);
 
 	    ceilval = ceiling << PTHREAD_MUTEX_PRIO_CEILING_SHIFT;
 	    oldprio = ceiling;
diff --git a/nptl/tpp.c b/nptl/tpp.c
index 2674f36564..627ef1dc6d 100644
--- a/nptl/tpp.c
+++ b/nptl/tpp.c
@@ -152,6 +152,17 @@ __pthread_tpp_change_priority (int previous_prio, int new_prio)
 	}
     }
 
+  /* Roll back the TPP bookkeeping information if the scheduler
+     reconfiguration failed.  */
+  if (result != 0)
+    {
+      tpp->priomax = priomax;
+      if (new_prio != -1)
+	--tpp->priomap[new_prio - fifo_min_prio];
+      if (previous_prio != -1)
+	++tpp->priomap[previous_prio - fifo_min_prio];
+    }
+
   lll_unlock (self->lock, LLL_PRIVATE);
 
   return result;
@@ -196,3 +207,11 @@ __pthread_current_priority (void)
   return result;
 }
 libc_hidden_def (__pthread_current_priority)
+
+int
+__pthread_mutex_priority_error (int err, int oldprio)
+{
+  if (oldprio != -1)
+    __pthread_tpp_change_priority (oldprio, -1);
+  return err;
+}
diff --git a/sysdeps/nptl/pthreadP.h b/sysdeps/nptl/pthreadP.h
index de432d4032..982705aee5 100644
--- a/sysdeps/nptl/pthreadP.h
+++ b/sysdeps/nptl/pthreadP.h
@@ -211,6 +211,10 @@ libc_hidden_proto (__pthread_tpp_change_priority)
 extern int __pthread_current_priority (void);
 libc_hidden_proto (__pthread_current_priority)
 
+/* If OLDPRIO is not -1, undo its TPP priority change.  Return ERR.  */
+int __pthread_mutex_priority_error (int err, int oldprio) attribute_hidden;
+
+
 /* This will not catch all invalid descriptors but is better than
    nothing.  And if the test triggers the thread descriptor is
    guaranteed to be invalid.  */
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.