Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
Select.cxx
Go to the documentation of this file.
1
34#include <fcntl.h>
35#include <sys/select.h>
36
37#include "Devtab.hxx"
38
40static OSEvent wakeup;
41
45static OSEventType get_event()
46{
47 static int thread_count = 0;
48 OSEventType event =
49#if tskKERNEL_VERSION_MAJOR >= 9
50 /* FreeRTOS 9.x+ implementation */
51 (OSEventType)pvTaskGetThreadLocalStoragePointer(
52 nullptr, TLS_INDEX_SELECT_EVENT_BIT);
53#else
54 /* legacy implementation uses task tag */
55 (OSEventType)xTaskGetApplicationTaskTag(nullptr);
56#endif
57
58 if (event == 0)
59 {
60 if(thread_count >= OSEvent::number_of_bits())
61 {
62 thread_count = 0;
63 }
64 event = 0x1 << thread_count;
65#if defined (TLS_INDEX_SELECT_EVENT_BIT)
66 /* FreeRTOS 9.x+ implementation */
67 vTaskSetThreadLocalStoragePointer(nullptr, TLS_INDEX_SELECT_EVENT_BIT,
68 (void*)event);
69#else
70 /* legacy implementation uses task tag */
71 vTaskSetApplicationTaskTag(nullptr, (void*)event);
72#endif
73 ++thread_count;
74 }
75 return event;
76}
77
79{
80 portENTER_CRITICAL();
81 OSEventType event = get_event();
82 portEXIT_CRITICAL();
83 wakeup.clear(event);
84}
85
96int Device::select(int nfds, fd_set *readfds, fd_set *writefds,
97 fd_set *exceptfds, long long timeout)
98{
99 long long until = 0;
100 if (timeout >= 0)
101 {
102 until = OSTime::get_monotonic() + timeout;
103 }
104 fd_set rd_result;
105 fd_set wr_result;
106 fd_set ex_result;
107
108 int mode_type[] = {FREAD, FWRITE, 0};
109 fd_set *in_set[3] = {readfds, writefds, exceptfds};
110 fd_set *out_set[3] = {&rd_result, &wr_result, &ex_result};
111 int number = 0;
112
113 FD_ZERO(&rd_result);
114 FD_ZERO(&wr_result);
115 FD_ZERO(&ex_result);
116
117 portENTER_CRITICAL();
118 OSEventType event = get_event();
119 portEXIT_CRITICAL();
120
121 bool first = true;
122
123 for ( ; /* forever */ ; )
124 {
125 /* cycle through all the FD Sets */
126 for (int mode = 0; mode < 3; ++mode)
127 {
128 if (in_set[mode])
129 {
130 /* cycle through all the file descriptors */
131 for (int i = 0; i < nfds; ++i)
132 {
133 if (FD_ISSET(i, in_set[mode]))
134 {
135 File *file = file_lookup(i);
136 if (!file)
137 {
138 /* errno should already be set appropriately */
139 return -1;
140 }
141 if (file->dev->select(file, mode_type[mode]))
142 {
143 /* active */
144 FD_SET(i, out_set[mode]);
145 ++number;
146 }
147 }
148 }
149 }
150 }
151
152 if (number)
153 {
154 /* We have a read */
155 if (readfds)
156 {
157 *readfds = rd_result;
158 }
159 if (writefds)
160 {
161 *writefds = wr_result;
162 }
163 if (exceptfds)
164 {
165 *exceptfds = ex_result;
166 }
167 return number;
168 }
169 // We only run two rounds of this loop; if the event bit was signaled,
170 // our thread was likely woken up by a signal.
171 if (!first) {
172 errno = EINTR;
173 return -1;
174 }
175 first = false;
176
177 if (until)
178 {
179 long long now = OSTime::get_monotonic();
180 if (now >= until)
181 {
182 return 0;
183 }
184 wakeup.timedwait(event, NULL, true, OSEvent::WAIT_ANY, until - now);
185 }
186 else
187 {
188 /* block forever until fd active */
189 wakeup.wait(event, NULL, true, OSEvent::WAIT_ANY);
190 }
191 }
192}
193
198{
202 portENTER_CRITICAL();
203 info->event |= get_event();
204 portEXIT_CRITICAL();
205}
206
211{
212 portENTER_CRITICAL();
213 if (info->event != 0)
214 {
215 wakeup.set(info->event);
216 info->event = 0;
217 }
218 portEXIT_CRITICAL();
219}
220
225{
226 if (info->event != 0)
227 {
228 wakeup.set_from_isr(info->event, woken);
229 info->event = 0;
230 }
231 if (woken)
232 {
233#ifdef GCC_CM3
234 portYIELD_FROM_ISR(*woken);
235#elif defined(THUMB_INTERWORK) // armv4t
236 if (*woken)
237 {
238 portYIELD_FROM_ISR();
239 }
240#else
241 os_isr_exit_yield_test(*woken);
242#endif
243 }
244}
static OSEventType get_event()
Returns an event bit unique to the current thread.
Definition Select.cxx:45
static OSEvent wakeup
event used to wakeup select calls
Definition Select.cxx:40
static File * file_lookup(int fd)
Looks up a reference to a File corresponding to a given file descriptor.
Definition Fileio.cxx:82
virtual bool select(File *file, int mode)
Device select method.
Definition Devtab.hxx:226
static long long get_monotonic()
Get the monotonic time since the system started.
Definition OS.hxx:560
#define FWRITE
Workaround for missing header defines on some newlib versions.
Definition fcntl.h:58
#define FREAD
Workaround for missing header defines on some newlib versions.
Definition fcntl.h:53
Select wakeup information.
Definition Devtab.hxx:491
OSEventType event
bit mask of clients that need woken
Definition Devtab.hxx:500
static void select_wakeup_from_isr(SelectInfo *info, int *woken)
Wakeup the list of clients needing woken.
Definition Select.cxx:224
static void select_insert(SelectInfo *info)
Add client to list of clients needing woken.
Definition Select.cxx:197
static Device * first
first device in linked list
Definition Devtab.hxx:535
static void select_wakeup(SelectInfo *info)
Wakeup the list of clients needing woken.
Definition Select.cxx:210
static int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, long long timeout)
POSIX select().
Definition Select.cxx:96
static void select_clear()
Clears the current thread's select bits.
Definition Select.cxx:78
File information.
Definition Devtab.hxx:52
FileIO * dev
file operations
Definition Devtab.hxx:53