The proper fix is to synchronize ipipe_catch_event(..., NULL) with the
event dispatcher, so that any caller could legitimately assume that no
subsequent call to the former handler will happen on any CPU after this
service has returned. Since ipipe_unregister_domain() may already
legitimately assume that all event handlers have been cleared using
ipipe_catch_event() by the caller before proceeding, the issue would be
solved.

That's I understand. I just said "a cleanup caller" which amongst other things does ipipe_unregister_domain. Although, yep. The latter one is not necessarily involved.

The difficult part is to refrain from masking the hw interrupts when
running the event handlers for the sake of keeping short latencies
(nothing would prevent those handlers to re-enable interrupts anyway).
IOW, using a big stick like the critical inter-CPU lock is not the
preferred option.

And it's not a good idea to get ipipe_catch_event() buzy spinning as (as I understand) ipipe_dispatch_event() may take, in general, an unbounded amount of time.

Ok, some more weird thoughts on top of my mind. I hope the idea is clear, notwithstanding my description that can be not that clear but hey... it's a late hour :)

----

ipipe_dispatch_event()
{

...

   ipipe_lock_cpu(flags);

   start_domain = this_domain = ipipe_percpu_domain[cpuid];

   list_for_each_safe(pos,npos,&__ipipe_pipeline) {

        next_domain = list_entry(pos,struct ipipe_domain,p_link);

+       event_handler = next_domain->evhand[event];

        if (next_domain->evhand[event] != NULL) {
                ipipe_percpu_domain[cpuid] = next_domain;
+               atomic_inc(&somewhere_stored->counter);
                ipipe_unlock_cpu(flags);

-               propagate = !next_domain->evhand[event](event,start_domain,data);
+               propagate = !event_handler(...);

              ipipe_lock_cpu(flags);
+               if (atomic_dec(&somewhere_stored->counter) == 0)
+                               send_virtual_irq(virt_irq, EVENT_TYPE, arg); // do it per interested domain
...
}

then ipipe_catch_event(..., NULL); should do something along the following lines :

ipipe_catch_event()
{
...

        lock() ; // not sure, it's even necessary

        set ipd->evhand[event] to NULL;

        unlock();


        // gets blocked
        ipipe_get_synched(EVENT_TYPE, arg);

...
}

ipipe_gets_synched()
-  lock
-  if somewhere_stored->counter != 0
- adds a caller to some wait queue (impl. depends on domain)
- unlock

- gets blocked.


virtual_irq_handler()

- lock
- wakeup_all_blocked for a given EVENT_TYPE and domain
- unlock


--
Best regards,
Dmitry Adamushko
_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core

Reply via email to