bug-hurd
[Top][All Lists]
Advanced

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

Re: [PATCH v3 1/2] libirqhelp: user interrupt handler helper library


From: Samuel Thibault
Subject: Re: [PATCH v3 1/2] libirqhelp: user interrupt handler helper library
Date: Mon, 3 Oct 2022 02:19:44 +0200
User-agent: NeoMutt/20170609 (1.8.3)

Damien Zammit, le dim. 25 sept. 2022 04:12:27 +0000, a ecrit:
> +static void
> +toggle_irq(struct irq *irq, bool on)
> +{
> +  pthread_mutex_lock (&irq->irqlock);
> +  irq->enabled = on;
> +  pthread_cond_signal (&irq->irqcond);

Better only signal when `on` is true, since nobody is waiting for
`irq->enabled` to become false.

> +  pthread_mutex_unlock (&irq->irqlock);
> +}
> +
> +void
> +irqhelp_disable_irq(int gsi)
> +{
> +  struct irq *irq = lookup_irq_structure(gsi);
> +  if (!irq)
> +    return;

I'd say at least somehow warn? That's not expected.

> +
> +  toggle_irq(irq, false);
> +}
> +
> +void
> +irqhelp_enable_irq(int gsi)
> +{
> +  struct irq *irq = lookup_irq_structure(gsi);
> +  if (!irq)
> +    return;
> +
> +  toggle_irq(irq, true);
> +}
> +
> +void *
> +irqhelp_server_loop(void *arg)
> +{
> +  struct irq *irq = (struct irq *)arg;
> +
> +  if (!irq)
> +    return NULL;
> +
> +  /* init hook */
> +  if (irq->init_hook)
> +    irq->init_hook(irq->context);

I don't understand why these hooks. If the library user wants to do
something at the beginning of irqhelp_server_loop, it call just do it
before calling irqhelp_server_loop.

> +  int interrupt_demuxer (mach_msg_header_t *inp,
> +                      mach_msg_header_t *outp)
> +  {
> +    device_intr_notification_t *n = (device_intr_notification_t *) inp;
> +
> +    ((mig_reply_header_t *) outp)->RetCode = MIG_NO_REPLY;
> +    if (n->intr_header.msgh_id != DEVICE_INTR_NOTIFY)
> +      return 0;  /* not an interrupt */
> +
> +    /* FIXME: id <-> gsi now has an indirection, assuming 1:1 */
> +    if (n->id != irq->gsi)
> +      return 0;  /* interrupt not for us */
> +
> +    /* wait if irq disabled */
> +    pthread_mutex_lock (&irq->irqlock);
> +    while (!irq->enabled)
> +      pthread_cond_wait (&irq->irqcond, &irq->irqlock);
> +    pthread_mutex_unlock (&irq->irqlock);
> +
> +    /* pre-handler */
> +    if (irq->pre_hook)
> +      irq->pre_hook(irq->context);
> +
> +    /* call handler */
> +    irq->handler(irq->context);
> +
> +    /* post-handler */
> +    if (irq->post_hook)
> +      irq->post_hook(irq->context);

And similarly if the library user wants to do something before and after
the handler is called, it can just create its own handler that does
pre-stuff, calls the underlying handler, and does post-stuff. AIUI in
the ddekit case we don't even need it.

> +    /* ACK interrupt */
> +    device_intr_ack (irqdev, irq->port, MACH_MSG_TYPE_MAKE_SEND);
> +
> +    return 1;
> +  }
> +
> +  /* Server loop */
> +  mach_msg_server (interrupt_demuxer, 0, irq->port);
> +
> +  return NULL;
> +}
> +
> +static struct irq *
> +interrupt_register(int gsi,
> +                int bus,
> +                int dev,
> +                int fun,
> +                void (*handler)(void *),
> +                void *context,
> +                int *cookie)
> +{
> +  mach_port_t delivery_port;
> +  mach_port_t pset, psetcntl;
> +  error_t err;
> +  struct irq *irq = NULL;
> +
> +  irq = malloc(sizeof(struct irq));
> +  if (!irq)
> +    return NULL;
> +
> +  LIST_INSERT_HEAD(&irqs, irq, entries);

It doesn't seem to be used?  I don't think we'll use it actually, if we
make irqhelp_remove_interrupt_handler just take the irq structure.

> +  irq->handler = handler;
> +  irq->context = context;
> +  irq->gsi = gsi;
> +  irq->init_hook = NULL;     /* can be overriden later by caller */
> +  irq->pre_hook = NULL;              /* can be overriden later by caller */
> +  irq->post_hook = NULL;     /* can be overriden later by caller */
> +  irq->enabled = true;               /* don't require initial explicit 
> enable */
> +  pthread_mutex_init (&irq->irqlock, NULL);
> +  pthread_cond_init (&irq->irqcond, NULL);
> +
> +  err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE,
> +                         &delivery_port);
> +  if (err)
> +    goto fail;
> +
> +  irq->port = delivery_port;
> +
> +  err = thread_get_assignment (mach_thread_self (), &pset);
> +  if (err)
> +    goto fail;
> +
> +  err = host_processor_set_priv (master_host, pset, &psetcntl);
> +  if (err)
> +    goto fail;
> +
> +  thread_max_priority (mach_thread_self (), psetcntl, 0);
> +  err = thread_priority (mach_thread_self (), IRQ_THREAD_PRIORITY, 0);
> +  if (err)
> +    goto fail;
> +
> +  err = device_intr_register(irqdev, irq->gsi,
> +                             0, irq->port,
> +                             MACH_MSG_TYPE_MAKE_SEND);
> +  if (err)
> +    goto fail;
> +
> +  *cookie = irq->cookie = atomic_increment (&refcnt);

Do we still need a cookie? Since we already return an opaque structure
that the library user could just pass to irqhelp_remove_interrupt_handler?

> +  return irq;
> +
> +fail:
> +  pthread_cond_destroy(&irq->irqcond);
> +  pthread_mutex_destroy(&irq->irqlock);
> +  free(irq);
> +  return NULL;
> +}
> +
> +
> +/* Accepts gsi or bus/dev/fun or both, but cant be all -1.
> +   If gsi is -1, will lookup the gsi via ACPI.
> +   If bus/dev/fun are -1, must pass in gsi.
> +   Accepts a pointer to a cookie to be used to
> +   deregister the handler later.  */
> +struct irqhelp *
> +irqhelp_install_interrupt_handler(int gsi,
> +                               int bus,
> +                               int dev,
> +                               int fun,
> +                               void (*handler)(void *),
> +                               void *context,
> +                               int *cookie)
> +{
> +  struct irq *irq;
> +  error_t err;
> +
> +  if (!handler)
> +    return NULL;
> +
> +  if (!cookie)
> +    return NULL;
> +
> +  err = get_irq();
> +  if (err)
> +    return NULL;
> +
> +  if (gsi < 0)
> +    {
> +      if ((bus < 0) || (dev < 0) || (fun < 0))
> +        return NULL;
> +
> +      err = get_acpi();
> +      if (err)
> +        return NULL;
> +
> +      /* We need to call acpi translator to get gsi */
> +      err = acpi_get_pci_irq (acpidev, bus, dev, fun, &gsi);
> +      if (err)
> +        return NULL;
> +    }
> +
> +  err = get_privileged_ports (&master_host, 0);
> +  if (err)
> +    return NULL;
> +
> +  irq = interrupt_register(gsi, bus, dev, fun, handler, context, cookie);
> +
> +  mach_port_deallocate (mach_task_self (), master_host);
> +  return (struct irqhelp *)irq;
> +}
> +
> +error_t
> +irqhelp_remove_interrupt_handler(int gsi,
> +                              int bus,
> +                              int dev,
> +                              int fun,
> +                              int cookie)
> +{
> +  /* Not implemented yet, but don't fail */
> +  return 0;
> +}
> diff --git a/libirqhelp/irqhelp.h b/libirqhelp/irqhelp.h
> new file mode 100644
> index 00000000..292d912d
> --- /dev/null
> +++ b/libirqhelp/irqhelp.h
> @@ -0,0 +1,39 @@
> +/* Library providing helper functions for userspace irq handling.
> +   Copyright (C) 2022 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU General Public License as
> +   published by the Free Software Foundation; either version 2, or (at
> +   your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful, but
> +   WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program; if not, write to the Free Software
> +   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
> +
> +#ifndef _HURD_IRQHELP_
> +#define _HURD_IRQHELP_
> +
> +#include <mach.h>
> +#include <hurd/hurd_types.h>
> +#include <pthread.h>
> +#include <stdlib.h>
> +
> +struct irqhelp {
> +  void (*init_hook)(void *);
> +  void (*pre_hook)(void *);
> +  void (*post_hook)(void *);
> +};
> +
> +struct irqhelp * irqhelp_install_interrupt_handler(int gsi, int bus, int 
> dev, int fun,
> +                                                void (*handler)(void *), 
> void *context, int *cookie);
> +error_t irqhelp_remove_interrupt_handler(int gsi, int bus, int dev, int fun, 
> int cookie);
> +void * irqhelp_server_loop(void *arg);
> +void irqhelp_enable_irq(int gsi);
> +void irqhelp_disable_irq(int gsi);
> +
> +#endif
> --
> 2.34.1
> 
> 
> 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]