PyEventEngine 0.6.2__cp315-cp315-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- event_engine/__infra__.pxd +2 -0
- event_engine/__init__.pxd +2 -0
- event_engine/__init__.py +62 -0
- event_engine/base/__infra__.pxd +9 -0
- event_engine/base/__init__.pxd +9 -0
- event_engine/base/__init__.py +31 -0
- event_engine/base/c_allocator_protocol.c +14310 -0
- event_engine/base/c_allocator_protocol.cp315-win_amd64.pyd +0 -0
- event_engine/base/c_allocator_protocol.h +23 -0
- event_engine/base/c_allocator_protocol.pxd +31 -0
- event_engine/base/c_allocator_protocol.pyx +193 -0
- event_engine/capi/__infra__.pxd +189 -0
- event_engine/capi/__init__.pxd +189 -0
- event_engine/capi/__init__.py +84 -0
- event_engine/capi/c_engine.c +32542 -0
- event_engine/capi/c_engine.cp315-win_amd64.pyd +0 -0
- event_engine/capi/c_engine.h +393 -0
- event_engine/capi/c_engine.pxd +84 -0
- event_engine/capi/c_engine.pyi +478 -0
- event_engine/capi/c_engine.pyx +673 -0
- event_engine/capi/c_event.c +22826 -0
- event_engine/capi/c_event.cp315-win_amd64.pyd +0 -0
- event_engine/capi/c_event.h +342 -0
- event_engine/capi/c_event.pxd +159 -0
- event_engine/capi/c_event.pyi +265 -0
- event_engine/capi/c_event.pyx +444 -0
- event_engine/capi/c_topic.c +34545 -0
- event_engine/capi/c_topic.cp315-win_amd64.pyd +0 -0
- event_engine/capi/c_topic.h +1007 -0
- event_engine/capi/c_topic.pxd +147 -0
- event_engine/capi/c_topic.pyi +644 -0
- event_engine/capi/c_topic.pyx +818 -0
- event_engine/capi/fallback_engine.py +707 -0
- event_engine/config_view.c +10271 -0
- event_engine/config_view.cp315-win_amd64.pyd +0 -0
- event_engine/config_view.pyx +55 -0
- event_engine/includes/event_engine/base/c_allocator_protocol.c +14310 -0
- event_engine/includes/event_engine/base/c_allocator_protocol.h +23 -0
- event_engine/includes/event_engine/capi/c_engine.c +32542 -0
- event_engine/includes/event_engine/capi/c_engine.h +393 -0
- event_engine/includes/event_engine/capi/c_event.c +22826 -0
- event_engine/includes/event_engine/capi/c_event.h +342 -0
- event_engine/includes/event_engine/capi/c_topic.c +34545 -0
- event_engine/includes/event_engine/capi/c_topic.h +1007 -0
- event_engine/includes/event_engine/config_view.c +10271 -0
- event_engine/native/__init__.py +60 -0
- event_engine/native/_event.py +420 -0
- event_engine/native/_topic.py +171 -0
- event_engine/native/engine.py +793 -0
- event_engine/native/event.py +469 -0
- event_engine/native/topic.py +943 -0
- pyeventengine-0.6.2.dist-info/METADATA +189 -0
- pyeventengine-0.6.2.dist-info/RECORD +56 -0
- pyeventengine-0.6.2.dist-info/WHEEL +5 -0
- pyeventengine-0.6.2.dist-info/licenses/LICENSE +21 -0
- pyeventengine-0.6.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
#ifndef C_ENGINE_H
|
|
2
|
+
#define C_ENGINE_H
|
|
3
|
+
|
|
4
|
+
#include <errno.h>
|
|
5
|
+
#include <stdatomic.h>
|
|
6
|
+
#include <stdint.h>
|
|
7
|
+
#include <stdlib.h>
|
|
8
|
+
#include <string.h>
|
|
9
|
+
#include <time.h>
|
|
10
|
+
|
|
11
|
+
#ifdef _WIN32
|
|
12
|
+
#include <cbase/nt/pthread_nt_compat.h>
|
|
13
|
+
#include <cbase/nt/time_sched_nt_compat.h>
|
|
14
|
+
#else
|
|
15
|
+
#include <pthread.h>
|
|
16
|
+
#include <sched.h>
|
|
17
|
+
#endif
|
|
18
|
+
|
|
19
|
+
#include <cbase/allocator_protocol/c_allocator_protocol.h>
|
|
20
|
+
#include <event_engine/capi/c_event.h>
|
|
21
|
+
#include <event_engine/capi/c_topic.h>
|
|
22
|
+
|
|
23
|
+
/* Default capacity if not provided elsewhere */
|
|
24
|
+
#ifndef DEFAULT_MQ_CAPACITY
|
|
25
|
+
#define DEFAULT_MQ_CAPACITY 0x0fff
|
|
26
|
+
#endif
|
|
27
|
+
|
|
28
|
+
/* Hybrid spin limit (number of busy iterations before blocking) */
|
|
29
|
+
#ifndef DEFAULT_MQ_SPIN_LIMIT
|
|
30
|
+
#define DEFAULT_MQ_SPIN_LIMIT 0xffff
|
|
31
|
+
#endif
|
|
32
|
+
|
|
33
|
+
/* Default timeout in seconds for blocking operations */
|
|
34
|
+
#ifndef DEFAULT_MQ_TIMEOUT_SECONDS
|
|
35
|
+
#define DEFAULT_MQ_TIMEOUT_SECONDS 1.0
|
|
36
|
+
#endif
|
|
37
|
+
|
|
38
|
+
/* @brief In-memory ring-buffer message queue
|
|
39
|
+
*
|
|
40
|
+
* The buffer is a flexible array member placed last so the whole queue + buffer
|
|
41
|
+
* can be allocated in one block for better locality and simpler allocation.
|
|
42
|
+
*/
|
|
43
|
+
typedef struct message_queue {
|
|
44
|
+
size_t capacity; // max number of entries
|
|
45
|
+
size_t head; // index to pop
|
|
46
|
+
size_t tail; // index to push
|
|
47
|
+
size_t count; // current count
|
|
48
|
+
evt_topic* topic; // topic this queue is bound to (may be NULL)
|
|
49
|
+
|
|
50
|
+
pthread_mutex_t mutex;
|
|
51
|
+
pthread_cond_t not_empty;
|
|
52
|
+
pthread_cond_t not_full;
|
|
53
|
+
|
|
54
|
+
#ifdef _WIN32
|
|
55
|
+
evt_message_payload* buf[1]; // MSVC-compatible trailing storage
|
|
56
|
+
#else
|
|
57
|
+
evt_message_payload* buf[]; // flexible array member
|
|
58
|
+
#endif
|
|
59
|
+
} message_queue;
|
|
60
|
+
|
|
61
|
+
/* ----------------------------------------------------------------------
|
|
62
|
+
* Signatures and Documentation
|
|
63
|
+
* --------------------------------------------------------------------*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @brief Create a new message queue.
|
|
67
|
+
* @param capacity maximum number of entries (must be > 0)
|
|
68
|
+
* @param topic optional Topic to bind the queue to (may be NULL)
|
|
69
|
+
* @param allocator allocator_protocol for the allocation
|
|
70
|
+
* @return pointer to newly allocated message_queue or NULL on allocation failure
|
|
71
|
+
*/
|
|
72
|
+
static inline message_queue* c_mq_new(size_t capacity, evt_topic* topic, allocator_protocol* allocator);
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @brief Destroy a message queue.
|
|
76
|
+
* @param mq pointer to message_queue to destroy
|
|
77
|
+
* @return 0 on success, -1 on invalid argument
|
|
78
|
+
*
|
|
79
|
+
* Note: does not free evt_message_payload pointers still present in the buffer;
|
|
80
|
+
* caller is responsible for draining/freeing them before calling.
|
|
81
|
+
*/
|
|
82
|
+
static inline int c_mq_free(message_queue* mq);
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @brief Non-blocking put into the queue.
|
|
86
|
+
* @param mq queue pointer
|
|
87
|
+
* @param msg pointer to evt_message_payload (caller-owned)
|
|
88
|
+
* @return 0 on success, -1 on full/invalid args
|
|
89
|
+
*/
|
|
90
|
+
static inline int c_mq_put(message_queue* mq, evt_message_payload* msg);
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @brief Non-blocking get from the queue.
|
|
94
|
+
* @param mq queue pointer
|
|
95
|
+
* @param out_msg out parameter to receive evt_message_payload*
|
|
96
|
+
* @return 0 on success, -1 on empty/invalid args
|
|
97
|
+
*/
|
|
98
|
+
static inline int c_mq_get(message_queue* mq, evt_message_payload** out_msg);
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @brief Blocking put; waits until space available or timeout.
|
|
102
|
+
* @param mq queue pointer
|
|
103
|
+
* @param msg pointer to evt_message_payload
|
|
104
|
+
* @param timeout_seconds maximum seconds to wait (<=0 means wait forever)
|
|
105
|
+
* @return 0 on success, -1 on timeout/invalid args or error
|
|
106
|
+
*/
|
|
107
|
+
static inline int c_mq_put_await(message_queue* mq, evt_message_payload* msg, double timeout_seconds);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @brief Blocking get; waits until an item is available or timeout.
|
|
111
|
+
* @param mq queue pointer
|
|
112
|
+
* @param out_msg out parameter to receive evt_message_payload*
|
|
113
|
+
* @param timeout_seconds maximum seconds to wait (<=0 means wait forever)
|
|
114
|
+
* @return 0 on success, -1 on timeout/invalid args or error
|
|
115
|
+
*/
|
|
116
|
+
static inline int c_mq_get_await(message_queue* mq, evt_message_payload** out_msg, double timeout_seconds);
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @brief Busy-looping put (spin up to max_spin times until space).
|
|
120
|
+
* @param mq queue pointer
|
|
121
|
+
* @param msg pointer to evt_message_payload
|
|
122
|
+
* @param max_spin maximum spin attempts before giving up
|
|
123
|
+
* @return 0 on success, -1 on full/invalid args or if max_spin reached
|
|
124
|
+
*/
|
|
125
|
+
static inline int c_mq_put_busy(message_queue* mq, evt_message_payload* msg, size_t max_spin);
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* @brief Busy-looping get (spin up to max_spin times until item).
|
|
129
|
+
* @param mq queue pointer
|
|
130
|
+
* @param out_msg out parameter to receive evt_message_payload*
|
|
131
|
+
* @param max_spin maximum spin attempts before giving up
|
|
132
|
+
* @return 0 on success, -1 on empty/invalid args or if max_spin reached
|
|
133
|
+
*/
|
|
134
|
+
static inline int c_mq_get_busy(message_queue* mq, evt_message_payload** out_msg, size_t max_spin);
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @brief Hybrid put: busy-spin for a short while then block (timeout does not include spin time).
|
|
138
|
+
* @param mq queue pointer
|
|
139
|
+
* @param msg pointer to evt_message_payload
|
|
140
|
+
* @param timeout_seconds maximum seconds to wait in blocking phase (<=0 means wait forever)
|
|
141
|
+
* @return 0 on success, -1 on timeout/invalid args or error
|
|
142
|
+
*/
|
|
143
|
+
static inline int c_mq_put_hybrid(message_queue* mq, evt_message_payload* msg, size_t max_spin, double timeout_seconds);
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* @brief Hybrid get: busy-spin for a short while then block (timeout does not include spin time).
|
|
147
|
+
* @param mq queue pointer
|
|
148
|
+
* @param out_msg out parameter to receive evt_message_payload*
|
|
149
|
+
* @param timeout_seconds maximum seconds to wait in blocking phase (<=0 means wait forever)
|
|
150
|
+
* @return 0 on success, -1 on timeout/invalid args or error
|
|
151
|
+
*/
|
|
152
|
+
static inline int c_mq_get_hybrid(message_queue* mq, evt_message_payload** out_msg, size_t max_spin, double timeout_seconds);
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* @brief Get current occupied count of the queue.
|
|
156
|
+
* @param mq queue pointer
|
|
157
|
+
* @return number of occupied entries, or 0 on invalid arg
|
|
158
|
+
*/
|
|
159
|
+
static inline size_t c_mq_occupied(message_queue* mq);
|
|
160
|
+
|
|
161
|
+
/* ----------------------------------------------------------------------
|
|
162
|
+
* Implementations
|
|
163
|
+
* --------------------------------------------------------------------*/
|
|
164
|
+
|
|
165
|
+
/* Helper: add seconds (fractional allowed) to timespec */
|
|
166
|
+
static inline void timespec_add_seconds(struct timespec* ts, double seconds) {
|
|
167
|
+
time_t sec = (time_t) seconds;
|
|
168
|
+
long nsec = (long) ((seconds - (double) sec) * 1e9);
|
|
169
|
+
ts->tv_sec += sec;
|
|
170
|
+
ts->tv_nsec += nsec;
|
|
171
|
+
if (ts->tv_nsec >= 1000000000L) {
|
|
172
|
+
ts->tv_sec += 1;
|
|
173
|
+
ts->tv_nsec -= 1000000000L;
|
|
174
|
+
}
|
|
175
|
+
else if (ts->tv_nsec < 0) {
|
|
176
|
+
ts->tv_sec -= 1;
|
|
177
|
+
ts->tv_nsec += 1000000000L;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/* Create a new queue. Returns NULL on allocation failure. */
|
|
182
|
+
static inline message_queue* c_mq_new(size_t capacity, evt_topic* topic, allocator_protocol* allocator) {
|
|
183
|
+
if (capacity == 0) return NULL;
|
|
184
|
+
|
|
185
|
+
#ifdef _WIN32
|
|
186
|
+
size_t total_bytes = sizeof(message_queue) + (capacity - 1) * sizeof(evt_message_payload*);
|
|
187
|
+
#else
|
|
188
|
+
size_t total_bytes = sizeof(message_queue) + capacity * sizeof(evt_message_payload*);
|
|
189
|
+
#endif
|
|
190
|
+
|
|
191
|
+
message_queue* mq = (message_queue*) c_ap_alloc(total_bytes, allocator);
|
|
192
|
+
if (!mq) return NULL;
|
|
193
|
+
|
|
194
|
+
mq->capacity = capacity;
|
|
195
|
+
mq->head = mq->tail = mq->count = 0;
|
|
196
|
+
mq->topic = topic;
|
|
197
|
+
|
|
198
|
+
pthread_mutex_init(&mq->mutex, NULL);
|
|
199
|
+
pthread_cond_init(&mq->not_empty, NULL);
|
|
200
|
+
pthread_cond_init(&mq->not_full, NULL);
|
|
201
|
+
|
|
202
|
+
return mq;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/* Destroy queue. Does not free message payloads pointed to by entries. */
|
|
206
|
+
static inline int c_mq_free(message_queue* mq) {
|
|
207
|
+
if (!mq) return -1;
|
|
208
|
+
|
|
209
|
+
pthread_mutex_lock(&mq->mutex);
|
|
210
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
211
|
+
pthread_cond_destroy(&mq->not_empty);
|
|
212
|
+
pthread_cond_destroy(&mq->not_full);
|
|
213
|
+
pthread_mutex_destroy(&mq->mutex);
|
|
214
|
+
|
|
215
|
+
c_ap_free(mq);
|
|
216
|
+
return 0;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* Non-blocking put. Returns 0 on success, -1 on full/invalid args. */
|
|
220
|
+
static inline int c_mq_put(message_queue* mq, evt_message_payload* msg) {
|
|
221
|
+
if (!mq || !msg) return -1;
|
|
222
|
+
int ret = -1;
|
|
223
|
+
pthread_mutex_lock(&mq->mutex);
|
|
224
|
+
if (mq->count == mq->capacity) {
|
|
225
|
+
ret = -1; /* full */
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
mq->buf[mq->tail] = msg;
|
|
229
|
+
mq->tail = (mq->tail + 1) % mq->capacity;
|
|
230
|
+
mq->count++;
|
|
231
|
+
pthread_cond_signal(&mq->not_empty);
|
|
232
|
+
ret = 0;
|
|
233
|
+
}
|
|
234
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
235
|
+
return ret;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* Non-blocking get. On success *out_msg is set and returns 0. Returns -1 if empty/invalid args. */
|
|
239
|
+
static inline int c_mq_get(message_queue* mq, evt_message_payload** out_msg) {
|
|
240
|
+
if (!mq || !out_msg) return -1;
|
|
241
|
+
int ret = -1;
|
|
242
|
+
pthread_mutex_lock(&mq->mutex);
|
|
243
|
+
if (mq->count == 0) {
|
|
244
|
+
ret = -1; /* empty */
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
*out_msg = mq->buf[mq->head];
|
|
248
|
+
mq->buf[mq->head] = NULL;
|
|
249
|
+
mq->head = (mq->head + 1) % mq->capacity;
|
|
250
|
+
mq->count--;
|
|
251
|
+
pthread_cond_signal(&mq->not_full);
|
|
252
|
+
ret = 0;
|
|
253
|
+
}
|
|
254
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
255
|
+
return ret;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* Blocking put. Waits until space is available. Returns 0 on success, -1 on error. */
|
|
259
|
+
static inline int c_mq_put_await(message_queue* mq, evt_message_payload* msg, double timeout_seconds) {
|
|
260
|
+
if (!mq || !msg) return -1;
|
|
261
|
+
pthread_mutex_lock(&mq->mutex);
|
|
262
|
+
struct timespec ts;
|
|
263
|
+
if (timeout_seconds > 0) {
|
|
264
|
+
clock_gettime(CLOCK_REALTIME, &ts);
|
|
265
|
+
timespec_add_seconds(&ts, timeout_seconds);
|
|
266
|
+
}
|
|
267
|
+
while (mq->count == mq->capacity) {
|
|
268
|
+
if (timeout_seconds > 0) {
|
|
269
|
+
int rc = pthread_cond_timedwait(&mq->not_full, &mq->mutex, &ts);
|
|
270
|
+
if (rc == ETIMEDOUT) {
|
|
271
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
272
|
+
return -1;
|
|
273
|
+
}
|
|
274
|
+
if (rc != 0 && rc != EINTR) {
|
|
275
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
276
|
+
return -1;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
pthread_cond_wait(&mq->not_full, &mq->mutex);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
mq->buf[mq->tail] = msg;
|
|
284
|
+
mq->tail = (mq->tail + 1) % mq->capacity;
|
|
285
|
+
mq->count++;
|
|
286
|
+
pthread_cond_signal(&mq->not_empty);
|
|
287
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
288
|
+
return 0;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* Blocking get. Waits until an item is available. Returns 0 on success, -1 on error. */
|
|
292
|
+
static inline int c_mq_get_await(message_queue* mq, evt_message_payload** out_msg, double timeout_seconds) {
|
|
293
|
+
if (!mq || !out_msg) return -1;
|
|
294
|
+
pthread_mutex_lock(&mq->mutex);
|
|
295
|
+
struct timespec ts;
|
|
296
|
+
if (timeout_seconds > 0) {
|
|
297
|
+
clock_gettime(CLOCK_REALTIME, &ts);
|
|
298
|
+
timespec_add_seconds(&ts, timeout_seconds);
|
|
299
|
+
}
|
|
300
|
+
while (mq->count == 0) {
|
|
301
|
+
if (timeout_seconds > 0) {
|
|
302
|
+
int rc = pthread_cond_timedwait(&mq->not_empty, &mq->mutex, &ts);
|
|
303
|
+
if (rc == ETIMEDOUT) {
|
|
304
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
305
|
+
return -1;
|
|
306
|
+
}
|
|
307
|
+
if (rc != 0 && rc != EINTR) {
|
|
308
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
309
|
+
return -1;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
pthread_cond_wait(&mq->not_empty, &mq->mutex);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
*out_msg = mq->buf[mq->head];
|
|
317
|
+
mq->buf[mq->head] = NULL;
|
|
318
|
+
mq->head = (mq->head + 1) % mq->capacity;
|
|
319
|
+
mq->count--;
|
|
320
|
+
pthread_cond_signal(&mq->not_full);
|
|
321
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
322
|
+
return 0;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* Busy-looping put (spin up to max_spin times until space). */
|
|
326
|
+
static inline int c_mq_put_busy(message_queue* mq, evt_message_payload* msg, size_t max_spin) {
|
|
327
|
+
if (!mq || !msg) return -1;
|
|
328
|
+
for (size_t i = 0; i < max_spin; ++i) {
|
|
329
|
+
pthread_mutex_lock(&mq->mutex);
|
|
330
|
+
if (mq->count < mq->capacity) {
|
|
331
|
+
mq->buf[mq->tail] = msg;
|
|
332
|
+
mq->tail = (mq->tail + 1) % mq->capacity;
|
|
333
|
+
mq->count++;
|
|
334
|
+
pthread_cond_signal(&mq->not_empty);
|
|
335
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
336
|
+
return 0;
|
|
337
|
+
}
|
|
338
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
339
|
+
sched_yield();
|
|
340
|
+
}
|
|
341
|
+
return -1;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/* Busy-looping get (spin up to max_spin times until item). */
|
|
345
|
+
static inline int c_mq_get_busy(message_queue* mq, evt_message_payload** out_msg, size_t max_spin) {
|
|
346
|
+
if (!mq || !out_msg) return -1;
|
|
347
|
+
for (size_t i = 0; i < max_spin; ++i) {
|
|
348
|
+
pthread_mutex_lock(&mq->mutex);
|
|
349
|
+
if (mq->count > 0) {
|
|
350
|
+
*out_msg = mq->buf[mq->head];
|
|
351
|
+
mq->buf[mq->head] = NULL;
|
|
352
|
+
mq->head = (mq->head + 1) % mq->capacity;
|
|
353
|
+
mq->count--;
|
|
354
|
+
pthread_cond_signal(&mq->not_full);
|
|
355
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
356
|
+
return 0;
|
|
357
|
+
}
|
|
358
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
359
|
+
sched_yield();
|
|
360
|
+
}
|
|
361
|
+
return -1;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/* Hybrid put: busy-spin for max_spin iterations then block */
|
|
365
|
+
static inline int c_mq_put_hybrid(message_queue* mq, evt_message_payload* msg, size_t max_spin, double timeout_seconds) {
|
|
366
|
+
if (!mq || !msg) return -1;
|
|
367
|
+
if (c_mq_put_busy(mq, msg, max_spin) == 0) {
|
|
368
|
+
return 0;
|
|
369
|
+
}
|
|
370
|
+
// After spinning, fallback to blocking with timeout (timeout does not include spin time)
|
|
371
|
+
return c_mq_put_await(mq, msg, timeout_seconds);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/* Hybrid get: busy-spin for max_spin iterations then block */
|
|
375
|
+
static inline int c_mq_get_hybrid(message_queue* mq, evt_message_payload** out_msg, size_t max_spin, double timeout_seconds) {
|
|
376
|
+
if (!mq || !out_msg) return -1;
|
|
377
|
+
if (c_mq_get_busy(mq, out_msg, max_spin) == 0) {
|
|
378
|
+
return 0;
|
|
379
|
+
}
|
|
380
|
+
// After spinning, fallback to blocking with timeout (timeout does not include spin time)
|
|
381
|
+
return c_mq_get_await(mq, out_msg, timeout_seconds);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/* Get current occupied count */
|
|
385
|
+
static inline size_t c_mq_occupied(message_queue* mq) {
|
|
386
|
+
if (!mq) return 0;
|
|
387
|
+
pthread_mutex_lock(&mq->mutex);
|
|
388
|
+
size_t n = mq->count;
|
|
389
|
+
pthread_mutex_unlock(&mq->mutex);
|
|
390
|
+
return n;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
#endif /* C_ENGINE_H */
|