-
Notifications
You must be signed in to change notification settings - Fork 105
New to openweave #492
base: master
Are you sure you want to change the base?
New to openweave #492
Conversation
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 What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
1 similar comment
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 What to do if you already signed the CLAIndividual signers
Corporate signers
ℹ️ Googlers: Go here for more info. |
CLAs look good, thanks! ℹ️ Googlers: Go here for more info. |
1 similar comment
CLAs look good, thanks! ℹ️ Googlers: Go here for more info. |
Codecov Report
@@ 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
Continue to review full report at Codecov.
|
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. |
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. |
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 |
@jaylogue So this is interesting; you'll notice that in my changes to auto-release, one of the exit points wasn't releasing: So there's 2 possibilities here:
|
@@ -298,12 +292,11 @@ INET_ERROR DNSResolver::Cancel() | |||
*/ | |||
void DNSResolver::HandleResolveComplete() | |||
{ | |||
Weave::System::Object::AutoRelease objectRelease(*this); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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);
...
}
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!