[squid-dev] [RFC] [PREVIEW] LockingPointer round 3.

Alex Rousskov rousskov at measurement-factory.com
Thu Jul 21 15:42:46 UTC 2016


On 07/21/2016 07:58 AM, Amos Jeffries wrote:
>      void resetWithoutLocking(T *t) {
> +#if USE_OPENSSL
> +        assert(!t || t->references > 0);
> +        assert(!raw || raw->references > 0);
> +        if (raw && t == raw) {
> +            assert(raw->references > 1); // us plus caller locks
> +        }
> +#endif
>          unlock();
>          raw = t;
>      }

The first assert() is correct.

The second assert() belongs to unlock() where it is already present.
Remove it from here.

The third assert() comment implies that self-reset is not supported (and
will assert) in some cases, but other self-reset cases are fine. If that
is what you are proposing, you should be explicit about it. Needless to
say, I am against such inconsistent behavior and recommend removing that
third assert.


> If you are referring to the self-reset assert(t != raw) and so adamant
> that is right

I spent many hours discussing why such assert would be wrong [when the
other method has the opposite do-nothing implementation]. And now you
think I may consider it being correct and even call me adamant. Sigh.


> OpenSSL 1.1.0 is making a lot of
> things opaque and that includes the reference counting. We may not be
> able to access t->references for long.

Which is why it is probably a good idea to add MustBeLocked(const T*) or
AssertIfUnlocked(const T*) or similar static method (that does nothing
if it cannot check) instead of sprinkling code with #ifdefs and explicit
accesses to references. If the asserts above are fixed, one such method
would suffice AFAICT.



>>> // XXX: why not set fd_table if that add() succeeded ?

>> The simple answer is that if you set fd_table after cache add()ing
>> succeeded, then both fd_table and the cache will delete the same
>> pointer, crashing Squid. Note that ctx is a raw pointer [to a smart
>> pointer]. However, I doubt this is the correct/best answer.
>>
>> AFAICT, the poor-quality comments in the original code were supposed to
>> answer that question like this: The _only_ reason we add ctx to the
>> table is so that it gets eventually destroyed. The context object is not
>> needed in the table and should not be accessed from there. If we
>> successfully add ctx to the cache, then the cache becomes responsible
>> for its destruction and we do not need to add it to the table.


> So that means the fd_table member can be set *always*

Probably, but this is not my area of the expertise.


> On the other hand. I suspect that the use fd_table is being put to is
> better served by one of the MasterXaction / AccessLogEntry /
> ConnStateData objects relevant to the transaction using that context.

Not MasterXaction or AccessLogEntry -- the context is specific to the
connection, not transaction. ConnStateData is a good candidate but you
may find it difficult to share with those who need the context.

Pretty much any use of fd_table outside Comm code is a bug, but fixing
that bug is difficult.


> +            // fd_table is now responsible for reference counting of the pointer.

This comment is misleading. Both fd_table and the cache (if any) are
responsible. IMO, there is no need to retell what the code already
clearly says so I recommend removing that comment.


> +                    delete tmp; // dont leak tmp on failures

I recommend deleting that comment. It is misleading (more than just tmp
will leak without that delete) and misspelled. You may want to replace
it with "XXX: leaks on exceptions" or, better, use std::unique_ptr (and
release() it on add() success) to prevent those leaks.

> +    /**
> +     * Construct directly from a raw pointer is forbidden.

s/Construct/Constructing/ or s/Construct/Construction/


> +     * Use the appropriate reset method instead.

This does not make sense -- if I need a _constructor_ I cannot use a
regular method.


> +    explicit LockingPointer(T *) = delete;

Did you mean to prohibit all from-pointer construction or just the
explicit one? If it is the former, I suggest removing "explicit".


> How about?
> 
>   static SelfType&& MakeFromLockedOpenSslPointer(T *t) {
>       SelfType out;
>       out.resetWithoutLocking(t);
>       return std::move(out);
>   }
> 
> 
> Theres something I'm not quite understanding going on with the
> return-by-value for template types giving me compiler errors. Thus the
> std::move, it seems to build but I'm not sure if it will run properly at
> all.

I strongly recommend against writing optimization code you do not fully
understand. Add a simple static method that returns a SelfType instead.

This particular method clearly has nothing to do with OpenSsl. Using
OpenSsl in its name but calling it in GnuTLS-compiled code is very
confusing IMO. I recommend removing OpenSsl letters from its name. If
you want to restrict this method use to OpenSSL builds (for now), then
surround it with #ifdefs and document why others should not use it.


The word "Make" does not seem to add any value so I recommend removing
it from the method name:
   CrlPointer::FromLockedOpenSslPointer() is as clear as
   CrlPointer::MakeFromLockedOpenSslPointer()


> identifying this ambiguous use was the point of
> the comment experiment.

It looks like the experiment is still ongoing. If not, please remove
stale experimental comments.


Thank you,

Alex.



More information about the squid-dev mailing list