正在显示
1 个修改的文件
包含
232 行增加
和
0 行删除
src/server/spserver/event_msgqueue.c
0 → 100644
1 | +/* | |
2 | + * event_msgqueue.c | |
3 | + * | |
4 | + * Libevent threaded message passing primitives | |
5 | + * | |
6 | + * Andrew Danforth <acd@weirdness.net>, October 2006 | |
7 | + * | |
8 | + * Copyright (c) Andrew Danforth, 2006 | |
9 | + * | |
10 | + */ | |
11 | + | |
12 | +#include <stdlib.h> | |
13 | +#include <string.h> | |
14 | +#include <sys/types.h> | |
15 | + | |
16 | +#include "spthread.hpp" | |
17 | + | |
18 | +#include "spporting.hpp" | |
19 | +#include "event_msgqueue.h" | |
20 | + | |
21 | +struct circqueue { | |
22 | + unsigned int head; | |
23 | + unsigned int tail; | |
24 | + unsigned int count; | |
25 | + unsigned int max_entries; | |
26 | + unsigned int array_elements; | |
27 | + void **entries; | |
28 | +}; | |
29 | + | |
30 | +#define DEFAULT_UNBOUNDED_QUEUE_SIZE 1024 | |
31 | + | |
32 | +struct event_msgqueue { | |
33 | + int push_fd; | |
34 | + int pop_fd; | |
35 | + int unlock_between_callbacks; | |
36 | + | |
37 | + struct event queue_ev; | |
38 | + | |
39 | + sp_thread_mutex_t lock; | |
40 | + void (*callback)(void *, void *); | |
41 | + void *cbarg; | |
42 | + struct circqueue *queue; | |
43 | +}; | |
44 | + | |
45 | +static unsigned int nextpow2(unsigned int num) { | |
46 | + --num; | |
47 | + num |= num >> 1; | |
48 | + num |= num >> 2; | |
49 | + num |= num >> 4; | |
50 | + num |= num >> 8; | |
51 | + num |= num >> 16; | |
52 | + return ++num; | |
53 | +} | |
54 | + | |
55 | +#define circqueue_get_length(q) ((q)->count) | |
56 | +#define circqueue_is_empty(q) (!circqueue_get_length(q)) | |
57 | +#define circqueue_is_full(q) ((q)->count == (q)->array_elements) | |
58 | + | |
59 | +static struct circqueue *circqueue_new(unsigned int size) { | |
60 | + struct circqueue *cq; | |
61 | + | |
62 | + if (!(cq = calloc(1, sizeof(struct circqueue)))) | |
63 | + return(NULL); | |
64 | + | |
65 | + cq->max_entries = size; | |
66 | + if (!size || !(cq->array_elements = nextpow2(size))) | |
67 | + cq->array_elements = DEFAULT_UNBOUNDED_QUEUE_SIZE; | |
68 | + cq->entries = malloc(sizeof(void *) * cq->array_elements); | |
69 | + if (!cq->entries) { | |
70 | + free(cq); | |
71 | + return(NULL); | |
72 | + } | |
73 | + | |
74 | + return(cq); | |
75 | +} | |
76 | + | |
77 | +static void circqueue_destroy(struct circqueue *cq) { | |
78 | + free(cq->entries); | |
79 | + free(cq); | |
80 | +} | |
81 | + | |
82 | +static int circqueue_grow(struct circqueue *cq) { | |
83 | + void **newents; | |
84 | + unsigned int newsize = cq->array_elements << 1; | |
85 | + unsigned int headchunklen = 0, tailchunklen = 0; | |
86 | + | |
87 | + if (!(newents = malloc(sizeof(void *) * newsize))) | |
88 | + return(-1); | |
89 | + | |
90 | + if (cq->head < cq->tail) | |
91 | + headchunklen = cq->tail - cq->head; | |
92 | + else { | |
93 | + headchunklen = cq->array_elements - cq->head; | |
94 | + tailchunklen = cq->tail; | |
95 | + } | |
96 | + | |
97 | + memcpy(newents, &cq->entries[cq->head], sizeof(void *) * headchunklen); | |
98 | + if (tailchunklen) | |
99 | + memcpy(&newents[headchunklen], cq->entries, sizeof(void *) * tailchunklen); | |
100 | + | |
101 | + cq->head = 0; | |
102 | + cq->tail = headchunklen + tailchunklen; | |
103 | + cq->array_elements = newsize; | |
104 | + | |
105 | + free(cq->entries); | |
106 | + cq->entries = newents; | |
107 | + | |
108 | + return(0); | |
109 | +} | |
110 | + | |
111 | +static int circqueue_push_tail(struct circqueue *cq, void *elem) { | |
112 | + if (cq->max_entries) { | |
113 | + if (cq->count == cq->max_entries) | |
114 | + return(-1); | |
115 | + } else if (circqueue_is_full(cq) && circqueue_grow(cq) != 0) | |
116 | + return(-1); | |
117 | + | |
118 | + cq->count++; | |
119 | + cq->entries[cq->tail++] = elem; | |
120 | + cq->tail &= cq->array_elements - 1; | |
121 | + | |
122 | + return(0); | |
123 | +} | |
124 | + | |
125 | +static void *circqueue_pop_head(struct circqueue *cq) { | |
126 | + void *data; | |
127 | + | |
128 | + if (!cq->count) | |
129 | + return(NULL); | |
130 | + | |
131 | + cq->count--; | |
132 | + data = cq->entries[cq->head++]; | |
133 | + cq->head &= cq->array_elements - 1; | |
134 | + | |
135 | + return(data); | |
136 | +} | |
137 | + | |
138 | +static void msgqueue_pop(int fd, short flags, void *arg) { | |
139 | + struct event_msgqueue *msgq = arg; | |
140 | + char buf[64]; | |
141 | + | |
142 | + recv(fd, buf, sizeof(buf),0); | |
143 | + | |
144 | + sp_thread_mutex_lock(&msgq->lock); | |
145 | + while(!circqueue_is_empty(msgq->queue)) { | |
146 | + void *qdata; | |
147 | + | |
148 | + qdata = circqueue_pop_head(msgq->queue); | |
149 | + | |
150 | + if (msgq->unlock_between_callbacks) | |
151 | + sp_thread_mutex_unlock(&msgq->lock); | |
152 | + | |
153 | + msgq->callback(qdata, msgq->cbarg); | |
154 | + | |
155 | + if (msgq->unlock_between_callbacks) | |
156 | + sp_thread_mutex_lock(&msgq->lock); | |
157 | + } | |
158 | + sp_thread_mutex_unlock(&msgq->lock); | |
159 | +} | |
160 | + | |
161 | +struct event_msgqueue *msgqueue_new(struct event_base *base, unsigned int max_size, void (*callback)(void *, void *), void *cbarg) { | |
162 | + struct event_msgqueue *msgq; | |
163 | + struct circqueue *cq; | |
164 | + int fds[2]; | |
165 | + | |
166 | + if (!(cq = circqueue_new(max_size))) | |
167 | + return(NULL); | |
168 | + | |
169 | + if (sp_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) { | |
170 | + circqueue_destroy(cq); | |
171 | + return(NULL); | |
172 | + } | |
173 | + | |
174 | + if (!(msgq = malloc(sizeof(struct event_msgqueue)))) { | |
175 | + circqueue_destroy(cq); | |
176 | + sp_close(fds[0]); | |
177 | + sp_close(fds[1]); | |
178 | + return(NULL); | |
179 | + } | |
180 | + | |
181 | + msgq->push_fd = fds[0]; | |
182 | + msgq->pop_fd = fds[1]; | |
183 | + msgq->queue = cq; | |
184 | + msgq->callback = callback; | |
185 | + msgq->cbarg = cbarg; | |
186 | + sp_thread_mutex_init(&msgq->lock, NULL); | |
187 | + event_set(&msgq->queue_ev, msgq->pop_fd, EV_READ | EV_PERSIST, msgqueue_pop, msgq); | |
188 | + event_base_set(base, &msgq->queue_ev); | |
189 | + event_add(&msgq->queue_ev, NULL); | |
190 | + | |
191 | + msgq->unlock_between_callbacks = 1; | |
192 | + | |
193 | + return(msgq); | |
194 | +} | |
195 | + | |
196 | +void msgqueue_destroy(struct event_msgqueue *msgq) | |
197 | +{ | |
198 | + for( ; msgqueue_length(msgq) > 0; ) { | |
199 | + sleep( 1 ); | |
200 | + } | |
201 | + | |
202 | + event_del(&msgq->queue_ev); | |
203 | + circqueue_destroy(msgq->queue); | |
204 | + sp_close(msgq->push_fd); | |
205 | + sp_close(msgq->pop_fd); | |
206 | + free(msgq); | |
207 | +} | |
208 | + | |
209 | +int msgqueue_push(struct event_msgqueue *msgq, void *msg) { | |
210 | + const char buf[1] = { 0 }; | |
211 | + int r = 0; | |
212 | + | |
213 | + sp_thread_mutex_lock(&msgq->lock); | |
214 | + if ((r = circqueue_push_tail(msgq->queue, msg)) == 0) { | |
215 | + if (circqueue_get_length(msgq->queue) == 1) | |
216 | + send(msgq->push_fd, buf, 1,0); | |
217 | + } | |
218 | + sp_thread_mutex_unlock(&msgq->lock); | |
219 | + | |
220 | + return(r); | |
221 | +} | |
222 | + | |
223 | +unsigned int msgqueue_length(struct event_msgqueue *msgq) { | |
224 | + unsigned int len; | |
225 | + | |
226 | + sp_thread_mutex_lock(&msgq->lock); | |
227 | + len = circqueue_get_length(msgq->queue); | |
228 | + sp_thread_mutex_unlock(&msgq->lock); | |
229 | + | |
230 | + return(len); | |
231 | +} | |
232 | + | ... | ... |
请
注册
或
登录
后发表评论