BIND 10 #2198: make sure InterprocessSyncLocker is thread safe

BIND 10 Development do-not-reply at isc.org
Thu Oct 11 12:10:08 UTC 2012


#2198: make sure InterprocessSyncLocker is thread safe
-------------------------------------+-------------------------------------
                   Reporter:         |                 Owner:  muks
  jinmei                             |                Status:  reviewing
                       Type:         |             Milestone:
  defect                             |  Sprint-20121023
                   Priority:         |            Resolution:
  medium                             |             Sensitive:  0
                  Component:         |           Sub-Project:  Core
  logging                            |  Estimated Difficulty:  5
                   Keywords:         |           Total Hours:  0
            Defect Severity:  N/A    |
Feature Depending on Ticket:         |
        Add Hours to Ticket:  0      |
                  Internal?:  0      |
-------------------------------------+-------------------------------------
Changes (by vorner):

 * owner:  vorner => muks


Comment:

 Hello

 Replying to [comment:14 muks]:
 > Thanks for catching this. I've updated the dependencies and order of
 build. It should build properly now.

 Thanks.

 > > Replying to [comment:12 muks]:
 > If the code were written like this, then true. This is why the API doc
 comment was added asking users of `Mutex` to consider using
 `Mutex::Locker` where applicable. But where it doesn't fit in naturally,
 allowing `lock()` and `unlock()` methods is not bad.

 Well, using lock() and unlock() in a language that has exceptions is very
 risky. I'd very much like to avoid that and disallow that. Jinmei seems to
 agree with the approach (I guess from the condvar discussion in #2332). So
 I'd
 hate to allow it because of it is more slightly more convenient in one
 place.

 I may be too scared of threads, but I know it might be very problematic to
 debug (yes, I did try writing threaded applications before). So I want to
 be on
 the safe side and disallow any kinds of bugs I can.

 > > Also, the tryLock ‒ I guess it is needed somewhere and not provided
 for
 > > completeness? Because I don't see the need for it and it seems to be
 used in
 > > tests only.
 >
 > It's required to test that the other methods work properly for a file
 lock. Also because this is a interprocess synchronization object (not just
 for logger), `tryLock()` is a reasonable operation to provide.

 Well, I have idea of how to do it with a Locker too (throwing exception in
 case
 it isn't possible to lock). But I still don't know if we want such
 operation at
 all, if it is not really used in the real code anywhere.

 > > {{{#!c++
 > > scoped_ptr<Mutex::Locker> locker(new Locker(mutex_));
 > >
 > > if (do_lock(...)) {
 > >     is_locked_ = true;
 > >     locker_ = locker.release();
 > >     return (true);
 > > }
 > >
 > > return (false);
 > > }}}
 >
 > Wouldn't this involve maintaining another `locker_` member variable? Is
 the current code incorrect or complicated to follow? To me the latter code
 and maintaining `locker_` would be more complicated and unnatural in this
 particular case.

 Yes. But then, it means we don't let people directly to the lock() and
 unlock() and get rid of the very awkwardly looking try thing and it would
 IMO be even safer.

 > > This really needs some error checking, EBUSY is not everything the
 pthread_try_lock can return:
 > > {{{#!c++
 > > bool
 > > Mutex::tryLock() {
 > >     assert(impl_ != NULL);
 > >     const int result = pthread_mutex_trylock(&impl_->mutex);
 > >     if (result != 0) {
 > >         return (false);
 > >     }
 > >     ++impl_->locked_count; // Only in debug mode
 > >     return (true);
 > > }
 > > }}}
 >
 > `tryLock()` returns `false` indicating the lock operation failed. Does
 it have to throw as well? I'll add it if you think it's valid.

 Well, but you want to distinguish problems like „The mutex does not exist“
 and
 „The same thread tries to lock it again“ from „The mutex is being locked
 right
 now, try later“. Because the first two are serious programmer errors (the
 second could actually lead to application trying again and again and
 failing
 forever, without providing any notification something is wrong), while the
 last
 is normal operation. It doesn't have to throw, assert like the rest would
 be enough.

 > > What is the point of the exercise with weak pointers, if the code
 still relies on the fact that everything in the map is a valid pointer?
 >
 > As the weak pointer maintains no direct reference, I thought it was more
 understandable code. Or I am not following the question. ^^ :)

 I think that if we want to use them, we want to be prepared for the
 situation
 when we find an invalid weak pointer in the map, just in case something
 forgot
 to remove it. This way, it would throw (I think).

 > > Also, what is the reason behind this?
 > > {{{#!diff
 > > -#include "interprocess_sync_file.h"
 > > +#include <util/interprocess_sync_file.h>
 > > }}}
 >
 > Just for consistency with the rest of the codebase.

 But the second is less corect. There are quote-includes through the code
 as well, if they are from the local directory.

 Anyway, would it be OK if I took the oportunity and wrote a counter-
 proposal for the code as I see it?

-- 
Ticket URL: <http://bind10.isc.org/ticket/2198#comment:15>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development


More information about the bind10-tickets mailing list