Register Event for Foreign Thread

Discussions and support about ChibiOS/RT, the free embedded RTOS.
Thargon
Posts: 86
Joined: Wed Feb 04, 2015 5:03 pm
Location: CITEC, Bielefeld University, germany
Has thanked: 6 times
Been thanked: 12 times

Register Event for Foreign Thread

Postby Thargon » Fri May 11, 2018 12:50 pm

Hi,

important fact first: I am still using ChibiOS/RT 17.6 and I have not checked if this question still applies for 18.2.

I just want to register an event to an foreign thread (not 'currp').
In my case I have a control thread that configures several slaves, but calling 'chEvtRegister()' (or one of its siblings) will always register the specified event to the current thread ('currp' which is the control thread).

In 'chEvtRegisterMaskWithFlags()' (which is eventually called by its siblings) the member 'listener' of the specified event_source_t is set to 'currp', so I suppose that I is possible to have an additional argument to specify a custom thread object here. If that is possible according additional API functions like

Code: Select all

chEvtRegisterThread(event_source_t *esp, event_listener_t *elp, thread_t *tp, eventid_t event)
would be a nice feature ;)
Until then I could just modify the 'listener' member (and just hope that the non-atomicity of this approach will cause no trouble).

Thomas

User avatar
Giovanni
Site Admin
Posts: 11224
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 401 times
Been thanked: 333 times
Contact:

Re: Register Event for Foreign Thread

Postby Giovanni » Fri May 11, 2018 5:19 pm

Hi,

The usual pattern is that each thread registers on sources it is interested on, isn't this applicable in your scenario? threads should "know" which events they are going to listen.

Giovanni

Thargon
Posts: 86
Joined: Wed Feb 04, 2015 5:03 pm
Location: CITEC, Bielefeld University, germany
Has thanked: 6 times
Been thanked: 12 times

Re: Register Event for Foreign Thread

Postby Thargon » Mon May 14, 2018 9:21 am

Yes, I usually support this idea and so far it was completely fine for me. Actually I can still implement the wanted behavior following that pattern but only in a static way or with additional overhead. Let me give an example:

There are two threads A and B. Both are already running and communication is completely done via events, so no timeouts, no active polling of variables. At some point thread A wants to advertise a new event to B, so that B could listen to the according event source. But as long as there is no communication from A to B, A just cannot tell B about that event.
Also dynamic (de)activation of events is a use case for me. I would like to deactivate events (on the listener side) in certain situations dynamically. Unless the listening thread does this actively by itself, there is no solution but to react to according events by a NOP like behavior (detect but ignore event). I would like to safe this overhead be completely unregister the listener from the source and register again later. While unregistration can be triggered by an event, registration cannot, since the event has been deactivated -.-

I see three solutions to this issue:
  • All events must be registered during initialization, so no dynamic event subscription or (de)activation possible.
  • There is some sort of "fundamental event" or "control event" that is always active (from initialization until shutdown) that can be used for such control tasks but adds some constant overhead, of course.
  • There is a possibility to remotely manipulate events from another thread.

I know the latter can cause other issues and therefore should not be recommended, but I think offering the possibility would not hurt. Furthermore, if a thread must not manipulate another one, you should hide its reference in the first place.

Best regards,
Thomas

User avatar
Giovanni
Site Admin
Posts: 11224
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 401 times
Been thanked: 333 times
Contact:

Re: Register Event for Foreign Thread

Postby Giovanni » Mon May 14, 2018 11:03 am

Hi,

Let's assume we want to associated a new source to B, this mean also assign a event bit number and B would need to know the bit number beforehand in order to serve it. B should always have handlers for all events assignable to it.

This kind of situation could be best handled by modifying the mask of events B is interested in, if you make this mask a global variable then another thread can manipulate it. B would be always registered on all sources it can handle.

Giovanni

Thargon
Posts: 86
Joined: Wed Feb 04, 2015 5:03 pm
Location: CITEC, Bielefeld University, germany
Has thanked: 6 times
Been thanked: 12 times

Re: Register Event for Foreign Thread

Postby Thargon » Mon May 14, 2018 11:54 am

Hm, I often map multiple events to the same mask as long as they are of the same type, like 1 = OS event, 2 = I/O event, 3 = shell event, ...
In case there are multiple I/Os a thread listens to, for instance, I then check the flags of the listeners in case an event ocurred. I don't know any other way to circumvent the 32 bit limitation of masks and flags.

If I do as you said, I could only mask up to 32 event sources, which might be a limitation in certain situations. Moreover, all the event sources must be known to the listening thread during initialization or it must be informed in some way during operation, which eventually leads to the original problem. So in my case, that's no feasible solution.

Anyway, what is the argument not to provide methods like

Code: Select all

chEvtRegisterThread(event_source_t *esp, event_listener_t *elp, thread_t *tp, eventid_t event)
except that it is not recommended?

User avatar
Giovanni
Site Admin
Posts: 11224
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 401 times
Been thanked: 333 times
Contact:

Re: Register Event for Foreign Thread

Postby Giovanni » Mon May 14, 2018 12:24 pm

The limitation is 32 event sources registered with unique bits in the mask, you may have more than 32 as long multiple sources raise the same bit. This does not change regardless if the registration is done internally or externally. Using the mask you can ignore specific bits not specific sources if there is "bit sharing".

The way to circumvent the 32 bits limitation is to use the 32 additional bits that you can have for each listener, those are under control of the source. For example, the serial driver requires only one event bit in the mask but then it defines additional parity, overflow, framing, etc bits that are added to the listener. The grand total is 32x32 maximum bits.
Note that the meaning of the bits in the event mask are decided by the registered entity (the thread), the meaning of the bits in the listener are decided by the source.
If you have multiple "OS Events" then you need one bit in the mask, bits in the listener would tell which OS event if there are more than one kind.

Anyway I see it as forcing the events mechanism so I don't see it a good fit for an API enhancement but you could do that in user code, it is just adding an element to a list, there is no need for it to be an official API. There is no technical reason it could not be done.

Giovanni

Thargon
Posts: 86
Joined: Wed Feb 04, 2015 5:03 pm
Location: CITEC, Bielefeld University, germany
Has thanked: 6 times
Been thanked: 12 times

Re: Register Event for Foreign Thread

Postby Thargon » Mon May 14, 2018 1:08 pm

Yes, with the 32 bit limitation I meant the one-bit-per-source case. If sources share bits there can be any number (this is the way I do it).

However, I'm a bit confused right now regarding the terms 'mask' and 'flag'.
As I understand, a thread can register to a source by using a dedicated listener object. Doing so it defines a mask, which is ORed to the thread's member variable whenever an event is received. The source on the other hand can only propagate flags to all listeners, but cannot affect the threads masks directly. For more fine-grained filtering listeners can be configured so that only events with specific flags are propagated to the thread and the according flags are set in the listener object. That way one can distinguish a maximum of 32x32 events per thread.

In practice, however, this may not suffice. If I have two SerialDrivers, for instance, I would use the same mask for both sources to represent them as I/O event. Since I cannot (and don't want to) configure the SerialDriver objects regarding their flags, both objects will broadcast identical events and I can only distinguish them by checking the according listeners for their flags set. In order to deactivate a driver, I could set the flag filter of the according listener to 0x00, of course, but I would still have to check all listeners the one way or another.

Regarding doing what I want in user code: Unfortunately that is not trivial right now as well because of the 'chSysLock()' call in 'chEvtRegisterMaskWithFlags()'. If I want to register to a custom thread, I need to modify the 'listener' member of the event_listener_t object (the pointer to the listening thread) outside the locked region, which is bad. Alternatively, I could reimplement an according function from scratch, which is prone to break sooner or later.

Maybe a compromise could be an according S-Function? So basically 'chEvtRegisterMaskWithFlags()' without the locking and an according wrapper that just puts those two lines around the S-func call?

- Thomas

User avatar
Giovanni
Site Admin
Posts: 11224
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 401 times
Been thanked: 333 times
Contact:

Re: Register Event for Foreign Thread

Postby Giovanni » Mon May 14, 2018 1:26 pm

There are two distinct types eventmask_t and eventflags_t and must never be mixed, the former is the mask of the event sources registered in the thread, the latter are the flags posted into the listener by an event source. You simply cannot have two serial ports sharing the same event bit, flags would come from both serial ports and there would be no way to tell which one posted the flags.

Adding the S function would make no sense for the intended use of the subsystem (where is the thread registering itself), however, changing the pointer would not be a problem outside the critical zone, a 32 bit write is atomic, the critical zone is there because the list insertion.

That code is very unlikely to change anyway, it has been the same for ages now, you can safely clone it.

Note that both types are configurable in chtypes.h, you may extend masks to 64bits but I have never tested it (I did test 8, 16 and 32 so it should be fine).

Giovanni

Thargon
Posts: 86
Joined: Wed Feb 04, 2015 5:03 pm
Location: CITEC, Bielefeld University, germany
Has thanked: 6 times
Been thanked: 12 times

Re: Register Event for Foreign Thread

Postby Thargon » Mon May 14, 2018 2:02 pm

Giovanni wrote:Adding the S function would make no sense for the intended use of the subsystem (where is the thread registering itself), however, changing the pointer would not be a problem outside the critical zone, a 32 bit write is atomic, the critical zone is there because the list insertion.
If you say so. Setting all variables within a locked region still seems to be 'more correct' to me.

Giovanni wrote:Note that both types are configurable in chtypes.h, you may extend masks to 64bits but I have never tested it (I did test 8, 16 and 32 so it should be fine).
64 bit operations can be quite nasty on 32 bit machines since those are not atomic anymore. I guess that there is a lot of code which assumes operations with eventmask_t and eventflags_t to be atomic, which would not be the case anymore with 64 bit. It might work, it might fail, in any case it must not be considered to be safe. Anyway, 64 individual sources are better than 32 but still far from 'as many as you like'.

I think I will try the first solution I posted earlier (no dynamic event registration) and spice it up with a little bit of flag filtering. Mayhaps it will turn out that this is actually sufficient flexibility.

Thank you once again for your feedback, Giovanni!
- Thomas


Return to “ChibiOS/RT”

Who is online

Users browsing this forum: No registered users and 1 guest