From: Helmut Grohne <helmut.grohne@intenta.de>
To: Bartosz Golaszewski <brgl@bgdev.pl>
Cc: Kent Gibson <warthog618@gmail.com>,
"linux-gpio@vger.kernel.org" <linux-gpio@vger.kernel.org>,
Bartosz Golaszewski <bgolaszewski@baylibre.com>
Subject: Re: [libgpiod][RFC PATCH] bindings: cxx: demote the line's parent chip reference to a weak_ptr
Date: Fri, 16 Oct 2020 12:29:39 +0200 [thread overview]
Message-ID: <20201016102937.GA22245@laureti-dev> (raw)
In-Reply-To: <20201016090949.24456-1-brgl@bgdev.pl>
On Fri, Oct 16, 2020 at 11:09:49AM +0200, Bartosz Golaszewski wrote:
> Demote the parent reference to a weak_ptr. Introduce a sub-class that
> allows line and line_bulk objects to lock the chip by temporarily
> converting this weak_ptr to a full shared_ptr - this way we don't risk
> dropping the last reference to the parent chip when the line is calling
> the underlying library functions. Chip deleted during that time will
> expire right after the concerned line method returns.
I don't think I understand the implications for this yet. Something in
my mental model must be wrong or the change doesn't make much sense.
> +chip::chip(const ::std::weak_ptr<::gpiod_chip>& chip_ptr)
> + : _m_chip(chip_ptr)
> +{
> +
> +}
> +
I think what happens here is that you upgrade a weak_ptr to a
shared_ptr. Wouldn't it be more natural to request a
::std::shared_ptr<::gpiod_chip> &&
here and thus make the ownership-taking more explicit? It would be done
on the caller-side and thus be more transparent. Stuffing weak_ptrs
should continue to work.
> @@ -526,7 +528,22 @@ private:
> line_event make_line_event(const ::gpiod_line_event& event) const noexcept;
>
> ::gpiod_line* _m_line;
> - chip _m_chip;
> + ::std::weak_ptr<::gpiod_chip> _m_owner;
> +
> + class chip_locker
> + {
> + public:
> + chip_locker(const line& line);
> + ~chip_locker(void) = default;
> +
> + chip_locker(const chip_locker& other) = delete;
> + chip_locker(chip_locker&& other) = delete;
> + chip_locker& operator=(const chip_locker&& other) = delete;
> + chip_locker& operator=(chip_locker&& other) = delete;
> +
> + private:
> + ::std::shared_ptr<::gpiod_chip> _m_chip;
> + };
>
> friend chip;
> friend line_bulk;
I don't quite get what problem this chip_lcoker solves. It seems to
prevent concurrent destruction of a ::gpiod_chip. How can this happen?
One option would be concurrency due to threads. However the whole API
does not look thread-safe so this would be wrong. The other could be
callbacks. I couldn't find any callbacks in the C++ bindings. So now I
am confused why one would need to lock the chip. Do you fear changes
inside signal handlers?
> @@ -536,9 +553,11 @@ private:
> /**
> * @brief Find a GPIO line by name. Search all GPIO chips present on the system.
> * @param name Name of the line.
> - * @return Returns a line object - empty if the line was not found.
> + * @return Returns a <line, chip> pair where line is the line with given name
> + * and chip is the line's owner. Both objects are empty if the line was
> + * not found.
> */
> -GPIOD_API line find_line(const ::std::string& name);
> +GPIOD_API ::std::pair<line, chip> find_line(const ::std::string& name);
This makes the API a little less convenient to use.
> @@ -39,6 +39,7 @@ line::line(::gpiod_line* line, const chip& owner)
> unsigned int line::offset(void) const
> {
> this->throw_if_null();
> + line::chip_locker lock_chip(*this);
>
> return ::gpiod_line_offset(this->_m_line);
> }
This example nicely shows why I am confused about the chip_locker. Why
can the chip not become null between the throw_if_null call and the
chip_locker construction, but it can be externally mutated between the
chip_locker construction and the gpiod_line_offset call? It would appear
to me that the chip_locker is entirely unnecessary here.
I also think that this refactoring still does not accurately represent
the kernel interfaces. When you dispose a chip, the owned line becomes
invalidated. Why do I have to keep the chip to use the line? Is it
really reasonable to have chips own lines?
When I use the bare kernel interfaces, I can open a chip, request a line
(which receives a separate fd) and then I can close the chip and
continue working with the line fd. I could even open the chip in one
process and transfer the open line fd to a different (possibly
sandboxed) process or close the chip and sandbox the process prohibiting
further VFS operations. As far as I can see, neither the old nor the
proposed API handles any of this.
Helmut
next prev parent reply other threads:[~2020-10-16 10:29 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-10-16 9:09 [libgpiod][RFC PATCH] bindings: cxx: demote the line's parent chip reference to a weak_ptr Bartosz Golaszewski
2020-10-16 10:29 ` Helmut Grohne [this message]
2020-10-16 13:38 ` Bartosz Golaszewski
2020-10-19 12:17 ` Bartosz Golaszewski
2020-10-19 12:38 ` Helmut Grohne
2020-10-19 13:06 ` Bartosz Golaszewski
2020-10-20 5:57 ` Helmut Grohne
2020-10-20 6:58 ` Bartosz Golaszewski
2020-11-04 15:45 ` Bartosz Golaszewski
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=20201016102937.GA22245@laureti-dev \
--to=helmut.grohne@intenta.de \
--cc=bgolaszewski@baylibre.com \
--cc=brgl@bgdev.pl \
--cc=linux-gpio@vger.kernel.org \
--cc=warthog618@gmail.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