Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Signaling Events from Interrupt Handlers

Best way to wake multiple threads from interrupt?

> I want to make a character device driver that passes the same data to all tasks that are reading it. It is not so important whether the data is queued or if just latest sample is retrieved. Problem is just how to wake up the waiting threads.

...

And you basically have gone through the list of wait mechanisms:

Message Queues

> 1) Open a message queue when the device is opened (a new queue for each task) and keep them in a list. Post to a non-blocking endpoint of these queues in the ISR. Read from a blocking endpoint in the device read(). I would need to generate names for the message queues, as there doesn't seem to be anonymous message queues?

...

If the interrupt level consumes all of the CONFIG_PREALLOC_MQ_MSGS messages, it will fall back and use the emergency pool of 8 pre-allocated messages. If those are also exhausted, then the message will not be sent and an interrupt is effectively lost.

Semaphores

> 2) Allocate a semaphore per each device open and keep them in a list. Post the semaphores when new data is available in a shared buffer. Read the data inside sched_lock().

...

The above code snippet is essentially what the NuttX pthread_cond_broadcast() does (see nuttx/sched/pthread_condbroadcast.c). In NuttX condition variables are really just wrappers around semaphores that give them a few new properties. You could even call pthread_cond_broadcast() from an interrupt handler: See http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_cond_signal.htmlImage RemovedImage Added for usage information.

Neither of the above mechanisms are portable uses of these interfaces. However, there is no portable interface for communicating directly with interrupt handlers.

...

NOTE: There is possibility of improper interactions between the semaphore when I is used for signaling and priority inheritance. In this case, you should disable priority inheritance on the signaling semaphore using sem_setprotocol(SEM_PRIO_NONE). See the signaling semaphore Wiki Page for further information.

Signals

> 3) Store the thread id's in a list when read() is called. Wake up the threads using{{ sigqueue()}}. Read the data from a shared buffer inside sched_lock().

...

The POSIX signal definition includes some support that would make this easier for you. This support is not currently implemented in NuttX. The kill() interface for example (http://pubs.opengroup.org/onlinepubs/009695399/functions/kill.htmlImage RemovedImage Added) supports this behavior:

...

NuttX does not currently support process groups. But that might be a good RTOS extension. If you and others think that would be useful I could probably add the basics of such a feature in a day or so.

poll()

> Is there some better way that I haven't discovered?

The obvious thing that you did not mention is poll(). See http://pubs.opengroup.org/onlinepubs/009695399/functions/poll.htmlImage RemovedImage Added . Since you are writing a device driver, support the poll() method in your driver seems to be the natural solution. See the drivers/ directory for many examples, drivers/pipes/pipe_common.c for one. Each thread could simply wait on poll(); when the event occurs the driver could then wake up the set of waiters. Under
the hood, this is again just a set of sem_post's. But it is also a very standard mechanism.

...

> > That would be something great! PX4 project has that implemented somehow
> > (in C++), so maybe - if license permits - it could be ported to NuttX in
> > no time?
>
> https://pixhawk.ethz.ch/px4/dev/shared_object_communicationImage RemovedImage Added

I don't know a lot about this, but it might be worth looking into if it matches your need.