Blame view

RIOT/core/include/thread_flags.h 5.93 KB
a752c7ab   elopes   add first test an...
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  /*
   * Copyright (C) 2015 Kaspar Schleiser <kaspar@schleiser.de>
   *
   * This file is subject to the terms and conditions of the GNU Lesser
   * General Public License v2.1. See the file LICENSE in the top level
   * directory for more details.
   */
  
  /**
   * @defgroup    core_thread_flags Thread Flags
   * @ingroup     core
   * @brief       Thread flags
   *
   * This API can be used to notify threads of conditions in a race-free
   * and allocation-less way.
   *
   * Each thread can handle up to 16 boolean flags, stored as a bitmask in the
   * flags field of its thread.  Those flags can be set or unset, using
   * thread_flags_set(), from ISR's, other threads or even by the thread itself.
   *
   * A thread can wait for any combination of its flags to become set, using
   * thread_flags_wait_any() or thread_flags_wait_all().
   * Those functions clear flags that caused them to return.
   * It is not possible to wait for flags to become unset.
   *
   * Thread flags have certain properties that make them the preferred choice
   * over messages or mutexes in some circumstances:
   *
   * - setting thread flags cannot fail
   *   If messages are used to notify a thread of a condition from within an ISR,
   *   and the receiving thread is not waiting, has no queue or the queue is
   *   full, the ISR cannot deliver the message. A thread flag can always be set.
   *
   * - thread flags are very flexible
   *   With thread flags it is possible to wait for multiple conditions and
   *   messages at the same time. When mutexes are used to notify about events,
   *   only one event can be waited for.
   *
   * Usually, if it is only of interest that an event occurred, but not how many
   * of them, thread flags should be considered.
   *
   * Note that some flags (currently the three most significant bits) are used by
   * core functions and should not be set by the user. They can be waited for.
   *
   * This API is optional and must be enabled by adding "core_thread_flags" to USEMODULE.
   *
   * @{
   *
   * @file
   * @brief       Thread Flags API
   *
   * @author      Kaspar Schleiser <kaspar@schleiser.de>
   */
  #ifndef THREAD_FLAGS_H
  #define THREAD_FLAGS_H
  
  #ifndef MODULE_CORE_THREAD_FLAGS
  #error Missing USEMODULE += core_thread_flags
  #endif
  
  #include "kernel_types.h"
  #include "sched.h"  /* for thread_t typedef */
  
  #ifdef __cplusplus
   extern "C" {
  #endif
  
  /**
   * @name reserved thread flags
   * @{
   */
  
  /**
   * @brief Set when a message becomes available
   *
   * This flag is set for a thread if a message becomes available either by being
   * queued in the thread's message queue or by another thread becoming
   * send-blocked.
   *
   * It is only reset through thread_flags_wait_*(), not by msg_receive().
   *
   * One thread flag event might point to one, many or no messages ready to be
   * received.  It is advisable to use the non-blocking @ref msg_try_receive() in
   * a loop to retrieve the messages.
   * Use e.g., the following pattern when waiting for both thread flags and
   * messages:
   *
   *      while(1) {
   *          thread_flags_t flags = thread_flags_wait_any(0xFFFF);
   *          if (flags & THREAD_FLAG_MSG_WAITING) {
   *              msg_t msg;
   *              while (msg_try_receive(&msg) == 1) {
   *                  [ handle msg ]
   *              }
   *          }
   *          ...
   *      }
   */
  #define THREAD_FLAG_MSG_WAITING      (0x1<<15)
  /**
   * @brief Set by @ref xtimer_set_timeout_flag() when the timer expires
   *
   * @see xtimer_set_timeout_flag
   */
  #define THREAD_FLAG_TIMEOUT          (0x1<<14)
  /** @} */
  
  /**
   * @brief Type definition of thread_flags_t
   */
  typedef uint16_t thread_flags_t;
  
  /**
   * @brief Set thread flags, possibly waking it up
   *
   * @param[in]   thread     thread to work on
   * @param[in]   mask    additional flags to be set for the current thread,
   *                      represented as a bitmask
   */
  void thread_flags_set(thread_t *thread, thread_flags_t mask);
  
  /**
   * @brief Clear current thread's flags
   *
   * @param[in]   mask    unset flags for the current thread,
   *                      represented as a bitmask
   *
   * @returns     flags that have actually been cleared (mask & thread->flags before clear)
   */
  thread_flags_t thread_flags_clear(thread_flags_t mask);
  
  /**
   * @brief Wait for any flag in mask to become set (blocking)
   *
   * If any of the flags in mask are already set, this function will return
   * immediately, otherwise, it will suspend the thread (as
   * THREAD_STATUS_WAIT_ANY) until any of the flags in mask get set.
   *
   * Both ways, it will clear and return (sched_active_thread-flags & mask).
   *
   * @param[in]   mask    mask of flags to wait for
   *
   * @returns     flags that caused return/wakeup ((sched_active_thread-flags & mask).
   */
  thread_flags_t thread_flags_wait_any(thread_flags_t mask);
  
  /**
   * @brief Wait for all flags in mask to become set (blocking)
   *
   * If all the flags in mask are already set, this function will return
   * immediately, otherwise, it will suspend the thread (as
   * THREAD_STATUS_WAIT_ALL) until all of the flags in mask have been set.
   *
   * Both ways, it will clear and return (sched_active_thread-flags & mask).
   *
   * @param[in]   mask    mask of flags to wait for
   *
   * @returns     mask
   */
  thread_flags_t thread_flags_wait_all(thread_flags_t mask);
  
  /**
   * @brief Wait for any flags in mask to become set (blocking), one at a time
   *
   * This function is like thread_flags_wait_any(), but will only clear and return
   * one flag at a time, least significant set bit first.
   *
   * @param[in]   mask    mask of flags to wait for
   *
   * @returns     flag that triggered the return / wait
   */
  thread_flags_t thread_flags_wait_one(thread_flags_t mask);
  
  /**
   * @brief Possibly Wake up thread waiting for flags
   *
   * Wakes up a thread if it is thread flag blocked and its condition is met.
   * Has to be called with interrupts disabled.
   * Does not trigger yield.
   *
   * @internal
   *
   * @param[in]   thread  thread to possibly wake up
   * @return      1       if @p thread has been woken up
   *              0       otherwise
   */
  int thread_flags_wake(thread_t *thread);
  
  #ifdef __cplusplus
  }
  #endif
  
  #endif /* THREAD_FLAGS_H */
  /** @} */