Hi,
When using chEvtBroadcastFlags the event flags (el_flags) of a event_listener_t are not cleared automatically when the event is triggered.
The problem is that this results in incorrect behaviour for functions that work with eventmasks, like chEvtGetAndClearEvents. This function can actually return the same event multiple times without the event source (event_source_t) triggering the corresponding flag more than once. This is a bug.
The issue comes from the fact that the flags are not cleared in the listener. This causes the listener to re-trigger an event whenever the event source broadcasts any flag, regardless of the wflags mask in the listener.
Only chEvtGetAndClearFlags provides correct clearing & returning of the triggered flags.
Since this behaviour is not documented anywhere (as far as I could find), this is a serious issue.
Best regards
Patrick
chevents: listener flags clearing (bug)
- Giovanni
- Site Admin
- Posts: 14891
- Joined: Wed May 27, 2009 8:48 am
- Has thanked: 1202 times
- Been thanked: 996 times
Re: chevents: listener flags clearing (bug)
HI,
The listening thread is meant to call chEvtGetAndClearFlags() in order to get and clear them, this is intentional.
All the event wait functions know nothing about the listener structure(s) so it can't be done in that context (there is no way starting from a thread to enumerate all the listener structures associated to the thread, the association is mono-directional listeners->thread, thread->listeners is not possible).
The broadcast function only sees that there are pending flags that are part of the wanted flags (el_wflags) so it signals the thread unless the flags are cleared.
Giovanni
The listening thread is meant to call chEvtGetAndClearFlags() in order to get and clear them, this is intentional.
All the event wait functions know nothing about the listener structure(s) so it can't be done in that context (there is no way starting from a thread to enumerate all the listener structures associated to the thread, the association is mono-directional listeners->thread, thread->listeners is not possible).
The broadcast function only sees that there are pending flags that are part of the wanted flags (el_wflags) so it signals the thread unless the flags are cleared.
Giovanni
-
Stapelzeiger
- Posts: 7
- Joined: Mon Apr 06, 2015 1:08 pm
Re: chevents: listener flags clearing (bug)
The point is that the function chEvtGetAndClearEvents doesn't do what it says i.e. clear the event, since it is retriggered as soon as the source broadcasts anything. This is very unintuitive and not documented.
For the implementation details: I see that the thread can't enumerate the listeners, but the broadcast function could still clear the flags as soon as it wakes up the thread (and maybe store a copy if needed for readout later, for the chEvtGetAndClearFlags API).
For the implementation details: I see that the thread can't enumerate the listeners, but the broadcast function could still clear the flags as soon as it wakes up the thread (and maybe store a copy if needed for readout later, for the chEvtGetAndClearFlags API).
- Giovanni
- Site Admin
- Posts: 14891
- Joined: Wed May 27, 2009 8:48 am
- Has thanked: 1202 times
- Been thanked: 996 times
Re: chevents: listener flags clearing (bug)
Wait, there are two kind of flags there:
1) Events Mask (eventmask_t), this is a per-thread mask and is cleared inside the "wait" functions. The function returns the cleared flags.
2) Event Flags (evenflags_t), this is information generated by sources and is accumulated (ORed) inside the listener structures. This has to be cleared as an acknowledge by chEvtGetAndClearFlags() or you will be notified again.
Are you referring to 1 or 2?
chEvtGetAndClearEvents() clears the type 1 and seldom used, it can be used in order to start from a clean state.
Giovanni
1) Events Mask (eventmask_t), this is a per-thread mask and is cleared inside the "wait" functions. The function returns the cleared flags.
2) Event Flags (evenflags_t), this is information generated by sources and is accumulated (ORed) inside the listener structures. This has to be cleared as an acknowledge by chEvtGetAndClearFlags() or you will be notified again.
Are you referring to 1 or 2?
chEvtGetAndClearEvents() clears the type 1 and seldom used, it can be used in order to start from a clean state.
Giovanni
-
Stapelzeiger
- Posts: 7
- Joined: Mon Apr 06, 2015 1:08 pm
Re: chevents: listener flags clearing (bug)
1) doesn't really clear the event (yes, sure it clears the event in the thread, but this isn't really anything useful).
2) does what it says.
The thing is that when working with event masks (eventmask_t) the function chEvtGetAndClearEvents doesn't clear the event at the listener. So you have to call chEvtGetAndClearFlags to really clear the event. This is not the behaviour one would expect and doesn't seem to be documented. I'm sure that I'm not the only one who misunderstood that bit, since it is only evident when reading the implementation of chflags.
I looked quickly through the code again. What I suggest is that as soon as the event flags (el_flags) in the listener match the mask (el_wflags) the el_flags are cleared and an event is generated for the task. This should result in expected behaviour for the chEvtGetAndClearEvents & chEvtWait* functions.
To keep the current behaviour of the chEvtGetAndClearFlags API the el_flags could be copied in the listener before being cleared. Then the chEvtGetAndClearFlags could return the (el_flags | el_flags_copy) and clear both.
2) does what it says.
The thing is that when working with event masks (eventmask_t) the function chEvtGetAndClearEvents doesn't clear the event at the listener. So you have to call chEvtGetAndClearFlags to really clear the event. This is not the behaviour one would expect and doesn't seem to be documented. I'm sure that I'm not the only one who misunderstood that bit, since it is only evident when reading the implementation of chflags.
I looked quickly through the code again. What I suggest is that as soon as the event flags (el_flags) in the listener match the mask (el_wflags) the el_flags are cleared and an event is generated for the task. This should result in expected behaviour for the chEvtGetAndClearEvents & chEvtWait* functions.
To keep the current behaviour of the chEvtGetAndClearFlags API the el_flags could be copied in the listener before being cleared. Then the chEvtGetAndClearFlags could return the (el_flags | el_flags_copy) and clear both.
- Giovanni
- Site Admin
- Posts: 14891
- Joined: Wed May 27, 2009 8:48 am
- Has thanked: 1202 times
- Been thanked: 996 times
Re: chevents: listener flags clearing (bug)
Hi,
Consider that events and event flags are two distinct things. It is possible to work with events without having to use event flags.
Consider this scenario: a thread is signaled directly using chEvtSignal(), this only use events, event flags are not used at all, why should chEvtGetAndClearEvents() clear also flags? there aren't listener nor flags involved.
Flags are only part of the (optional) broadcasting mechanism, this is why you won't see any handling of those in those functions only dealing with events. Flags are only handled in the context of the event_listener_t object.
I can agree documentation could be better, for some reason I seem to be unable to fully explain the mechanism.
Giovanni
Consider that events and event flags are two distinct things. It is possible to work with events without having to use event flags.
Consider this scenario: a thread is signaled directly using chEvtSignal(), this only use events, event flags are not used at all, why should chEvtGetAndClearEvents() clear also flags? there aren't listener nor flags involved.
Flags are only part of the (optional) broadcasting mechanism, this is why you won't see any handling of those in those functions only dealing with events. Flags are only handled in the context of the event_listener_t object.
I can agree documentation could be better, for some reason I seem to be unable to fully explain the mechanism.
Giovanni
-
Stapelzeiger
- Posts: 7
- Joined: Mon Apr 06, 2015 1:08 pm
Re: chevents: listener flags clearing (bug)
Consider that events and event flags are two distinct things. It is possible to work with events without having to use event flags.
I got that.
why should chEvtGetAndClearEvents() clear also flags?
I don't want the function to actually go and clear flags in the listeners. This would not respect the separation between flags and events, and besides it would be hard to implement.
What I suggest is that the listener clears its own flags as soon as it has notified the thread (using chEvtSignal) so that it won't signal the thread again for the same flag.
- Giovanni
- Site Admin
- Posts: 14891
- Joined: Wed May 27, 2009 8:48 am
- Has thanked: 1202 times
- Been thanked: 996 times
Re: chevents: listener flags clearing (bug)
OK, and how the thread would know which flags were involved if those have been cleared?
Giovanni
Giovanni
-
Stapelzeiger
- Posts: 7
- Joined: Mon Apr 06, 2015 1:08 pm
Re: chevents: listener flags clearing (bug)
you could create a copy inside the listener. (what i suggested in my comment above to keep the existing flags API)
- Giovanni
- Site Admin
- Posts: 14891
- Joined: Wed May 27, 2009 8:48 am
- Has thanked: 1202 times
- Been thanked: 996 times
Re: chevents: listener flags clearing (bug)
That would increase the size of the listener and I need a good reason for increasing RAM usage and breaking compatibility.
It is not a bug anyway, it is working as intended.
Giovanni
It is not a bug anyway, it is working as intended.
Giovanni