]>
Commit | Line | Data |
---|---|---|
54a0048b SL |
1 | void mq_nanosleep(unsigned ns); |
2 | ||
1a4d82fc JJ |
3 | /* |
4 | * Simple templated message queue implementation that relies on only mutexes for | |
5 | * synchronization (which reduces portability issues). Given the following | |
6 | * setup: | |
7 | * | |
8 | * typedef struct mq_msg_s mq_msg_t; | |
9 | * struct mq_msg_s { | |
10 | * mq_msg(mq_msg_t) link; | |
11 | * [message data] | |
12 | * }; | |
13 | * mq_gen(, mq_, mq_t, mq_msg_t, link) | |
14 | * | |
15 | * The API is as follows: | |
16 | * | |
17 | * bool mq_init(mq_t *mq); | |
18 | * void mq_fini(mq_t *mq); | |
19 | * unsigned mq_count(mq_t *mq); | |
20 | * mq_msg_t *mq_tryget(mq_t *mq); | |
21 | * mq_msg_t *mq_get(mq_t *mq); | |
22 | * void mq_put(mq_t *mq, mq_msg_t *msg); | |
23 | * | |
24 | * The message queue linkage embedded in each message is to be treated as | |
25 | * externally opaque (no need to initialize or clean up externally). mq_fini() | |
26 | * does not perform any cleanup of messages, since it knows nothing of their | |
27 | * payloads. | |
28 | */ | |
29 | #define mq_msg(a_mq_msg_type) ql_elm(a_mq_msg_type) | |
30 | ||
31 | #define mq_gen(a_attr, a_prefix, a_mq_type, a_mq_msg_type, a_field) \ | |
32 | typedef struct { \ | |
33 | mtx_t lock; \ | |
34 | ql_head(a_mq_msg_type) msgs; \ | |
35 | unsigned count; \ | |
36 | } a_mq_type; \ | |
37 | a_attr bool \ | |
38 | a_prefix##init(a_mq_type *mq) { \ | |
39 | \ | |
40 | if (mtx_init(&mq->lock)) \ | |
41 | return (true); \ | |
42 | ql_new(&mq->msgs); \ | |
43 | mq->count = 0; \ | |
44 | return (false); \ | |
45 | } \ | |
46 | a_attr void \ | |
47 | a_prefix##fini(a_mq_type *mq) \ | |
48 | { \ | |
49 | \ | |
50 | mtx_fini(&mq->lock); \ | |
51 | } \ | |
52 | a_attr unsigned \ | |
53 | a_prefix##count(a_mq_type *mq) \ | |
54 | { \ | |
55 | unsigned count; \ | |
56 | \ | |
57 | mtx_lock(&mq->lock); \ | |
58 | count = mq->count; \ | |
59 | mtx_unlock(&mq->lock); \ | |
60 | return (count); \ | |
61 | } \ | |
62 | a_attr a_mq_msg_type * \ | |
63 | a_prefix##tryget(a_mq_type *mq) \ | |
64 | { \ | |
65 | a_mq_msg_type *msg; \ | |
66 | \ | |
67 | mtx_lock(&mq->lock); \ | |
68 | msg = ql_first(&mq->msgs); \ | |
69 | if (msg != NULL) { \ | |
70 | ql_head_remove(&mq->msgs, a_mq_msg_type, a_field); \ | |
71 | mq->count--; \ | |
72 | } \ | |
73 | mtx_unlock(&mq->lock); \ | |
74 | return (msg); \ | |
75 | } \ | |
76 | a_attr a_mq_msg_type * \ | |
77 | a_prefix##get(a_mq_type *mq) \ | |
78 | { \ | |
79 | a_mq_msg_type *msg; \ | |
54a0048b | 80 | unsigned ns; \ |
1a4d82fc JJ |
81 | \ |
82 | msg = a_prefix##tryget(mq); \ | |
83 | if (msg != NULL) \ | |
84 | return (msg); \ | |
85 | \ | |
54a0048b | 86 | ns = 1; \ |
1a4d82fc | 87 | while (true) { \ |
54a0048b | 88 | mq_nanosleep(ns); \ |
1a4d82fc JJ |
89 | msg = a_prefix##tryget(mq); \ |
90 | if (msg != NULL) \ | |
91 | return (msg); \ | |
54a0048b | 92 | if (ns < 1000*1000*1000) { \ |
1a4d82fc | 93 | /* Double sleep time, up to max 1 second. */ \ |
54a0048b SL |
94 | ns <<= 1; \ |
95 | if (ns > 1000*1000*1000) \ | |
96 | ns = 1000*1000*1000; \ | |
1a4d82fc JJ |
97 | } \ |
98 | } \ | |
99 | } \ | |
100 | a_attr void \ | |
101 | a_prefix##put(a_mq_type *mq, a_mq_msg_type *msg) \ | |
102 | { \ | |
103 | \ | |
104 | mtx_lock(&mq->lock); \ | |
105 | ql_elm_new(msg, a_field); \ | |
106 | ql_tail_insert(&mq->msgs, msg, a_field); \ | |
107 | mq->count++; \ | |
108 | mtx_unlock(&mq->lock); \ | |
109 | } |