RTE OSAdapter POSIX 0.1.0 build 41b3eb3
POSIX/Linux OAL OSAdapter for Platform_RTE
Loading...
Searching...
No Matches
rte_posix_osadapter_lock.c
Go to the documentation of this file.
1/* _POSIX_C_SOURCE: glibc declares pthread_mutex_timedlock(), clock_gettime() and nanosleep() only under a POSIX
2 * feature-test macro (this product builds strict C99), same as mutex.c's own. */
3#define _POSIX_C_SOURCE 200809L
4
16
17#include <errno.h>
18#include <pthread.h>
19#include <stdbool.h>
20#include <stdint.h>
21#include <time.h>
22
24#define POSIX_LOCK_NS_PER_MS 1000000L
25#define POSIX_LOCK_NS_PER_S 1000000000L
26#if !defined(__linux__)
28#define POSIX_LOCK_POLL_NS 1000000L
29#endif
30
32
34static rte_status_t try_lock_once(pthread_mutex_t *mutex);
35static rte_status_t lock_until_deadline(pthread_mutex_t *mutex, rte_duration_ms_t timeout_ms);
36static void deadline_add_ms(struct timespec *ts, rte_duration_ms_t ms);
37
39
41
42
44rte_status_t posix_osa_lock_bounded(pthread_mutex_t *mutex, rte_duration_ms_t timeout_ms)
45{
46 rte_status_t status;
47
48 if (mutex == NULL)
49 {
50 status = RTE_STATUS_INVALID_PARAM;
51 }
52 else if (timeout_ms == 0U)
53 {
54 /* REQ-OAL-MUTEX-014: timeout_ms == 0 is one non-blocking try. */
55 status = try_lock_once(mutex);
56 }
57 else
58 {
59 status = lock_until_deadline(mutex, timeout_ms);
60 }
61 return status;
62}
63
64
65/****Local functions ****/
66
68static rte_status_t try_lock_once(pthread_mutex_t *mutex)
69{
70 rte_status_t status;
71 int rc = pthread_mutex_trylock(mutex);
72
73 if (rc == 0)
74 {
75 status = RTE_STATUS_OK;
76 }
77 else if (rc == EBUSY)
78 {
79 status = RTE_STATUS_TIMEOUT;
80 }
81 else
82 {
83 status = RTE_STATUS_INTERNAL_ERROR;
84 }
85 return status;
86}
87
88#if defined(__linux__)
90static rte_status_t lock_until_deadline(pthread_mutex_t *mutex, rte_duration_ms_t timeout_ms)
91{
92 rte_status_t status;
93 struct timespec deadline;
94
95 if (clock_gettime(CLOCK_REALTIME, &deadline) != 0)
96 {
97 status = RTE_STATUS_INTERNAL_ERROR; /* no deadline - never wait unbounded */
98 }
99 else
100 {
101 int rc;
102
103 deadline_add_ms(&deadline, timeout_ms);
104 rc = pthread_mutex_timedlock(mutex, &deadline);
105 if (rc == 0)
106 {
107 status = RTE_STATUS_OK;
108 }
109 else if (rc == ETIMEDOUT)
110 {
111 status = RTE_STATUS_TIMEOUT;
112 }
113 else
114 {
115 status = RTE_STATUS_INTERNAL_ERROR;
116 }
117 }
118 return status;
119}
120#else
123static rte_status_t lock_until_deadline(pthread_mutex_t *mutex, rte_duration_ms_t timeout_ms)
124{
125 rte_status_t status;
126 struct timespec deadline;
127
128 if (clock_gettime(CLOCK_MONOTONIC, &deadline) != 0)
129 {
130 status = RTE_STATUS_INTERNAL_ERROR; /* no deadline - never wait unbounded */
131 }
132 else
133 {
134 bool waiting;
135
136 deadline_add_ms(&deadline, timeout_ms);
137 status = try_lock_once(mutex);
138 waiting = (status == RTE_STATUS_TIMEOUT);
139 while (waiting)
140 {
141 struct timespec now;
142
143 if (clock_gettime(CLOCK_MONOTONIC, &now) != 0)
144 {
145 status = RTE_STATUS_INTERNAL_ERROR;
146 waiting = false;
147 }
148 else
149 {
150 int64_t remaining_ns = (((int64_t)deadline.tv_sec - (int64_t)now.tv_sec) * POSIX_LOCK_NS_PER_S) +
151 ((int64_t)deadline.tv_nsec - (int64_t)now.tv_nsec);
152
153 if (remaining_ns <= 0)
154 {
155 waiting = false; /* deadline reached: status stays RTE_STATUS_TIMEOUT */
156 }
157 else
158 {
159 struct timespec nap;
160
161 nap.tv_sec = 0;
162 nap.tv_nsec = (long)((remaining_ns < POSIX_LOCK_POLL_NS) ? remaining_ns : POSIX_LOCK_POLL_NS);
163 /* An EINTR only ends the sleep early; the deadline still bounds the loop. */
164 (void)nanosleep(&nap, NULL);
165 status = try_lock_once(mutex);
166 waiting = (status == RTE_STATUS_TIMEOUT);
167 }
168 }
169 }
170 }
171 return status;
172}
173#endif
174
176static void deadline_add_ms(struct timespec *ts, rte_duration_ms_t ms)
177{
178 rte_duration_ms_t whole_s = ms / 1000U;
179 rte_duration_ms_t rest_ms = ms % 1000U;
180
181 ts->tv_sec += (time_t)whole_s;
182 ts->tv_nsec += (long)rest_ms * POSIX_LOCK_NS_PER_MS;
183 if (ts->tv_nsec >= POSIX_LOCK_NS_PER_S)
184 {
185 ts->tv_sec += 1;
186 ts->tv_nsec -= POSIX_LOCK_NS_PER_S;
187 }
188}
rte_status_t posix_osa_lock_bounded(pthread_mutex_t *mutex, rte_duration_ms_t timeout_ms)
Waits at most timeout_ms for a pthread mutex.
static void deadline_add_ms(struct timespec *ts, rte_duration_ms_t ms)
static rte_status_t lock_until_deadline(pthread_mutex_t *mutex, rte_duration_ms_t timeout_ms)
static rte_status_t try_lock_once(pthread_mutex_t *mutex)
#define POSIX_LOCK_POLL_NS
#define POSIX_LOCK_NS_PER_MS
Private helper: a bounded wait for a pthread mutex (OSA rule R2: every wait bounded).