Skip to content
This repository has been archived by the owner on Dec 20, 2023. It is now read-only.

New to openweave #492

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open

New to openweave #492

wants to merge 13 commits into from

Conversation

marcosb
Copy link

@marcosb marcosb commented Feb 10, 2020

Hi,

Googler here looking to contribute; I was perusing the code and noticed there's a lot of manual locks/unlocks, instead of using RAII.

Is there a reason for not using SBRM here? It seems that if anything were to go wrong currently, the lock would be held indefinitely.

Thanks for your time, and if I missed something, let me know!

@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here with @googlebot I signed it! and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

1 similar comment
@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed (or fixed any issues), please reply here with @googlebot I signed it! and we'll verify it.


What to do if you already signed the CLA

Individual signers
Corporate signers

ℹ️ Googlers: Go here for more info.

@googlebot
Copy link

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

1 similar comment
@googlebot
Copy link

CLAs look good, thanks!

ℹ️ Googlers: Go here for more info.

@codecov-io
Copy link

Codecov Report

Merging #492 into master will decrease coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #492      +/-   ##
==========================================
- Coverage   54.05%   54.04%   -0.01%     
==========================================
  Files         344      344              
  Lines       59061    59057       -4     
==========================================
- Hits        31924    31920       -4     
  Misses      27137    27137
Impacted Files Coverage Δ
src/inet/AsyncDNSResolverSockets.cpp 96.39% <100%> (-0.13%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 9708816...fce2625. Read the comment docs.

@jaylogue
Copy link
Contributor

Hi Marcos,

Thanks for your contribution. The pattern you propose is certainly not unacceptable for use in OpenWeave, especially given that the size and complexity of generated code is effectively the same. That said, I think we have steered away from this pattern because of its limited value in our context; specifically due to our preference for a single exit path for methods and the fact that we don't use exceptions. The other issue I see with RAII patterns is the poor readability for people not intimately familiar with the pattern--e.g. embedded C developers. The lack of definitive "lock is taken here" / "lock is released here" statements can obscure the true behavior of the code.

@marcosb
Copy link
Author

marcosb commented Feb 12, 2020

Hey @jaylogue, thanks for the response! I probably picked a terrible example of where to use RAII, apologies for that - I picked a simple file just to get the discussion started.

Object::Release is probably a better example of multiple exit points & a place where RAII would be really useful; my thought was that if weave uses this pattern throughout, instances like this would not look so frightening & be so bug-prone:

https://github.com/openweave/openweave-core/blob/master/src/inet/DNSResolver.cpp

I can get a prototype CL for that file if you think it's worthwhile, just wanted to get a quick discussion going first.

@marcosb
Copy link
Author

marcosb commented Feb 12, 2020

OK made the sample changes to DNSResolver; not totally sure if it compiles but I'll check once it's done.

At least it gives an idea though of how enforcing the RAII pattern (even in places where it doesn't help much) could help guide people to using this to write safer code.

E.g. if we go this route, we can actually make the Release method private, so that only AutoRelease can do the releasing, thus guiding engineers to use the safer & more readable auto-release method

@marcosb
Copy link
Author

marcosb commented Feb 14, 2020

@jaylogue So this is interesting; you'll notice that in my changes to auto-release, one of the exit points wasn't releasing:
https://github.com/openweave/openweave-core/blob/master/src/inet/DNSResolver.cpp#L200

So there's 2 possibilities here:

  1. This was a bug & it should've been releasing
  2. This was WAI (I think it's reasonable to add a method to NOT auto-release in cases like this), but then there's no unit test coverage here

@@ -298,12 +292,11 @@ INET_ERROR DNSResolver::Cancel()
*/
void DNSResolver::HandleResolveComplete()
{
Weave::System::Object::AutoRelease objectRelease(*this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see this as an anti-pattern. In this case we're dealing with a reference count, vs. a lock, where the lifetime of reference spans multiple states of the object. In this case, a single call to a method called Release() is clearly the most obvious pattern.

@@ -91,9 +91,9 @@ INET_ERROR DNSResolver::Resolve(const char *hostName, uint16_t hostNameLen, uint
DNSResolver::OnResolveCompleteFunct onComplete, void *appState)
{
INET_ERROR res = INET_NO_ERROR;
Weave::System::Object::AutoRelease objectRelease(*this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to my comment below, I don't see this as a desirable pattern. Rather, I would argue that the returns should be replaced with ExitNow() jumps to an exit: label containing a single call to Release().

@@ -172,8 +195,7 @@ INET_ERROR AsyncDNSResolverSockets::EnqueueRequest(DNSResolver &resolver)
{
INET_ERROR err = INET_NO_ERROR;
int pthreadErr;

AsyncMutexLock();
LockHolder asyncMutexLock(*this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to above, I think this pattern makes it easy to miss the acquisition of the lock. I suggest always using an independent block to clearly demark the scope of the lock, with the lock being the only variable declared at the start of the block. E.g.:

INET_ERROR AsyncDNSResolverSockets::EnqueueRequest(DNSResolver &resolver)
{
    INET_ERROR err = INET_NO_ERROR;
    int pthreadErr;

    {
        auto lock = LockHolder::AquireLock(*this);

        ...
    }

    return err;
}


mInet->State = InetLayer::kState_ShutdownInProgress;
{
LockHolder asyncMutexLock(*this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This illustrates one of the downsides of this pattern--the point at which the lock is acquired doesn't read as an imperative statement, and hence is easily missed by the unaware reader.

I think a construct like this would be more obvious:

{
    auto lock = LockHolder::AquireLock(*this);

    ...
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants