public inbox for libc-ports@sourceware.org
 help / color / mirror / Atom feed
From: Carlos O'Donell <carlos@systemhalted.org>
To: "Joseph S. Myers" <joseph@codesourcery.com>
Cc: Jeff Law <law@redhat.com>, Mike Frysinger <vapier@gentoo.org>,
	 libc-alpha <libc-alpha@sourceware.org>,
	libc-ports@sourceware.org,
	 Marcus Shawcroft <marcus.shawcroft@linaro.org>
Subject: Re: [PATCH] Memory fencing problem in pthread cancellation
Date: Mon, 14 Jan 2013 22:58:00 -0000	[thread overview]
Message-ID: <50F48DA4.4000407@systemhalted.org> (raw)
In-Reply-To: <Pine.LNX.4.64.1301142218260.19709@digraph.polyomino.org.uk>

On 01/14/2013 05:21 PM, Joseph S. Myers wrote:
> On Mon, 14 Jan 2013, Carlos O'Donell wrote:
> 
>> diff --git a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c
>> index 58ca9ac..d7ac847 100644
>> --- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c
>> +++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c
>> @@ -104,6 +104,7 @@ asm (
>>  "      mov     r6, r0\n"
>>  "      cmp     r3, #0\n"
>>  "      beq     4f\n"
>> +       atomic_asm_full_barrier()
>>  "5:    mov     r0, r6\n"
>>  "      ldmfd   sp!, {r4, r5, r6, lr}\n"
>>  "      " CFI_ADJUST_CFA_OFFSET (-16) "\n"
>> @@ -123,7 +124,7 @@ asm (
>>  #else
>>  "1:    .word   _GLOBAL_OFFSET_TABLE_ - 3b - 8\n"
>>  #endif
>> -"2:    .word   libgcc_s_resume(GOTOFF)\n"
>> +"2:    .word   libgcc_s_handle(GOTOFF)\n"
>>  "      .size   _Unwind_Resume, .-_Unwind_Resume\n"
>>  );
> 
> That last change doesn't seem right.  Note the subsequent "bx r3" if r3 
> isn't zero.  If you want to test libgcc_s_handle for being zero, you then 
> need, separately (after the barrier?) to load the libgcc_s_resume value.

You are correct, we need another entry for libgcc_s_resume, and we need
to load that after the barrier, otherwise we won't call libgcc_s_resume.

Something like this:

diff --git a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c
index 58ca9ac..1e03b13 100644
--- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c
+++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-forcedunwind.c
@@ -104,7 +104,12 @@ asm (
 "      mov     r6, r0\n"
 "      cmp     r3, #0\n"
 "      beq     4f\n"
-"5:    mov     r0, r6\n"
+       atomic_asm_full_barrier()
+"5:    ldr     r4, 6f\n"
+"      ldr     r5, 7f\n"
+"8:    add     r4, pc, r4\n"
+"      ldr     r3, [r4, r5]\n"
+"      mov     r0, r6\n"
 "      ldmfd   sp!, {r4, r5, r6, lr}\n"
 "      " CFI_ADJUST_CFA_OFFSET (-16) "\n"
 "      " CFI_RESTORE (r4) "\n"
@@ -123,7 +128,13 @@ asm (
 #else
 "1:    .word   _GLOBAL_OFFSET_TABLE_ - 3b - 8\n"
 #endif
-"2:    .word   libgcc_s_resume(GOTOFF)\n"
+"2:    .word   libgcc_s_handle(GOTOFF)\n"
+#ifdef __thumb2__
+"6:    .word   _GLOBAL_OFFSET_TABLE_ - 8b - 4\n"
+#else
+"6:    .word   _GLOBAL_OFFSET_TABLE_ - 8b - 8\n"
+#endif
+"7:    .word   libgcc_s_resume(GOTOFF)\n"
 "      .size   _Unwind_Resume, .-_Unwind_Resume\n"
 );
---

I was hoping that someone with an ARM cross-build environment
could test this and tell us how it goes? :-)

> (Whatever you do in unwind-forcedunwind.c, presumably much the same change 
> should go in unwind-resume.c as well.)

Yes, all the same changes are required in:

./sysdeps/gnu/unwind-resume.c
./ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c

I'd say something like this?

diff --git a/sysdeps/gnu/unwind-resume.c b/sysdeps/gnu/unwind-resume.c
index df845cd..fecfc94 100644
--- a/sysdeps/gnu/unwind-resume.c
+++ b/sysdeps/gnu/unwind-resume.c
@@ -21,6 +21,7 @@
 #include <unwind.h>
 #include <gnu/lib-names.h>
 
+static void *libgcc_s_handle;
 static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
 static _Unwind_Reason_Code (*libgcc_s_personality)
   (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
@@ -41,13 +42,25 @@ init (void)
 
   libgcc_s_resume = resume;
   libgcc_s_personality = personality;
+  atomic_write_barrier ();
+  /* At the point at which any thread writes the handle
+     to libgcc_s_handle, the initialization is complete.
+     The writing of libgcc_s_handle is atomic. All other
+     threads reading libgcc_s_handle do so atomically. Any
+     thread that does not execute this function must issue
+     a read barrier to ensure that all of the above has
+     actually completed and that the values of the
+     function pointers are correct.   */
+  libgcc_s_handle = handle;
 }
 
 void
 _Unwind_Resume (struct _Unwind_Exception *exc)
 {
-  if (__builtin_expect (libgcc_s_resume == NULL, 0))
+  if (__builtin_expect (libgcc_s_handle == NULL, 0))
     init ();
+  else
+    atomic_read_barrier ();
   libgcc_s_resume (exc);
 }
 
@@ -57,8 +70,10 @@ __gcc_personality_v0 (int version, _Unwind_Action actions,
                       struct _Unwind_Exception *ue_header,
                       struct _Unwind_Context *context)
 {
-  if (__builtin_expect (libgcc_s_personality == NULL, 0))
+  if (__builtin_expect (libgcc_s_handle == NULL, 0))
     init ();
+  else
+    atomic_read_barrier ();
   return libgcc_s_personality (version, actions, exception_class,
                               ue_header, context);
 }
---
diff --git a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c
index 0a3ad95..a67190d 100644
--- a/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c
+++ b/ports/sysdeps/unix/sysv/linux/arm/nptl/unwind-resume.c
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <unwind.h>
 
+static void *libgcc_s_handle;
 static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
 static _Unwind_Reason_Code (*libgcc_s_personality)
   (_Unwind_State, struct _Unwind_Exception *, struct _Unwind_Context *);
@@ -41,6 +42,16 @@ init (void)
 
   libgcc_s_resume = resume;
   libgcc_s_personality = personality;
+  atomic_write_barrier ();
+  /* At the point at which any thread writes the handle
+     to libgcc_s_handle, the initialization is complete.
+     The writing of libgcc_s_handle is atomic. All other
+     threads reading libgcc_s_handle do so atomically. Any
+     thread that does not execute this function must issue
+     a read barrier to ensure that all of the above has
+     actually completed and that the values of the
+     function pointers are correct.   */
+  libgcc_s_handle = handle;
 }
 
 /* It's vitally important that _Unwind_Resume not have a stack frame; the
@@ -67,7 +78,12 @@ asm (
 "      mov     r6, r0\n"
 "      cmp     r3, #0\n"
 "      beq     4f\n"
-"5:    mov     r0, r6\n"
+       atomic_asm_full_barrier()
+"5:    ldr     r4, 6f\n"
+"      ldr     r5, 7f\n"
+"8:    add     r4, pc, r4\n"
+"      ldr     r3, [r4, r5]\n"
+"      mov     r0, r6\n"
 "      ldmfd   sp!, {r4, r5, r6, lr}\n"
 "      " CFI_ADJUST_CFA_OFFSET (-16) "\n"
 "      " CFI_RESTORE (r4) "\n"
@@ -76,7 +92,7 @@ asm (
 "      " CFI_RESTORE (lr) "\n"
 "      bx      r3\n"
 "      " CFI_RESTORE_STATE "\n"
-"4:    bl      init\n"
+"4:    bl      pthread_cancel_init\n"
 "      ldr     r3, [r4, r5]\n"
 "      b       5b\n"
 "      " CFI_ENDPROC "\n"
@@ -86,7 +102,13 @@ asm (
 #else
 "1:    .word   _GLOBAL_OFFSET_TABLE_ - 3b - 8\n"
 #endif
-"2:    .word   libgcc_s_resume(GOTOFF)\n"
+"2:    .word   libgcc_s_handle(GOTOFF)\n"
+#ifdef __thumb2__
+"6:    .word   _GLOBAL_OFFSET_TABLE_ - 8b - 4\n"
+#else
+"6:    .word   _GLOBAL_OFFSET_TABLE_ - 8b - 8\n"
+#endif
+"7:    .word   libgcc_s_resume(GOTOFF)\n"
 "      .size   _Unwind_Resume, .-_Unwind_Resume\n"
 );
 
@@ -95,7 +117,9 @@ __gcc_personality_v0 (_Unwind_State state,
                      struct _Unwind_Exception *ue_header,
                      struct _Unwind_Context *context)
 {
-  if (__builtin_expect (libgcc_s_personality == NULL, 0))
+  if (__builtin_expect (libgcc_s_handle == NULL, 0))
     init ();
+  else
+    atomic_read_barrier ();
   return libgcc_s_personality (state, ue_header, context);
 }
---

It looks like the assembly in unwind-resume.c and unwind-forcedunwind.c
are identical and should be shared?

Cheers,
Carlos.

  reply	other threads:[~2013-01-14 22:58 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <50F46969.1000305@redhat.com>
2013-01-14 22:11 ` Carlos O'Donell
2013-01-14 22:21   ` Joseph S. Myers
2013-01-14 22:58     ` Carlos O'Donell [this message]
2013-01-14 23:50       ` Joseph S. Myers
2013-01-31 22:08       ` Jeff Law
2013-01-31 22:05   ` Jeff Law

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=50F48DA4.4000407@systemhalted.org \
    --to=carlos@systemhalted.org \
    --cc=joseph@codesourcery.com \
    --cc=law@redhat.com \
    --cc=libc-alpha@sourceware.org \
    --cc=libc-ports@sourceware.org \
    --cc=marcus.shawcroft@linaro.org \
    --cc=vapier@gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).