All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.