Re: [libgpiod v2][PATCH] line-config: rework the internal implementation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Oct 5, 2021 at 6:20 AM Kent Gibson <warthog618@xxxxxxxxx> wrote:
>
> On Wed, Sep 22, 2021 at 10:11:00AM +0200, Bartosz Golaszewski wrote:
> > This reworks how the line config objects work internally. In order to reduce
> > the size of the gpiod_line_config objects, we switch from using a set number
> > of override config structures with each storing a list of line offsets to
> > storing a smaller override object for each of the maximum of 64 lines.
> > Additionally these internal config structures are now packed and only occupy
> > the minimum required amount of memory.
> >
> > The processing of these new overrides has become a bit more complicated but
> > should actually be more robust wrt corner cases.
> >
> > Signed-off-by: Bartosz Golaszewski <brgl@xxxxxxxx>
>
> Given the level of rework the diff is harder work than looking at the
> resulting code, but it all looks good to me.
> A few minor comments scattered below.
>

[snip]

> >
> >  GPIOD_API struct gpiod_line_config *gpiod_line_config_new(void)
>
> You don't have any change to gpiod_line_config_free() here, but
> isn't free() guaranteed to be NULL aware, so you can drop the NULL
> check?
> If not, couldn't it be flipped to:
>
>         if (config)
>                 free(config);
>
> Similarly gpiod_line_config_new() could have
>
>         if (config)
>                 gpiod_line_config_reset(config);
>
> and that "if" could be dropped if gpiod_line_config_reset() were NULL
> aware.
>

No, you're right, as long as we don't dereference the pointer, we can
drop the check. Here and elsewhere.

> But the general policy is that gpiod functions are not NULL aware?
>

In general yes, but various free functions are NULL-aware.

[snip]

> >  static struct base_config *
> > -get_base_config_for_offset(struct gpiod_line_config *config,
> > -                        unsigned int offset)
> > +get_base_config_for_reading(struct gpiod_line_config *config,
> > +                        unsigned int offset, unsigned int flag)
> >  {
> > -     struct secondary_config *secondary;
> > -     unsigned int i, j;
> > -
> > -     /*
> > -      * We're looking backwards as the settings get overwritten if set
> > -      * multiple times.
> > -      */
> > -     for (i = config->num_secondary; i > 0; i--) {
> > -             secondary = &config->secondary[i - 1];
> > +     struct override_config *override;
> >
> > -             for (j = 0; j < secondary->num_offsets; j++) {
> > -                     if (secondary->offsets[j] == offset)
> > -                             return &secondary->config;
> > -             }
> > -     }
> > +     override = get_override_by_offset(config, offset);
> > +     if (!override || !(override->override_flags & flag))
> > +             return &config->defaults;
> >
> > -     return NULL;
> > +     return &override->base;
> >  }
> >
>
> Maybe flip the logic around to make it easier to read:
>
>         if (override && (override->override_flags & flag))
>                 return &override->base;
>
>     return &config->defaults;
>
> Similarly in gpiod_line_config_get_output_value().
>

Done.

> >  static void set_direction(struct base_config *config, int direction)
>
> In set_direction() you have a specific case (GPIOD_LINE_DIRECTION_AS_IS)
> that matches the default behaviour.  I generally drop that case and let
> the default handle it, but that is just personal preference.
>
> Similarly in other set_XXX switches.
>

My personal preference is to be explicit and include those default
cases even if only to tell my future self what's happening here.

> > @@ -209,7 +170,7 @@ static void set_direction(struct base_config *config, int direction)
> >  GPIOD_API void
> >  gpiod_line_config_set_direction(struct gpiod_line_config *config, int direction)
> >  {
> > -     set_direction(&config->primary, direction);
> > +     set_direction(&config->defaults, direction);
> >  }
> >
> >  GPIOD_API void
> > @@ -224,13 +185,19 @@ gpiod_line_config_set_direction_subset(struct gpiod_line_config *config,
> >                                      int direction, unsigned int num_offsets,
> >                                      const unsigned int *offsets)
> >  {
> > -     struct secondary_config *secondary;
> > +     struct override_config *override;
> > +     unsigned int i, offset;
> >
> > -     secondary = get_secondary_config(config, num_offsets, offsets);
> > -     if (!secondary)
> > -             return;
> > +     for (i = 0; i < num_offsets; i++) {
> > +             offset = offsets[i];
> >
>
> Worth the effort given it is only used once?
>

Must have been a leftover, thanks.

[snip]

> >
> >  GPIOD_API void
> > @@ -464,20 +448,26 @@ gpiod_line_config_set_active_high_subset(struct gpiod_line_config *config,
> >                                        unsigned int num_offsets,
> >                                        const unsigned int *offsets)
> >  {
> > -     struct secondary_config *secondary;
> > +     struct override_config *override;
> > +     unsigned int i, offset;
> >
> > -     secondary = get_secondary_config(config, num_offsets, offsets);
> > -     if (!secondary)
> > -             return;
> > +     for (i = 0; i < num_offsets; i++) {
> > +             offset = offsets[i];
> > +
> > +             override = get_override_config_for_writing(config, offset);
> > +             if (!override)
> > +                     return;
> >
> > -     secondary->config.active_low = false;
> > +             override->base.active_low = false;
> > +             override->override_flags |= OVERRIDE_FLAG_ACTIVE_LOW;
> > +     }
> >  }
> >
>
> gpiod_line_config_set_active_low_subset() and
> gpiod_line_config_set_active_high_subset() could call a common helper
> that accepts the active_low as a parameter?
>

Makes sense.

[snip]

> > +
> > +static bool override_config_debounce_period_is_equal(struct override_config *a,
> > +                                                  struct override_config *b)
> > +{
> > +     if (base_debounce_period_is_equal(&a->base, b) &&
> > +         ((a->override_flags & OVERRIDE_FLAG_DEBOUNCE_PERIOD) ==
> > +          (b->override_flags & OVERRIDE_FLAG_DEBOUNCE_PERIOD)))
> > +             return true;
> > +
> > +     return false;
> > +}
> > +
>
> To improve readability, flip the order here to test the flag equivalence
> first.
> Particularly wrt the "a" doesn't have debounce overridden case.
>

Done.

[snip]

>
> Don't see anything wrong here, but I'd like to see a bunch of tests to
> cover the corner cases you mentioned, as the bulk of the module complexity
> is here.
> Not that I expect that now.
>

Yes, definitely. Trying to get the gpio-sim module upstream for this
exact reason. Please take a look at this series if you can.

[snip]

>
> Overall it looks really good to me, so no problem with applying it,
> with or without my suggestions.

I've applied most of your suggestions and will squash this into the
big patch, thanks as usual!

Bart



[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux