public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Thomas Neumann <thomas.neumann@in.tum.de>
To: Jason Merrill <jason@redhat.com>, gcc-patches@gcc.gnu.org
Cc: Florian Weimer <fweimer@redhat.com>,
	Jakub Jelinek <jakub@redhat.com>,
	Jonathan Wakely <jwakely.gcc@gmail.com>,
	Thomas Rodgers <trodgers@redhat.com>
Subject: Re: [PATCH v3] eliminate mutex in fast path of __register_frame
Date: Mon, 12 Sep 2022 20:03:35 +0200	[thread overview]
Message-ID: <3740268a-c99f-c395-9445-15cf33e3555f@in.tum.de> (raw)
In-Reply-To: <e0aec20f-e2d4-e609-d818-8901e4d93f0a@redhat.com>

Thanks for your feedback, I will update the patch in the next few days, 
addressing the comments and reorganizing classify_object_over_fdes. 
Concerning your question:

>> +
>> +restart:
>> +  struct btree_node *iter;
>> +  uintptr_t lock;
>> +  {
>> +    // Accessing the root node requires defending against concurrent 
>> pointer
>> +    // changes Thus we couple rootLock -> lock on root node -> 
>> validate rootLock
> 
> Can you elaborate a bit more in the comment on why it's necessary and 
> sufficient to validate the containing node after "locking" the child node?
> 
>> +    if (!version_lock_lock_optimistic (&(t->root_lock), &lock))
>> +      goto restart;
>> +    iter = RLOAD (t->root);
>> +    if (!version_lock_validate (&(t->root_lock), lock))
>> +      goto restart;
>> +    if (!iter)
>> +      return NULL;
>> +    uintptr_t child_lock;
>> +    if ((!btree_node_lock_optimistic (iter, &child_lock))
>> +    || (!version_lock_validate (&(t->root_lock), lock)))
>> +      goto restart;
>> +    lock = child_lock;
>> +  }
>> +
>> +  // Now we can walk down towards the right leaf node

We are reading here without explicit locks, i.e., memory can change 
behind our back at any time. Thus, before we act on a value that we have 
read, we must check if that value is still valid.
The invariants that we rely upon are:
I1) a node pointer will always be either a nullptr or point to a b-tree 
node. The node might have been logically deleted, but the memory will 
always remain valid due to our free list.
I2) The root pointer is only modified by a thread that holds an 
exclusive lock on root_lock.
I3) valide calls fail if a) somebody else currently holds the lock, or 
b) if the version value has changed since locking, which happens when 
somebody releases an exlusive lock.

Using that, the code does the following steps

1. We lock root_lock optimistic. In case of an exclusive lock we restart 
immediately, otherwise we remember the current version
2. We load the root pointer and store it in iter. iter might contain 
arbitrary garbage due to races
3. We validate the root_lock, and restart in case of errors. Now we know 
that a) nobody has locked the root exclusively or modified it since step 
1 (I3), and b) iter indeed points to the node that corresponds the to 
the version that we have read in step 1 (due to I2)

At this point we now that iter is indeed the right root pointer. If it 
is a nullptr we stop here. Otherwise we continue with

4. We lock the root node itself (iter), storing the validated version in 
child_lock. We need that lock to detect changes to the content of the 
root, the root_lock only protects the pointer to the root. Loading the 
lock is safe due to I1. As our tree can change at any point in time, we 
need another valide call on root_lock to make sure that we still have 
the right root pointer.


At this point we have both a pointer to the root node and an optimistic 
lock that allows us to detect changes to the content of the root. Thus, 
we can safely navigate down, any changes to the b-tree that could affect 
us, like, e.g., node splits in the root, will be detected when 
validating the lock.


I hope that answered both the necessary and sufficient part. As a 
general rule, you must always use the pair relax-atomic-read + validate 
to avoid data races. Acting on any value that you have not validated is 
unsafe, as you could get races.

Best

Thomas

      reply	other threads:[~2022-09-12 18:03 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-26  9:13 Thomas Neumann
2022-09-12 16:04 ` Jason Merrill
2022-09-12 18:03   ` Thomas Neumann [this message]

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=3740268a-c99f-c395-9445-15cf33e3555f@in.tum.de \
    --to=thomas.neumann@in.tum.de \
    --cc=fweimer@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jakub@redhat.com \
    --cc=jason@redhat.com \
    --cc=jwakely.gcc@gmail.com \
    --cc=trodgers@redhat.com \
    /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).