dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_thread.c
Go to the documentation of this file.
1 
11 /*
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful, but
18  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20  * for more details.
21  *
22  * You should have received a copy of the GNU General Public License along
23  * with this program; if not, see <http://www.gnu.org/licenses/>
24  */
25 
26 
27 #include <pthread.h>
28 #include <unistd.h>
29 
30 #include <pios.h>
31 #include <pios_thread.h>
32 
33 #include <hwsimulation.h>
34 
35 bool __attribute__((weak)) are_realtime;
36 
37 struct pios_thread
38 {
39  pthread_t thread;
40 
41  const char *name;
42 };
43 
51 struct pios_thread *PIOS_Thread_WrapCurrentThread(const char *namep)
52 {
53  struct pios_thread *thread = PIOS_malloc_no_dma(sizeof(struct pios_thread));
54 
55  if (!thread) {
56  abort();
57  }
58 
59  thread->thread = pthread_self();
60 
61  thread->name = namep;
62 
63  if (are_realtime) {
64  struct sched_param param = {
65  .sched_priority = 30 + PIOS_THREAD_PRIO_HIGHEST * 5
66  };
67 
68  pthread_setschedparam(thread->thread, SCHED_RR, &param);
69  }
70 
71 #ifdef __linux__
72  pthread_setname_np(thread->thread, thread->name);
73 #endif
74 
75  return thread;
76 }
77 
79 {
80  (void) prio;
81 #ifdef __linux__
82  if (are_realtime) {
83  int pri_val = 30 + prio * 5;
84  pthread_setschedprio(pthread_self(), pri_val);
85  }
86 #endif
87 }
88 
89 struct pios_thread *PIOS_Thread_Create(void (*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
90 {
91  struct pios_thread *thread = malloc(sizeof(*thread));
92 
93  pthread_attr_t attr;
94 
95  if (pthread_attr_init(&attr)) {
96  perror("pthread_attr_init");
97  abort();
98  }
99 
100  if (are_realtime) {
101  struct sched_param param = {
102  .sched_priority = 30 + prio * 5
103  };
104 
105  pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
106  pthread_attr_setschedpolicy(&attr, SCHED_RR);
107  pthread_attr_setschedparam(&attr, &param);
108  }
109 
110  thread->name = namep;
111 
112  void *(*thr_func)(void *) = (void *) fp;
113 
114  int ret = pthread_create(&thread->thread, &attr, thr_func, argp);
115 
116  if (ret) {
117  printf("Couldn't start thr (%s) ret=%d\n", namep, ret);
118 
119  free(thread);
120  return NULL;
121  }
122 
123 #ifdef __linux__
124  pthread_setname_np(thread->thread, thread->name);
125 #endif
126 
127  printf("Started thread (%s) p=%p\n", namep, &thread->thread);
128 
129  return thread;
130 }
131 
132 void PIOS_Thread_Delete(struct pios_thread *threadp)
133 {
134  if (threadp != NULL) {
135  abort(); // Only support this on "self"
136  }
137 
138 #if 0
139  /* Need to figure out our own thread structure to clean it up */
140  free(threadp->name);
141  free(threadp);
142 #endif
143 
144  pthread_exit(0);
145 }
146 
147 static volatile uint32_t fake_clock;
148 static pthread_cond_t fake_clock_cond = PTHREAD_COND_INITIALIZER;
149 static pthread_mutex_t fake_clock_mutex = PTHREAD_MUTEX_INITIALIZER;
150 
151 static inline uint32_t PIOS_Thread_GetClock_Impl()
152 {
153  struct timespec monotime;
154 
155  clock_gettime(CLOCK_MONOTONIC, &monotime);
156 
157  return monotime.tv_sec * 1000 + monotime.tv_nsec / 1000000;
158 }
159 
160 #ifdef PIOS_INCLUDE_FAKETICK
161 static volatile uint32_t fake_tick_barrier;
162 
163 void PIOS_Thread_FakeClock_UpdateBarrier(uint32_t increment)
164 {
165  pthread_mutex_lock(&fake_clock_mutex);
166 
167  fake_tick_barrier = fake_clock + increment;
168  pthread_cond_broadcast(&fake_clock_cond);
169 
170  pthread_mutex_unlock(&fake_clock_mutex);
171 }
172 
173 void PIOS_Thread_FakeClock_Tick(void)
174 {
175  bool blocked = false;
176 
177  pthread_mutex_lock(&fake_clock_mutex);
178 
179  while ((fake_tick_barrier) && (fake_tick_barrier == fake_clock)) {
180  if (!blocked) {
181  uint8_t val = 1;
182  HwSimulationFakeTickBlockedSet(&val);
183  }
184 
185  blocked = true;
186 
187  pthread_cond_wait(&fake_clock_cond, &fake_clock_mutex);
188  }
189 
190  if (blocked) {
191  uint8_t val = 0;
192  HwSimulationFakeTickBlockedSet(&val);
193  }
194 
195  if (fake_clock == 0) {
196  fake_clock = PIOS_Thread_GetClock_Impl() + 1;
197  } else {
198  fake_clock++;
199  }
200 
201  pthread_cond_broadcast(&fake_clock_cond);
202 
203  pthread_mutex_unlock(&fake_clock_mutex);
204 }
205 #endif
206 
208 {
209  return fake_clock != 0;
210 }
211 
212 uint32_t PIOS_Thread_Systime(void)
213 {
214  uint32_t t = fake_clock;
215 
216  if (!t) {
218  }
219 
220  static uint32_t base = 0;
221 
222  if (!base) {
223  base = t;
224  }
225 
226  return t - base;
227 }
228 
229 void PIOS_Thread_Sleep(uint32_t time_ms)
230 {
231  if (time_ms == PIOS_THREAD_TIMEOUT_MAX) {
232  while (true) {
233  usleep(50000000); /* 50s */
234  }
235  }
236 
237  if (fake_clock) {
238  pthread_mutex_lock(&fake_clock_mutex);
239 
240  uint32_t expiration = fake_clock + time_ms;
241 
242  while ((expiration - fake_clock) <= time_ms) {
243  pthread_cond_wait(&fake_clock_cond,
244  &fake_clock_mutex);
245  }
246 
247  pthread_mutex_unlock(&fake_clock_mutex);
248 
249  return;
250  }
251 
252  usleep(1000 * time_ms);
253 }
254 
255 void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
256 {
257  *previous_ms += increment_ms;
258 
259  uint32_t now = PIOS_Thread_Systime();
260 
261  uint32_t ms = *previous_ms - now;
262 
263  if (ms > increment_ms) {
264  // Very late or wrapped.
265  *previous_ms = now;
266  } else if (ms > 0) {
267  PIOS_Thread_Sleep(ms);
268  }
269 }
270 
271 uint32_t PIOS_Thread_Get_Stack_Usage(struct pios_thread *threadp)
272 {
273  return 0; /* XXX */
274 }
275 
276 uint32_t PIOS_Thread_Get_Runtime(struct pios_thread *threadp)
277 {
278  return 0; /* XXX */
279 }
280 
281 bool PIOS_Thread_Period_Elapsed(const uint32_t prev_systime,
282  const uint32_t increment_ms)
283 {
284  uint32_t now = PIOS_Thread_Systime();
285 
286  uint32_t interval = now - prev_systime;
287 
288  return increment_ms <= interval;
289 }
290 
uint32_t PIOS_Thread_Systime(void)
Definition: pios_thread.c:212
int clock_gettime(clockid_t clk_id, struct timespec *t)
void weak
Definition: pios_heap.c:124
Main PiOS header to include all the compiled in PiOS options.
static uint32_t PIOS_Thread_GetClock_Impl()
Definition: pios_thread.c:151
#define PIOS_THREAD_TIMEOUT_MAX
Definition: pios_thread.h:29
void * PIOS_malloc_no_dma(size_t size)
Definition: pios_heap.c:166
static pthread_cond_t fake_clock_cond
Definition: pios_thread.c:148
void PIOS_Thread_ChangePriority(enum pios_thread_prio_e prio)
Definition: pios_thread.c:78
struct pios_thread * PIOS_Thread_Create(void(*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
Definition: pios_thread.c:89
#define CLOCK_MONOTONIC
Definition: pios_posix.h:60
bool PIOS_Thread_Period_Elapsed(const uint32_t prev_systime, const uint32_t increment_ms)
Determine if a period has elapsed since a datum.
Definition: pios_thread.c:281
void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
Definition: pios_thread.c:255
static volatile uint32_t fake_clock
Definition: pios_thread.c:147
void PIOS_Thread_Sleep(uint32_t time_ms)
Definition: pios_thread.c:229
uint32_t PIOS_Thread_Get_Stack_Usage(struct pios_thread *threadp)
Definition: pios_thread.c:271
struct UAVOBase base
pios_thread_prio_e
Definition: pios_thread.h:57
int printf(const char *format,...)
uint32_t PIOS_Thread_Get_Runtime(struct pios_thread *threadp)
Definition: pios_thread.c:276
bool __attribute__((weak))
Definition: pios_thread.c:35
void PIOS_Thread_Delete(struct pios_thread *threadp)
Definition: pios_thread.c:132
struct pios_thread * PIOS_Thread_WrapCurrentThread(const char *namep)
Creates a handle for the current thread.
Definition: pios_thread.c:51
bool PIOS_Thread_FakeClock_IsActive(void)
Definition: pios_thread.c:207
static pthread_mutex_t fake_clock_mutex
Definition: pios_thread.c:149