0001-linuxthreads-fixes-from-Will-Newton-will.newton-AT-g.patch 11 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
From 52c9ef85a65f4dc25a4d1ff79c0fba1ed53ef43a Mon Sep 17 00:00:00 2001
From: Denis Vlasenko <vda.linux@googlemail.com>
Date: Thu, 12 Mar 2009 20:56:59 +0000
Subject: [PATCH 01/39] linuxthreads fixes from Will Newton (will.newton AT gmail.com):
 * share Sys V semaphores in order to get appropriate SEM_UNDO semantics.
 * correct guardaddr in pthread_free() for TLS case
 * move spinlock unlocking before restart()
 * When exit was called from a signal handler, the restart
   from the manager processing the exit request instead restarted the thread
   in pthread_cond_timedwait.
   (see http://sources.redhat.com/ml/libc-ports/2006-05/msg00000.html)

---
 libpthread/linuxthreads/descr.h            |    2 --
 libpthread/linuxthreads/manager.c          |   15 ++++++++-------
 libpthread/linuxthreads/pthread.c          |   26 +++++++++++++++-----------
 libpthread/linuxthreads/specific.c         |   10 ++++++----
 libpthread/linuxthreads/spinlock.c         |   14 +++++++++++++-
 libpthread/linuxthreads/spinlock.h         |    6 ++++--
 libpthread/linuxthreads/sysdeps/i386/tls.h |    2 --
 7 files changed, 46 insertions(+), 29 deletions(-)

diff --git a/libpthread/linuxthreads/descr.h b/libpthread/linuxthreads/descr.h
index 24ec30b..47a9acd 100644
--- a/libpthread/linuxthreads/descr.h
+++ b/libpthread/linuxthreads/descr.h
@@ -123,9 +123,7 @@ struct _pthread_descr_struct
       union dtv *dtvp;
       pthread_descr self;	/* Pointer to this structure */
       int multiple_threads;
-# ifdef NEED_DL_SYSINFO
       uintptr_t sysinfo;
-# endif
     } data;
     void *__padding[16];
   } p_header;
diff --git a/libpthread/linuxthreads/manager.c b/libpthread/linuxthreads/manager.c
index be1e8d2..b068d6c 100644
--- a/libpthread/linuxthreads/manager.c
+++ b/libpthread/linuxthreads/manager.c
@@ -742,15 +742,15 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
 	  pid = __clone2(pthread_start_thread_event,
   		 (void **)new_thread_bottom,
 			 (char *)stack_addr - new_thread_bottom,
-			 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+			 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM |
 			 __pthread_sig_cancel, new_thread);
 #elif _STACK_GROWS_UP
 	  pid = __clone(pthread_start_thread_event, (void *) new_thread_bottom,
-			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM |
 			__pthread_sig_cancel, new_thread);
 #else
 	  pid = __clone(pthread_start_thread_event, stack_addr,
-			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM |
 			__pthread_sig_cancel, new_thread);
 #endif
 	  saved_errno = errno;
@@ -783,15 +783,15 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
       pid = __clone2(pthread_start_thread,
 		     (void **)new_thread_bottom,
                      (char *)stack_addr - new_thread_bottom,
-		     CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+		     CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM |
 		     __pthread_sig_cancel, new_thread);
 #elif _STACK_GROWS_UP
       pid = __clone(pthread_start_thread, (void *) new_thread_bottom,
-		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM |
 		    __pthread_sig_cancel, new_thread);
 #else
       pid = __clone(pthread_start_thread, stack_addr,
-		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND |
+		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM |
 		    __pthread_sig_cancel, new_thread);
 #endif /* !NEED_SEPARATE_REGISTER_STACK */
       saved_errno = errno;
@@ -892,10 +892,11 @@ static void pthread_free(pthread_descr th)
 #ifdef _STACK_GROWS_UP
 # ifdef USE_TLS
       size_t stacksize = guardaddr - th->p_stackaddr;
+      guardaddr = th->p_stackaddr;
 # else
       size_t stacksize = guardaddr - (char *)th;
-# endif
       guardaddr = (char *)th;
+# endif
 #else
       /* Guardaddr is always set, even if guardsize is 0.  This allows
 	 us to compute everything else.  */
diff --git a/libpthread/linuxthreads/pthread.c b/libpthread/linuxthreads/pthread.c
index 91333f2..4d1d906 100644
--- a/libpthread/linuxthreads/pthread.c
+++ b/libpthread/linuxthreads/pthread.c
@@ -740,17 +740,17 @@ int __pthread_initialize_manager(void)
 	  pid = __clone2(__pthread_manager_event,
 			 (void **) __pthread_manager_thread_bos,
 			 THREAD_MANAGER_STACK_SIZE,
-			 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
+			 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM,
 			 mgr);
 #elif _STACK_GROWS_UP
 	  pid = __clone(__pthread_manager_event,
 			(void **) __pthread_manager_thread_bos,
-			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
+			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM,
 			mgr);
 #else
 	  pid = __clone(__pthread_manager_event,
 			(void **) __pthread_manager_thread_tos,
-			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
+			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM,
 			mgr);
 #endif
 
@@ -780,13 +780,13 @@ int __pthread_initialize_manager(void)
 #ifdef NEED_SEPARATE_REGISTER_STACK
       pid = __clone2(__pthread_manager, (void **) __pthread_manager_thread_bos,
 		     THREAD_MANAGER_STACK_SIZE,
-		     CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, mgr);
+		     CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM, mgr);
 #elif _STACK_GROWS_UP
       pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_bos,
-		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, mgr);
+		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM, mgr);
 #else
       pid = __clone(__pthread_manager, (void **) __pthread_manager_thread_tos,
-		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, mgr);
+		    CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM, mgr);
 #endif
     }
   if (__builtin_expect (pid, 0) == -1) {
@@ -972,6 +972,10 @@ static void pthread_onexit_process(int retcode, void *arg)
     struct pthread_request request;
     pthread_descr self = thread_self();
 
+    /* Make sure we come back here after suspend(), in case we entered
+       from a signal handler.  */
+    THREAD_SETMEM(self, p_signal_jmp, NULL);
+
     request.req_thread = self;
     request.req_kind = REQ_PROCESS_EXIT;
     request.req_args.exit.code = retcode;
@@ -1201,13 +1205,13 @@ void __pthread_wait_for_restart_signal(pthread_descr self)
 
 void __pthread_restart_old(pthread_descr th)
 {
-  if (atomic_increment(&th->p_resume_count) == -1)
+  if (pthread_atomic_increment(&th->p_resume_count) == -1)
     kill(th->p_pid, __pthread_sig_restart);
 }
 
 void __pthread_suspend_old(pthread_descr self)
 {
-  if (atomic_decrement(&self->p_resume_count) <= 0)
+  if (pthread_atomic_decrement(&self->p_resume_count) <= 0)
     __pthread_wait_for_restart_signal(self);
 }
 
@@ -1218,7 +1222,7 @@ __pthread_timedsuspend_old(pthread_descr self, const struct timespec *abstime)
   int was_signalled = 0;
   sigjmp_buf jmpbuf;
 
-  if (atomic_decrement(&self->p_resume_count) == 0) {
+  if (pthread_atomic_decrement(&self->p_resume_count) == 0) {
     /* Set up a longjmp handler for the restart signal, unblock
        the signal and sleep. */
 
@@ -1275,9 +1279,9 @@ __pthread_timedsuspend_old(pthread_descr self, const struct timespec *abstime)
      being delivered. */
 
   if (!was_signalled) {
-    if (atomic_increment(&self->p_resume_count) != -1) {
+    if (pthread_atomic_increment(&self->p_resume_count) != -1) {
       __pthread_wait_for_restart_signal(self);
-      atomic_decrement(&self->p_resume_count); /* should be zero now! */
+      pthread_atomic_decrement(&self->p_resume_count); /* should be zero now! */
       /* woke spontaneously and consumed restart signal */
       return 1;
     }
diff --git a/libpthread/linuxthreads/specific.c b/libpthread/linuxthreads/specific.c
index 92eec3d..764bf1e 100644
--- a/libpthread/linuxthreads/specific.c
+++ b/libpthread/linuxthreads/specific.c
@@ -104,13 +104,14 @@ int pthread_key_delete(pthread_key_t key)
      that if the key is reallocated later by pthread_key_create, its
      associated values will be NULL in all threads.
 
-     If no threads have been created yet, clear it just in the
-     current thread.  */
+     If no threads have been created yet, or if we are exiting, clear
+     it just in the current thread.  */
 
   struct pthread_key_delete_helper_args args;
   args.idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
   args.idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
-  if (__pthread_manager_request != -1)
+  if (__pthread_manager_request != -1
+      && !(__builtin_expect (__pthread_exit_requested, 0)))
     {
       struct pthread_request request;
 
@@ -203,8 +204,9 @@ void __pthread_destroy_specifics()
   __pthread_lock(THREAD_GETMEM(self, p_lock), self);
   for (i = 0; i < PTHREAD_KEY_1STLEVEL_SIZE; i++) {
     if (THREAD_GETMEM_NC(self, p_specific[i]) != NULL) {
-      free(THREAD_GETMEM_NC(self, p_specific[i]));
+      void *p = THREAD_GETMEM_NC(self, p_specific[i]);
       THREAD_SETMEM_NC(self, p_specific[i], NULL);
+      free(p);
     }
   }
   __pthread_unlock(THREAD_GETMEM(self, p_lock));
diff --git a/libpthread/linuxthreads/spinlock.c b/libpthread/linuxthreads/spinlock.c
index f325402..f0cf19c 100644
--- a/libpthread/linuxthreads/spinlock.c
+++ b/libpthread/linuxthreads/spinlock.c
@@ -637,8 +637,20 @@ void __pthread_alt_unlock(struct _pthread_fastlock *lock)
 #if defined HAS_COMPARE_AND_SWAP
 	wait_node_dequeue(pp_head, pp_max_prio, p_max_prio);
 #endif
+
+      /* Release the spinlock *before* restarting.  */
+#if defined TEST_FOR_COMPARE_AND_SWAP
+      if (!__pthread_has_cas)
+#endif
+#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
+	{
+	  __pthread_release(&lock->__spinlock);
+	}
+#endif
+
       restart(p_max_prio->thr);
-      break;
+
+      return;
     }
   }
 
diff --git a/libpthread/linuxthreads/spinlock.h b/libpthread/linuxthreads/spinlock.h
index 210ead4..2a3c227 100644
--- a/libpthread/linuxthreads/spinlock.h
+++ b/libpthread/linuxthreads/spinlock.h
@@ -172,7 +172,8 @@ static __inline__ int __pthread_alt_trylock (struct _pthread_fastlock * lock)
 
 /* Operations on pthread_atomic, which is defined in internals.h */
 
-static __inline__ long atomic_increment(struct pthread_atomic *pa)
+static __inline__ long
+pthread_atomic_increment (struct pthread_atomic *pa)
 {
     long oldval;
 
@@ -184,7 +185,8 @@ static __inline__ long atomic_increment(struct pthread_atomic *pa)
 }
 
 
-static __inline__ long atomic_decrement(struct pthread_atomic *pa)
+static __inline__ long
+pthread_atomic_decrement (struct pthread_atomic *pa)
 {
     long oldval;
 
diff --git a/libpthread/linuxthreads/sysdeps/i386/tls.h b/libpthread/linuxthreads/sysdeps/i386/tls.h
index 2abd3a0..4c9b680 100644
--- a/libpthread/linuxthreads/sysdeps/i386/tls.h
+++ b/libpthread/linuxthreads/sysdeps/i386/tls.h
@@ -46,9 +46,7 @@ typedef struct
   dtv_t *dtv;
   void *self;		/* Pointer to the thread descriptor.  */
   int multiple_threads;
-#ifdef NEED_DL_SYSINFO
   uintptr_t sysinfo;
-#endif
 } tcbhead_t;
 
 #else /* __ASSEMBLER__ */
-- 
1.6.3.2