os_port_posix.c
Go to the documentation of this file.
1 /**
2  * @file os_port_posix.c
3  * @brief RTOS abstraction layer (POSIX Threads)
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 2.4.4
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL TRACE_LEVEL_OFF
31 
32 //Dependencies
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <sys/time.h>
37 #include "os_port.h"
38 #include "os_port_posix.h"
39 #include "debug.h"
40 
41 //Pthread start routine
42 typedef void *(*PthreadTaskCode) (void *param);
43 
44 //Default task parameters
46 {
47  0, //Size of the stack
48  0 //Task priority
49 };
50 
51 
52 /**
53  * @brief Kernel initialization
54  **/
55 
56 void osInitKernel(void)
57 {
58  //Not implemented
59 }
60 
61 
62 /**
63  * @brief Start kernel
64  **/
65 
66 void osStartKernel(void)
67 {
68  //Not implemented
69 }
70 
71 
72 /**
73  * @brief Create a task
74  * @param[in] name NULL-terminated string identifying the task
75  * @param[in] taskCode Pointer to the task entry function
76  * @param[in] arg Argument passed to the task function
77  * @param[in] params Task parameters
78  * @return Task identifier referencing the newly created task
79  **/
80 
81 OsTaskId osCreateTask(const char_t *name, OsTaskCode taskCode, void *arg,
82  const OsTaskParameters *params)
83 {
84  int_t ret;
85  pthread_t thread;
86 
87  //Create a new thread
88  ret = pthread_create(&thread, NULL, (PthreadTaskCode) taskCode, arg);
89 
90  //Return a pointer to the newly created thread
91  if(ret == 0)
92  {
93  return (OsTaskId) thread;
94  }
95  else
96  {
97  return OS_INVALID_TASK_ID;
98  }
99 }
100 
101 
102 /**
103  * @brief Delete a task
104  * @param[in] taskId Task identifier referencing the task to be deleted
105  **/
106 
107 void osDeleteTask(OsTaskId taskId)
108 {
109  //Delete the calling thread?
110  if(taskId == OS_SELF_TASK_ID)
111  {
112  //Kill ourselves
113  pthread_exit(NULL);
114  }
115 }
116 
117 
118 /**
119  * @brief Delay routine
120  * @param[in] delay Amount of time for which the calling task should block
121  **/
122 
124 {
125  //Delay the task for the specified duration
126  usleep(delay * 1000);
127 }
128 
129 
130 /**
131  * @brief Yield control to the next task
132  **/
133 
134 void osSwitchTask(void)
135 {
136  //Not implemented
137 }
138 
139 
140 /**
141  * @brief Suspend scheduler activity
142  **/
143 
145 {
146  //Not implemented
147 }
148 
149 
150 /**
151  * @brief Resume scheduler activity
152  **/
153 
155 {
156  //Not implemented
157 }
158 
159 
160 /**
161  * @brief Create an event object
162  * @param[in] event Pointer to the event object
163  * @return The function returns TRUE if the event object was successfully
164  * created. Otherwise, FALSE is returned
165  **/
166 
168 {
169  int_t ret;
170 
171  //Create a semaphore object
172  ret = sem_init(event, 0, 0);
173 
174  //Check whether the semaphore was successfully created
175  if(ret == 0)
176  {
177  return TRUE;
178  }
179  else
180  {
181  return FALSE;
182  }
183 }
184 
185 
186 /**
187  * @brief Delete an event object
188  * @param[in] event Pointer to the event object
189  **/
190 
191 void osDeleteEvent(OsEvent *event)
192 {
193  //Properly dispose the event object
194  sem_destroy(event);
195 }
196 
197 
198 /**
199  * @brief Set the specified event object to the signaled state
200  * @param[in] event Pointer to the event object
201  **/
202 
203 void osSetEvent(OsEvent *event)
204 {
205  int_t ret;
206  int_t value;
207 
208  //Get the current value of the semaphore
209  ret = sem_getvalue(event, &value);
210 
211  //Nonsignaled state?
212  if(ret == 0 && value == 0)
213  {
214  //Set the specified event to the signaled state
215  sem_post(event);
216  }
217 }
218 
219 
220 /**
221  * @brief Set the specified event object to the nonsignaled state
222  * @param[in] event Pointer to the event object
223  **/
224 
225 void osResetEvent(OsEvent *event)
226 {
227  int_t ret;
228 
229  //Force the specified event to the nonsignaled state
230  do
231  {
232  //Decrement the semaphore's count by one
233  ret = sem_trywait(event);
234 
235  //Check status
236  } while(ret == 0);
237 }
238 
239 
240 /**
241  * @brief Wait until the specified event is in the signaled state
242  * @param[in] event Pointer to the event object
243  * @param[in] timeout Timeout interval
244  * @return The function returns TRUE if the state of the specified object is
245  * signaled. FALSE is returned if the timeout interval elapsed
246  **/
247 
249 {
250  int_t ret;
251  struct timespec ts;
252 
253  //Wait until the specified event is in the signaled state or the timeout
254  //interval elapses
255  if(timeout == 0)
256  {
257  //Non-blocking call
258  ret = sem_trywait(event);
259  }
260  else if(timeout == INFINITE_DELAY)
261  {
262  //Infinite timeout period
263  ret = sem_wait(event);
264  }
265  else
266  {
267  //Get current time
268  clock_gettime(CLOCK_REALTIME, &ts);
269 
270  //Set absolute timeout
271  ts.tv_sec += timeout / 1000;
272  ts.tv_nsec += (timeout % 1000) * 1000000;
273 
274  //Normalize time stamp value
275  if(ts.tv_nsec >= 1000000000)
276  {
277  ts.tv_sec += 1;
278  ts.tv_nsec -= 1000000000;
279  }
280 
281  //Wait until the specified event becomes set
282  ret = sem_timedwait(event, &ts);
283  }
284 
285  //Check whether the specified event is set
286  if(ret == 0)
287  {
288  //Force the event back to the nonsignaled state
289  do
290  {
291  //Decrement the semaphore's count by one
292  ret = sem_trywait(event);
293 
294  //Check status
295  } while(ret == 0);
296 
297  //The specified event is in the signaled state
298  return TRUE;
299  }
300  else
301  {
302  //The timeout interval elapsed
303  return FALSE;
304  }
305 }
306 
307 
308 /**
309  * @brief Set an event object to the signaled state from an interrupt service routine
310  * @param[in] event Pointer to the event object
311  * @return TRUE if setting the event to signaled state caused a task to unblock
312  * and the unblocked task has a priority higher than the currently running task
313  **/
314 
316 {
317  //Not implemented
318  return FALSE;
319 }
320 
321 
322 /**
323  * @brief Create a semaphore object
324  * @param[in] semaphore Pointer to the semaphore object
325  * @param[in] count The maximum count for the semaphore object. This value
326  * must be greater than zero
327  * @return The function returns TRUE if the semaphore was successfully
328  * created. Otherwise, FALSE is returned
329  **/
330 
332 {
333  int_t ret;
334 
335  //Create a semaphore object
336  ret = sem_init(semaphore, 0, count);
337 
338  //Check whether the semaphore was successfully created
339  if(ret == 0)
340  {
341  return TRUE;
342  }
343  else
344  {
345  return FALSE;
346  }
347 }
348 
349 
350 /**
351  * @brief Delete a semaphore object
352  * @param[in] semaphore Pointer to the semaphore object
353  **/
354 
356 {
357  //Properly dispose the semaphore object
358  sem_destroy(semaphore);
359 }
360 
361 
362 /**
363  * @brief Wait for the specified semaphore to be available
364  * @param[in] semaphore Pointer to the semaphore object
365  * @param[in] timeout Timeout interval
366  * @return The function returns TRUE if the semaphore is available. FALSE is
367  * returned if the timeout interval elapsed
368  **/
369 
371 {
372  int_t ret;
373  struct timespec ts;
374 
375  //Wait until the semaphore is available or the timeout interval elapses
376  if(timeout == 0)
377  {
378  //Non-blocking call
379  ret = sem_trywait(semaphore);
380  }
381  else if(timeout == INFINITE_DELAY)
382  {
383  //Infinite timeout period
384  ret = sem_wait(semaphore);
385  }
386  else
387  {
388  //Get current time
389  clock_gettime(CLOCK_REALTIME, &ts);
390 
391  //Set absolute timeout
392  ts.tv_sec += timeout / 1000;
393  ts.tv_nsec += (timeout % 1000) * 1000000;
394 
395  //Normalize time stamp value
396  if(ts.tv_nsec >= 1000000000)
397  {
398  ts.tv_sec += 1;
399  ts.tv_nsec -= 1000000000;
400  }
401 
402  //Wait until the specified semaphore becomes available
403  ret = sem_timedwait(semaphore, &ts);
404  }
405 
406  //Check whether the specified semaphore is available
407  if(ret == 0)
408  {
409  return TRUE;
410  }
411  else
412  {
413  return FALSE;
414  }
415 }
416 
417 
418 /**
419  * @brief Release the specified semaphore object
420  * @param[in] semaphore Pointer to the semaphore object
421  **/
422 
424 {
425  //Release the semaphore
426  sem_post(semaphore);
427 }
428 
429 
430 /**
431  * @brief Create a mutex object
432  * @param[in] mutex Pointer to the mutex object
433  * @return The function returns TRUE if the mutex was successfully
434  * created. Otherwise, FALSE is returned
435  **/
436 
438 {
439  int_t ret;
440 
441  //Create a mutex object
442  ret = pthread_mutex_init(mutex, NULL);
443 
444  //Check whether the mutex was successfully created
445  if(ret == 0)
446  {
447  return TRUE;
448  }
449  else
450  {
451  return FALSE;
452  }
453 }
454 
455 
456 /**
457  * @brief Delete a mutex object
458  * @param[in] mutex Pointer to the mutex object
459  **/
460 
461 void osDeleteMutex(OsMutex *mutex)
462 {
463  //Properly dispose the mutex object
464  pthread_mutex_destroy(mutex);
465 }
466 
467 
468 /**
469  * @brief Acquire ownership of the specified mutex object
470  * @param[in] mutex Pointer to the mutex object
471  **/
472 
474 {
475  //Obtain ownership of the mutex object
476  pthread_mutex_lock(mutex);
477 }
478 
479 
480 /**
481  * @brief Release ownership of the specified mutex object
482  * @param[in] mutex Pointer to the mutex object
483  **/
484 
486 {
487  //Release ownership of the mutex object
488  pthread_mutex_unlock(mutex);
489 }
490 
491 
492 /**
493  * @brief Retrieve system time
494  * @return Number of milliseconds elapsed since the system was last started
495  **/
496 
498 {
499  struct timeval tv;
500 
501  //Get current time
502  gettimeofday(&tv, NULL);
503 
504  //Convert resulting value to milliseconds
505  return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
506 }
507 
508 
509 /**
510  * @brief Allocate a memory block
511  * @param[in] size Bytes to allocate
512  * @return A pointer to the allocated memory block or NULL if
513  * there is insufficient memory available
514  **/
515 
516 __weak_func void *osAllocMem(size_t size)
517 {
518  //Allocate a memory block
519  return malloc(size);
520 }
521 
522 
523 /**
524  * @brief Release a previously allocated memory block
525  * @param[in] p Previously allocated memory block to be freed
526  **/
527 
528 __weak_func void osFreeMem(void *p)
529 {
530  //Free memory block
531  free(p);
532 }
#define usleep(delay)
Definition: os_port.h:303
int bool_t
Definition: compiler_port.h:53
signed int int_t
Definition: compiler_port.h:49
uint8_t p
Definition: ndp.h:300
#define TRUE
Definition: os_port.h:50
#define OS_INVALID_TASK_ID
Event object.
char_t name[]
bool_t osCreateSemaphore(OsSemaphore *semaphore, uint_t count)
Create a semaphore object.
OsTaskId osCreateTask(const char_t *name, OsTaskCode taskCode, void *arg, const OsTaskParameters *params)
Create a task.
Definition: os_port_posix.c:81
systime_t osGetSystemTime(void)
Retrieve system time.
#define OS_SELF_TASK_ID
Semaphore object.
bool_t osWaitForSemaphore(OsSemaphore *semaphore, systime_t timeout)
Wait for the specified semaphore to be available.
bool_t osCreateEvent(OsEvent *event)
Create an event object.
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
#define FALSE
Definition: os_port.h:46
int32_t tv_sec
Definition: bsd_socket.h:573
void osResetEvent(OsEvent *event)
Set the specified event object to the nonsignaled state.
void osStartKernel(void)
Start kernel.
Definition: os_port_posix.c:66
void osDeleteMutex(OsMutex *mutex)
Delete a mutex object.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
void(* OsTaskCode)(void *arg)
Task routine.
void osInitKernel(void)
Kernel initialization.
Definition: os_port_posix.c:56
__weak_func void osFreeMem(void *p)
Release a previously allocated memory block.
const OsTaskParameters OS_TASK_DEFAULT_PARAMS
Definition: os_port_posix.c:45
void osReleaseMutex(OsMutex *mutex)
Release ownership of the specified mutex object.
void osDeleteTask(OsTaskId taskId)
Delete a task.
Task parameters.
int32_t tv_usec
Definition: bsd_socket.h:574
void osReleaseSemaphore(OsSemaphore *semaphore)
Release the specified semaphore object.
void osAcquireMutex(OsMutex *mutex)
Acquire ownership of the specified mutex object.
void osDeleteEvent(OsEvent *event)
Delete an event object.
void osDeleteSemaphore(OsSemaphore *semaphore)
Delete a semaphore object.
Mutex object.
uint32_t systime_t
System time.
char char_t
Definition: compiler_port.h:48
RTOS abstraction layer (POSIX Threads)
Timeout structure.
Definition: bsd_socket.h:572
bool_t osWaitForEvent(OsEvent *event, systime_t timeout)
Wait until the specified event is in the signaled state.
void osSwitchTask(void)
Yield control to the next task.
uint8_t value[]
Definition: tcp.h:369
void *(* PthreadTaskCode)(void *param)
Definition: os_port_posix.c:42
__weak_func void * osAllocMem(size_t size)
Allocate a memory block.
thread_t * OsTaskId
Task identifier.
bool_t osCreateMutex(OsMutex *mutex)
Create a mutex object.
unsigned int uint_t
Definition: compiler_port.h:50
void osResumeAllTasks(void)
Resume scheduler activity.
void osSuspendAllTasks(void)
Suspend scheduler activity.
RTOS abstraction layer.
Debugging facilities.
#define INFINITE_DELAY
Definition: os_port.h:75
void osDelayTask(systime_t delay)
Delay routine.