upstream nginx-0.7.35
[nginx.git] / nginx / src / event / ngx_event_busy_lock.c
1
2 /*
3  * Copyright (C) Igor Sysoev
4  */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_event.h>
10
11
12 static ngx_int_t ngx_event_busy_lock_look_cacheable(ngx_event_busy_lock_t *bl,
13     ngx_event_busy_lock_ctx_t *ctx);
14 static void ngx_event_busy_lock_handler(ngx_event_t *ev);
15 static void ngx_event_busy_lock_posted_handler(ngx_event_t *ev);
16
17
18 /*
19  * NGX_OK:     the busy lock is held
20  * NGX_AGAIN:  the all busy locks are held but we will wait the specified time
21  * NGX_BUSY:   ctx->timer == 0: there are many the busy locks
22  *             ctx->timer != 0: there are many the waiting locks
23  */
24
25 ngx_int_t
26 ngx_event_busy_lock(ngx_event_busy_lock_t *bl, ngx_event_busy_lock_ctx_t *ctx)
27 {
28     ngx_int_t  rc;
29
30     ngx_mutex_lock(bl->mutex);
31
32     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->event->log, 0,
33                    "event busy lock: b:%d mb:%d",
34                    bl->busy, bl->max_busy);
35
36     if (bl->busy < bl->max_busy) {
37         bl->busy++;
38
39         rc = NGX_OK;
40
41     } else if (ctx->timer && bl->waiting < bl->max_waiting) {
42         bl->waiting++;
43         ngx_add_timer(ctx->event, ctx->timer);
44         ctx->event->handler = ngx_event_busy_lock_handler;
45
46         if (bl->events) {
47             bl->last->next = ctx;
48
49         } else {
50             bl->events = ctx;
51         }
52
53         bl->last = ctx;
54
55         rc = NGX_AGAIN;
56
57     } else {
58         rc = NGX_BUSY;
59     }
60
61     ngx_mutex_unlock(bl->mutex);
62
63     return rc;
64 }
65
66
67 ngx_int_t
68 ngx_event_busy_lock_cacheable(ngx_event_busy_lock_t *bl,
69     ngx_event_busy_lock_ctx_t *ctx)
70 {
71     ngx_int_t  rc;
72
73     ngx_mutex_lock(bl->mutex);
74
75     rc = ngx_event_busy_lock_look_cacheable(bl, ctx);
76
77     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ctx->event->log, 0,
78                    "event busy lock: %d w:%d mw:%d",
79                    rc, bl->waiting, bl->max_waiting);
80
81     /*
82      * NGX_OK:     no the same request, there is free slot and we locked it
83      * NGX_BUSY:   no the same request and there is no free slot
84      * NGX_AGAIN:  the same request is processing
85      */
86
87     if (rc == NGX_AGAIN) {
88
89         if (ctx->timer && bl->waiting < bl->max_waiting) {
90             bl->waiting++;
91             ngx_add_timer(ctx->event, ctx->timer);
92             ctx->event->handler = ngx_event_busy_lock_handler;
93
94             if (bl->events == NULL) {
95                 bl->events = ctx;
96             } else {
97                 bl->last->next = ctx;
98             }
99             bl->last = ctx;
100
101         } else {
102             rc = NGX_BUSY;
103         }
104     }
105
106     ngx_mutex_unlock(bl->mutex);
107
108     return rc;
109 }
110
111
112 void
113 ngx_event_busy_unlock(ngx_event_busy_lock_t *bl,
114     ngx_event_busy_lock_ctx_t *ctx)
115 {
116     ngx_event_t                *ev;
117     ngx_event_busy_lock_ctx_t  *wakeup;
118
119     ngx_mutex_lock(bl->mutex);
120
121     if (bl->events) {
122         wakeup = bl->events;
123         bl->events = bl->events->next;
124
125     } else {
126         wakeup = NULL;
127         bl->busy--;
128     }
129
130     /*
131      * MP: all ctx's and their queue must be in shared memory,
132      *     each ctx has pid to wake up
133      */
134
135     if (wakeup == NULL) {
136         ngx_mutex_unlock(bl->mutex);
137         return;
138     }
139
140     if (ctx->md5) {
141         for (wakeup = bl->events; wakeup; wakeup = wakeup->next) {
142             if (wakeup->md5 == NULL || wakeup->slot != ctx->slot) {
143                 continue;
144             }
145
146             wakeup->handler = ngx_event_busy_lock_posted_handler;
147             wakeup->cache_updated = 1;
148
149             ev = wakeup->event;
150
151             ngx_post_event(ev, &ngx_posted_events);
152         }
153
154         ngx_mutex_unlock(bl->mutex);
155
156     } else {
157         bl->waiting--;
158
159         ngx_mutex_unlock(bl->mutex);
160
161         wakeup->handler = ngx_event_busy_lock_posted_handler;
162         wakeup->locked = 1;
163
164         ev = wakeup->event;
165
166         if (ev->timer_set) {
167             ngx_del_timer(ev);
168         }
169
170         ngx_post_event(ev, &ngx_posted_events);
171     }
172 }
173
174
175 void
176 ngx_event_busy_lock_cancel(ngx_event_busy_lock_t *bl,
177     ngx_event_busy_lock_ctx_t *ctx)
178 {
179     ngx_event_busy_lock_ctx_t  *c, *p;
180
181     ngx_mutex_lock(bl->mutex);
182
183     bl->waiting--;
184
185     if (ctx == bl->events) {
186         bl->events = ctx->next;
187
188     } else {
189         p = bl->events;
190         for (c = bl->events->next; c; c = c->next) {
191             if (c == ctx) {
192                 p->next = ctx->next;
193                 break;
194             }
195             p = c;
196         }
197     }
198
199     ngx_mutex_unlock(bl->mutex);
200 }
201
202
203 static ngx_int_t
204 ngx_event_busy_lock_look_cacheable(ngx_event_busy_lock_t *bl,
205     ngx_event_busy_lock_ctx_t *ctx)
206 {
207     ngx_int_t    free;
208     ngx_uint_t   i, bit, cacheable, mask;
209
210     bit = 0;
211     cacheable = 0;
212     free = -1;
213
214 #if (NGX_SUPPRESS_WARN)
215     mask = 0;
216 #endif
217
218     for (i = 0; i < bl->max_busy; i++) {
219
220         if ((bit & 7) == 0) {
221             mask = bl->md5_mask[i / 8];
222         }
223
224         if (mask & 1) {
225             if (ngx_memcmp(&bl->md5[i * 16], ctx->md5, 16) == 0) {
226                 ctx->waiting = 1;
227                 ctx->slot = i;
228                 return NGX_AGAIN;
229             }
230             cacheable++;
231
232         } else if (free == -1) {
233             free = i;
234         }
235
236         if (cacheable == bl->cacheable) {
237             if (free == -1 && cacheable < bl->max_busy) {
238                 free = i + 1;
239             }
240
241             break;
242         }
243
244         mask >>= 1;
245         bit++;
246     }
247
248     if (free == -1) {
249         return NGX_BUSY;
250     }
251
252 #if 0
253     if (bl->busy == bl->max_busy) {
254         return NGX_BUSY;
255     }
256 #endif
257
258     ngx_memcpy(&bl->md5[free * 16], ctx->md5, 16);
259     bl->md5_mask[free / 8] |= 1 << (free & 7);
260     ctx->slot = free;
261
262     bl->cacheable++;
263     bl->busy++;
264
265     return NGX_OK;
266 }
267
268
269 static void
270 ngx_event_busy_lock_handler(ngx_event_t *ev)
271 {
272     ev->handler = ngx_event_busy_lock_posted_handler;
273
274     ngx_post_event(ev, &ngx_posted_events);
275 }
276
277
278 static void
279 ngx_event_busy_lock_posted_handler(ngx_event_t *ev)
280 {
281     ngx_event_busy_lock_ctx_t  *ctx;
282
283     ctx = ev->data;
284     ctx->handler(ev);
285 }