On Tuesday 10 March 2009 03:53:01 pm Will Newton wrote:
> On Tue, Mar 10, 2009 at 12:23 PM, Denys Vlasenko
> <[email protected]> wrote:
> > On Thursday 26 February 2009 05:27:50 pm Will Newton wrote:
> >> On Thu, Feb 26, 2009 at 4:06 PM, Denys Vlasenko
> >> <[email protected]> wrote:
> >>
> >> >> Also,
> >> >> what mechanism does linuxthreads_new use to make sure it's using the
> >> >> functions in libc, rather than something overridden by the application?
> >> >
> >> > Have no idea. There is no evidence linuxthreads_new works for
> >> > any architecture. And no, I'm not going to check 12 architectures
> >> > just because you want to know it for sure. That had to be done by
> >> > the submitter of that code, at the time of submission.
> >> > Obviously, [s]he did not even test it on the most easily available
> >> > arch, x86.
> >>
> >> The new linuxthreads does work and is at this moment shipping in
> >> products. I posted a patch some time ago to update it to the latest
> >> version of linuxthreads upstream (and fix a serious bug in the
> >> process)
> >
> > Which part of the patch fixes the bug? What the bug is?
> 
> The bug is this one:
> 
> http://sourceware.org/ml/libc-ports/2005-10/msg00025.html
> 
> >> but it does not seem to have been applied. I've attached it
> >> again if anyone's interested.
> >
> > Applying it as is without understanding what I am fixing
> > would be a bit dangerous. Need your comments.
> >
> > --- metag-uClibc2/libpthread/linuxthreads/descr.h       5 Feb 2008 14:49:33 
> > -0000       1.2
> > +++ metag-uClibc2/libpthread/linuxthreads/descr.h       23 Apr 2008 
> > 13:27:00 -0000
> > @@ -123,9 +123,9 @@
> >       union dtv *dtvp;
> >       pthread_descr self;      /* Pointer to this structure */
> >       int multiple_threads;
> > -# ifdef NEED_DL_SYSINFO
> >       uintptr_t sysinfo;
> > -# endif
> > +      uintptr_t stack_guard;
> > +      uintptr_t pointer_guard;
> > ...
> > +  /* Copy the stack guard canary.  */
> > +#ifdef THREAD_COPY_STACK_GUARD
> > +  THREAD_COPY_STACK_GUARD (new_thread);
> > +#endif
> > +
> > +  /* Copy the pointer guard value.  */
> > +#ifdef THREAD_COPY_POINTER_GUARD
> > +  THREAD_COPY_POINTER_GUARD (new_thread);
> > +#endif
> >
> > these members appear to be only written to.
> > Why do you need write-only members?
> > THREAD_COPY_STACK_GUARD and THREAD_COPY_POINTER_GUARD
> > are not defined anywhere.
> 
> They are defined in the TLS code from glibc. They do not have any
> particular effect if they are not defined but they reduce the diff
> from upstream LinuxThreads.

I take it means that we can omit them and have smaller code.


> >          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);
> >
> > What does it fix? (Imagine that know almost nothing about threads).
> 
> Ok. This allows pthreads to share Sys V semaphores in order to get
> appropriate SEM_UNDO semantics.

Ok.


> > +    /* Make sure we come back here after suspend(), in case we entered
> > +       from a signal handler.  */
> > +    THREAD_SETMEM(self, p_signal_jmp, NULL);
> > +
> >
> > what does this fix?
> 
> http://sources.redhat.com/ml/libc-ports/2006-05/msg00000.html


> > -     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)))
> >
> > what does this fix? (I'd also remove __builtin_expect, it uglifies code
> > much more than it helps wrt performance).
> 
> It's trade off with reducing the diff from upstream LinuxThreads. It's
> easy to break code cleaning it up and e.g. losing a !.

So what does it fix?


> >   __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);
> >     }
> >   }
> >
> > what does this fix?
> 
> It looks like a possible race of some kind. I am not aware of the details.

Ok.


> >  #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;
> >     }
> >   }
> >
> > what does this fix?
> 
> The spinlock unlock issue. That was the main issue that I needed to
> fix with this patch set, most of the rest is just synching up with
> LinuxThreads HEAD so we can more easily compare and merge in the
> future.

I spend 20 minutes to understand that the reason here is:

        Release the spinlock *before* restarting

with emphasis on "before", because the code already does that
via "break" statement - it falls out of the while() loop
and does __pthread_release(&lock->__spinlock). But it happens
after restart(p_max_prio->thr).

What bad things currently happen if we do it other way around?



This fine code:

#if defined TEST_FOR_COMPARE_AND_SWAP
      if (!__pthread_has_cas)
#endif
#if !defined HAS_COMPARE_AND_SWAP || defined TEST_FOR_COMPARE_AND_SWAP
        *pp_max_prio = p_max_prio->next;
#endif
#if defined TEST_FOR_COMPARE_AND_SWAP
      else
#endif
#if defined HAS_COMPARE_AND_SWAP
        wait_node_dequeue(pp_head, pp_max_prio, p_max_prio);
#endif


which is  abundant in spinlock.c, IIUC can be rewritten as:


#if !defined TEST_FOR_COMPARE_AND_SWAP
# ifdef HAS_COMPARE_AND_SWAP
#  define __pthread_has_cas 1
# else
#  define __pthread_has_cas 0
# endif
#endif

      if (!__pthread_has_cas)
        *pp_max_prio = p_max_prio->next;
      else
        wait_node_dequeue(pp_head, pp_max_prio, p_max_prio);

This is "a bit" more readable. Oh well. The whole threading lib looks grim.

See 4.patch which I attached to svn, and 5.patch which contains bits I
did not apply (as they seem to be useless).

Let me know if there is some problem.
--
vda
diff -d -urpN uClibc.3/libpthread/linuxthreads/descr.h uClibc.4/libpthread/linuxthreads/descr.h
--- uClibc.3/libpthread/linuxthreads/descr.h	2009-03-05 20:44:10.000000000 +0100
+++ uClibc.4/libpthread/linuxthreads/descr.h	2009-03-12 21:39:06.000000000 +0100
@@ -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 -d -urpN uClibc.3/libpthread/linuxthreads/manager.c uClibc.4/libpthread/linuxthreads/manager.c
--- uClibc.3/libpthread/linuxthreads/manager.c	2009-03-05 20:44:10.000000000 +0100
+++ uClibc.4/libpthread/linuxthreads/manager.c	2009-03-12 21:36:20.000000000 +0100
@@ -742,15 +742,15 @@ static int pthread_handle_create(pthread
 	  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
       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 t
 #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 -d -urpN uClibc.3/libpthread/linuxthreads/pthread.c uClibc.4/libpthread/linuxthreads/pthread.c
--- uClibc.3/libpthread/linuxthreads/pthread.c	2009-03-05 20:44:10.000000000 +0100
+++ uClibc.4/libpthread/linuxthreads/pthread.c	2009-03-12 21:36:20.000000000 +0100
@@ -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 r
     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(p
 
 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
   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
      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 -d -urpN uClibc.3/libpthread/linuxthreads/specific.c uClibc.4/libpthread/linuxthreads/specific.c
--- uClibc.3/libpthread/linuxthreads/specific.c	2009-03-05 20:44:10.000000000 +0100
+++ uClibc.4/libpthread/linuxthreads/specific.c	2009-03-12 21:36:20.000000000 +0100
@@ -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 -d -urpN uClibc.3/libpthread/linuxthreads/spinlock.c uClibc.4/libpthread/linuxthreads/spinlock.c
--- uClibc.3/libpthread/linuxthreads/spinlock.c	2009-03-05 20:44:10.000000000 +0100
+++ uClibc.4/libpthread/linuxthreads/spinlock.c	2009-03-12 21:36:20.000000000 +0100
@@ -637,8 +637,20 @@ void __pthread_alt_unlock(struct _pthrea
 #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 -d -urpN uClibc.3/libpthread/linuxthreads/spinlock.h uClibc.4/libpthread/linuxthreads/spinlock.h
--- uClibc.3/libpthread/linuxthreads/spinlock.h	2009-03-05 20:44:10.000000000 +0100
+++ uClibc.4/libpthread/linuxthreads/spinlock.h	2009-03-12 21:36:20.000000000 +0100
@@ -172,7 +172,8 @@ static __inline__ int __pthread_alt_tryl
 
 /* 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(
 }
 
 
-static __inline__ long atomic_decrement(struct pthread_atomic *pa)
+static __inline__ long
+pthread_atomic_decrement (struct pthread_atomic *pa)
 {
     long oldval;
 
diff -d -urpN uClibc.3/libpthread/linuxthreads/sysdeps/i386/tls.h uClibc.4/libpthread/linuxthreads/sysdeps/i386/tls.h
--- uClibc.3/libpthread/linuxthreads/sysdeps/i386/tls.h	2009-03-05 20:44:08.000000000 +0100
+++ uClibc.4/libpthread/linuxthreads/sysdeps/i386/tls.h	2009-03-12 21:39:11.000000000 +0100
@@ -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__ */
diff -d -urpN uClibc.4/libpthread/linuxthreads/descr.h uClibc.5/libpthread/linuxthreads/descr.h
--- uClibc.4/libpthread/linuxthreads/descr.h	2009-03-12 21:39:06.000000000 +0100
+++ uClibc.5/libpthread/linuxthreads/descr.h	2009-03-12 21:06:19.000000000 +0100
@@ -124,6 +124,8 @@ struct _pthread_descr_struct
       pthread_descr self;	/* Pointer to this structure */
       int multiple_threads;
       uintptr_t sysinfo;
+      uintptr_t stack_guard;
+      uintptr_t pointer_guard;
     } data;
     void *__padding[16];
   } p_header;
@@ -191,6 +193,13 @@ struct _pthread_descr_struct
   size_t p_alloca_cutoff;	/* Maximum size which should be allocated
 				   using alloca() instead of malloc().  */
   /* New elements must be added at the end.  */
+
+  /* This member must be last.  */
+  char end_padding[];
+
+#define PTHREAD_STRUCT_END_PADDING \
+  (sizeof (struct _pthread_descr_struct)			      \
+   - offsetof (struct _pthread_descr_struct, end_padding))
 } __attribute__ ((aligned(32))); /* We need to align the structure so that
 				    doubles are aligned properly.  This is 8
 				    bytes on MIPS and 16 bytes on MIPS64.
diff -d -urpN uClibc.4/libpthread/linuxthreads/manager.c uClibc.5/libpthread/linuxthreads/manager.c
--- uClibc.4/libpthread/linuxthreads/manager.c	2009-03-12 21:36:20.000000000 +0100
+++ uClibc.5/libpthread/linuxthreads/manager.c	2009-03-12 21:06:19.000000000 +0100
@@ -679,6 +679,17 @@ static int pthread_handle_create(pthread
   new_thread->p_inheritsched = attr ? attr->__inheritsched : 0;
   new_thread->p_alloca_cutoff = stksize / 4 > __MAX_ALLOCA_CUTOFF
 				 ? __MAX_ALLOCA_CUTOFF : stksize / 4;
+
+  /* Copy the stack guard canary.  */
+#ifdef THREAD_COPY_STACK_GUARD
+  THREAD_COPY_STACK_GUARD (new_thread);
+#endif
+
+  /* Copy the pointer guard value.  */
+#ifdef THREAD_COPY_POINTER_GUARD
+  THREAD_COPY_POINTER_GUARD (new_thread);
+#endif
+
   /* Initialize the thread handle */
   __pthread_init_lock(&__pthread_handles[sseg].h_lock);
   __pthread_handles[sseg].h_descr = new_thread;
diff -d -urpN uClibc.4/libpthread/linuxthreads/pthread.c uClibc.5/libpthread/linuxthreads/pthread.c
--- uClibc.4/libpthread/linuxthreads/pthread.c	2009-03-12 21:36:20.000000000 +0100
+++ uClibc.5/libpthread/linuxthreads/pthread.c	2009-03-12 21:06:19.000000000 +0100
@@ -700,6 +700,16 @@ int __pthread_initialize_manager(void)
   mgr = &__pthread_manager_thread;
 #endif
 
+  /* Copy the stack guard canary.  */
+#ifdef THREAD_COPY_STACK_GUARD
+  THREAD_COPY_STACK_GUARD (mgr);
+#endif
+
+  /* Copy the pointer guard value.  */
+#ifdef THREAD_COPY_POINTER_GUARD
+  THREAD_COPY_POINTER_GUARD (mgr);
+#endif
+
   __pthread_manager_request = manager_pipe[1]; /* writing end */
   __pthread_manager_reader = manager_pipe[0]; /* reading end */
 
_______________________________________________
uClibc mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/uclibc

Reply via email to