Events sent to a task entering rtems_event_receive() may be lost
Joel Sherrill
joel.sherrill at OARcorp.com
Tue Jun 1 15:18:12 UTC 2004
Bummer about GNATS since I think there is a bug report pending
which matches this and it has a fix with it. You might want to
page through the mailing list since 4.6.1 to see if it got
cross-posted there.
--joel
Mick Davis wrote:
> Bug report; GNATS is down
>
> Originator
> Mick Davis
>
> Organization
> Microsol (Aust)
>
> Confidential
> no
>
> Synopsis
> Events sent to a task entering rtems_event_receive() may be lost
>
> Severty
> serious
>
> Priority
> medium
>
> Category
> rtems
>
> Release
> 4.5.0 and 4.6.1 see description
>
> Environment
> Motorola coldfire 5307 (m68k) target, cygwin tools.
>
> Description
> Although we are using RTEMS 4.5.0, we have replaced the files event*.c
> with those from 4.6.1 to address previously
>
> reported problems with lost events.
>
> The problem here is that events may be lost when sent to a task which enters
> rtems_event_receive() with options set to wait
>
> with a timeout and to return on receipt of any event.
>
> The events are sent from an interrupt source such as a timer service
> routine. If more than one set of events is sent to the
>
> task before it returns, the first event set may be overwritten.
>
> Using a debug logging function for the task which receives the event and the
> timer service routine which sends the event, it
>
> was seen that the following happened;
>
> 1) Task entered rtems_event_receive (RTEMS_ALL_EVENTS, RTEMS_EVENT_ANY |
> RTEMS_WAIT, TEST_INTERVAL, &rx_event)
> 2) Timer service routine sent event 1
> 3) Timer service routine sent event 2
> 4) Timer service routine sent event 3
> 5) Task returned successfully from rtems_event_receive() with events 2 and 3
> 6) Event 1 was never received with successive calls to rtems_event_receive()
>
> A review of the event code led to the following analysis and successful fix.
>
> The task enters the function rtems_event_receive() and then _Event_Seize()
> in eventseize.c.
>
> For the case of no pending events, the task does not immediately return from
> this function. At line 91 of eventseize.c, the
>
> function enables interrupts in order to begin a timeout to wait for sent
> events. At the time the function enables interrupts,
>
> the variable _Event_Sync_state has been set to EVENT_SYNC_NOTHING_HAPPENED
> but the call to set the thread state to
>
> STATES_WAITING_FOR_EVENT has not been made (Line 103).
>
> If the task is now interrupted with a call from the timer service routine to
> rtems_event_send(), execution continues in
>
> eventsend.c .
>
> The new events are set in the task's pending events variable, and the
> service routine enters _Event_Surrender() in
>
> eventsurrender.c .
>
> Since the task is waiting for the new events, execution enters the block
>
> if ( !_Event_sets_Is_empty( seized_events ) ) {
>
> However, since the task has not yet set the waiting for event flag, the code
> does not enter the block
>
> if ( _States_Is_waiting_for_event( the_thread->current_state ) )
>
> and proceeds to the switch statement for the variable _Event_Sync_state,
> entering the case for EVENT_SYNC_NOTHING_HAPPENED.
>
> Since the thread is executing, and the option to return on any event is set,
> the Wait.return_argument is set to the value of
>
> seized_events and these events are cleared from those which are pending. The
> timer service routine then returns.
>
> At this point, if the task resumes execution, the sent events will be
> received correctly. However, if a second timer service
>
> routine is pending, hen execution will reenter _Event_Surrender(). The same
> path may be followed, and since the second set of
>
> new events will also satisfy the options used in the call to
> rtems_event_receive(), they will also be written to the
>
> Wait.return_argument and cleared from the pending events, which will
> overwrite the value of Wait.return_argument set by the
>
> first timer service routine. This means the events set by the first timer
> service routine are not returned to the task, and
>
> are lost.
>
>
> How-To-Repeat
> Sample code is attached.
>
> The problem may be demonstrated with a number of tasks which use
> rtems_timer_fire_after() to run a service routine which
>
> sends an event to the same task. The delay used to fire the timer should be
> the same as the delay used to timeout the call to
>
> rtems_event_receive (), which is quickly re entered. In this way, events are
> being sent to the task as it enters
>
> rtems_event_receive ().
>
>
> Fix
> Diff file to eventsurrender.c is attached.
>
> The fix I propose is similar to that used in PR584, which closed another
> window. After writing the seized_events to
>
> the_thread->Wait.return_argument at line 99 of eventsurrender.c, this
> variable may be protected by clearing
>
> the_thread->Wait.count . That is, in eventsurrender.c
>
> 98a99
>
>> (rtems_event_set) the_thread->Wait.count = 0;
>
>
> Successive calls to rtems_event_send() will post events to the task's
> pending_events, but these events will not be included
>
> in the task's return because in _Event_Surrender() the event_condition will
> be 0, and no event can satisfy the wait
>
> condition.
>
> This fix was found to return the events previously lost when using the test
> code attached.
>
>
> Mick Davis
> Microsol (Aust) Pty Ltd
> mickd AT microsol.iinet.net.au
>
>
More information about the users
mailing list