summaryrefslogtreecommitdiffstats
path: root/cpukit/rtems/src/eventseize.c
blob: 0be6bd6f4501431c7a3e17b42f8b04640bb0685c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
 * @file
 *
 * @brief Event Manager Initialization
 * @ingroup ClassicEvent Events
 */

/*
 *  COPYRIGHT (c) 1989-2008.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.org/license/LICENSE.
 */

#if HAVE_CONFIG_H
  #include "config.h"
#endif

#include <rtems/sysinit.h>
#include <rtems/rtems/eventimpl.h>
#include <rtems/rtems/optionsimpl.h>
#include <rtems/score/threadimpl.h>
#include <rtems/score/watchdogimpl.h>

/*
 *  INTERRUPT LATENCY:
 *    available
 *    wait
 *    check sync
 */

void _Event_Seize(
  rtems_event_set    event_in,
  rtems_option       option_set,
  rtems_interval     ticks,
  rtems_event_set   *event_out,
  Thread_Control    *executing,
  Event_Control     *event,
  Thread_Wait_flags  wait_class,
  States_Control     block_state,
  ISR_lock_Context  *lock_context
)
{
  rtems_event_set    seized_events;
  rtems_event_set    pending_events;
  bool               success;
  Thread_Wait_flags  intend_to_block;
  Per_CPU_Control   *cpu_self;

  executing->Wait.return_code = RTEMS_SUCCESSFUL;

  pending_events = event->pending_events;
  seized_events  = _Event_sets_Get( pending_events, event_in );

  if ( !_Event_sets_Is_empty( seized_events ) &&
       (seized_events == event_in || _Options_Is_any( option_set )) ) {
    event->pending_events =
      _Event_sets_Clear( pending_events, seized_events );
    _Thread_Lock_release_default( executing, lock_context );
    *event_out = seized_events;
    return;
  }

  if ( _Options_Is_no_wait( option_set ) ) {
    _Thread_Lock_release_default( executing, lock_context );
    executing->Wait.return_code = RTEMS_UNSATISFIED;
    *event_out = seized_events;
    return;
  }

  intend_to_block = wait_class | THREAD_WAIT_STATE_INTEND_TO_BLOCK;

  /*
   *  Note what we are waiting for BEFORE we enter the critical section.
   *  The interrupt critical section management code needs this to be
   *  set properly when we are marked as in the event critical section.
   *
   *  NOTE: Since interrupts are disabled, this isn't that much of an
   *        issue but better safe than sorry.
   */
  executing->Wait.option          = option_set;
  executing->Wait.count           = event_in;
  executing->Wait.return_argument = event_out;
  _Thread_Wait_flags_set( executing, intend_to_block );

  cpu_self = _Thread_Dispatch_disable_critical( lock_context );
  _Thread_Lock_release_default( executing, lock_context );

  if ( ticks ) {
    _Thread_Wait_set_timeout_code( executing, RTEMS_TIMEOUT );
    _Thread_Timer_insert_relative(
      executing,
      cpu_self,
      _Thread_Timeout,
      ticks
    );
  }

  _Thread_Set_state( executing, block_state );

  /*
   * See _Event_Surrender() and _Thread_Timeout(), corresponding atomic
   * variable is Thread_Control::Wait::flags.
   */
  _Atomic_Fence( ATOMIC_ORDER_ACQUIRE );

  success = _Thread_Wait_flags_try_change(
    executing,
    intend_to_block,
    wait_class | THREAD_WAIT_STATE_BLOCKED
  );
  if ( !success ) {
    _Thread_Timer_remove( executing );
    _Thread_Unblock( executing );
  }

  _Thread_Dispatch_enable( cpu_self );
}

#if defined(RTEMS_MULTIPROCESSING)
static void _Event_Manager_initialization( void )
{
  _MPCI_Register_packet_processor( MP_PACKET_EVENT, _Event_MP_Process_packet );
}

RTEMS_SYSINIT_ITEM(
  _Event_Manager_initialization,
  RTEMS_SYSINIT_CLASSIC_EVENT,
  RTEMS_SYSINIT_ORDER_MIDDLE
);
#endif