1
2 /* $Id: fpm_status.c 312399 2011-06-23 08:03:52Z fat $ */
3 /* (c) 2009 Jerome Loyet */
4
5 #include "php.h"
6 #include "SAPI.h"
7 #include <stdio.h>
8 #include <time.h>
9
10 #include "fpm_config.h"
11 #include "fpm_scoreboard.h"
12 #include "fpm_shm.h"
13 #include "fpm_sockets.h"
14 #include "fpm_worker_pool.h"
15 #include "fpm_clock.h"
16 #include "zlog.h"
17
18 static struct fpm_scoreboard_s *fpm_scoreboard = NULL;
19 static int fpm_scoreboard_i = -1;
20 #ifdef HAVE_TIMES
21 static float fpm_scoreboard_tick;
22 #endif
23
24
fpm_scoreboard_init_main()25 int fpm_scoreboard_init_main() /* {{{ */
26 {
27 struct fpm_worker_pool_s *wp;
28 unsigned int i;
29
30 #ifdef HAVE_TIMES
31 #if (defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK))
32 fpm_scoreboard_tick = sysconf(_SC_CLK_TCK);
33 #else /* _SC_CLK_TCK */
34 #ifdef HZ
35 fpm_scoreboard_tick = HZ;
36 #else /* HZ */
37 fpm_scoreboard_tick = 100;
38 #endif /* HZ */
39 #endif /* _SC_CLK_TCK */
40 zlog(ZLOG_DEBUG, "got clock tick '%.0f'", fpm_scoreboard_tick);
41 #endif /* HAVE_TIMES */
42
43
44 for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
45 size_t scoreboard_size, scoreboard_nprocs_size;
46 void *shm_mem;
47
48 if (wp->config->pm_max_children < 1) {
49 zlog(ZLOG_ERROR, "[pool %s] Unable to create scoreboard SHM because max_client is not set", wp->config->name);
50 return -1;
51 }
52
53 if (wp->scoreboard) {
54 zlog(ZLOG_ERROR, "[pool %s] Unable to create scoreboard SHM because it already exists", wp->config->name);
55 return -1;
56 }
57
58 scoreboard_size = sizeof(struct fpm_scoreboard_s) + (wp->config->pm_max_children) * sizeof(struct fpm_scoreboard_proc_s *);
59 scoreboard_nprocs_size = sizeof(struct fpm_scoreboard_proc_s) * wp->config->pm_max_children;
60 shm_mem = fpm_shm_alloc(scoreboard_size + scoreboard_nprocs_size);
61
62 if (!shm_mem) {
63 return -1;
64 }
65 wp->scoreboard = shm_mem;
66 wp->scoreboard->nprocs = wp->config->pm_max_children;
67 shm_mem += scoreboard_size;
68
69 for (i = 0; i < wp->scoreboard->nprocs; i++, shm_mem += sizeof(struct fpm_scoreboard_proc_s)) {
70 wp->scoreboard->procs[i] = shm_mem;
71 }
72
73 wp->scoreboard->pm = wp->config->pm;
74 wp->scoreboard->start_epoch = time(NULL);
75 strlcpy(wp->scoreboard->pool, wp->config->name, sizeof(wp->scoreboard->pool));
76 }
77 return 0;
78 }
79 /* }}} */
80
fpm_scoreboard_update(int idle,int active,int lq,int lq_len,int requests,int max_children_reached,int slow_rq,int action,struct fpm_scoreboard_s * scoreboard)81 void fpm_scoreboard_update(int idle, int active, int lq, int lq_len, int requests, int max_children_reached, int slow_rq, int action, struct fpm_scoreboard_s *scoreboard) /* {{{ */
82 {
83 if (!scoreboard) {
84 scoreboard = fpm_scoreboard;
85 }
86 if (!scoreboard) {
87 zlog(ZLOG_WARNING, "Unable to update scoreboard: the SHM has not been found");
88 return;
89 }
90
91
92 fpm_spinlock(&scoreboard->lock, 0);
93 if (action == FPM_SCOREBOARD_ACTION_SET) {
94 if (idle >= 0) {
95 scoreboard->idle = idle;
96 }
97 if (active >= 0) {
98 scoreboard->active = active;
99 }
100 if (lq >= 0) {
101 scoreboard->lq = lq;
102 }
103 if (lq_len >= 0) {
104 scoreboard->lq_len = lq_len;
105 }
106 #ifdef HAVE_FPM_LQ /* prevent unnecessary test */
107 if (scoreboard->lq > scoreboard->lq_max) {
108 scoreboard->lq_max = scoreboard->lq;
109 }
110 #endif
111 if (requests >= 0) {
112 scoreboard->requests = requests;
113 }
114
115 if (max_children_reached >= 0) {
116 scoreboard->max_children_reached = max_children_reached;
117 }
118 if (slow_rq > 0) {
119 scoreboard->slow_rq = slow_rq;
120 }
121 } else {
122 if (scoreboard->idle + idle > 0) {
123 scoreboard->idle += idle;
124 } else {
125 scoreboard->idle = 0;
126 }
127
128 if (scoreboard->active + active > 0) {
129 scoreboard->active += active;
130 } else {
131 scoreboard->active = 0;
132 }
133
134 if (scoreboard->requests + requests > 0) {
135 scoreboard->requests += requests;
136 } else {
137 scoreboard->requests = 0;
138 }
139
140 if (scoreboard->max_children_reached + max_children_reached > 0) {
141 scoreboard->max_children_reached += max_children_reached;
142 } else {
143 scoreboard->max_children_reached = 0;
144 }
145
146 if (scoreboard->slow_rq + slow_rq > 0) {
147 scoreboard->slow_rq += slow_rq;
148 } else {
149 scoreboard->slow_rq = 0;
150 }
151 }
152
153 if (scoreboard->active > scoreboard->active_max) {
154 scoreboard->active_max = scoreboard->active;
155 }
156
157 fpm_unlock(scoreboard->lock);
158 }
159 /* }}} */
160
fpm_scoreboard_get()161 struct fpm_scoreboard_s *fpm_scoreboard_get() /* {{{*/
162 {
163 return fpm_scoreboard;
164 }
165 /* }}} */
166
fpm_scoreboard_proc_get(struct fpm_scoreboard_s * scoreboard,int child_index)167 struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get(struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{*/
168 {
169 if (!scoreboard) {
170 scoreboard = fpm_scoreboard;
171 }
172
173 if (!scoreboard) {
174 return NULL;
175 }
176
177 if (child_index < 0) {
178 child_index = fpm_scoreboard_i;
179 }
180
181 if (child_index < 0 || child_index >= scoreboard->nprocs) {
182 return NULL;
183 }
184
185 return scoreboard->procs[child_index];
186 }
187 /* }}} */
188
fpm_scoreboard_acquire(struct fpm_scoreboard_s * scoreboard,int nohang)189 struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang) /* {{{ */
190 {
191 struct fpm_scoreboard_s *s;
192
193 s = scoreboard ? scoreboard : fpm_scoreboard;
194 if (!s) {
195 return NULL;
196 }
197
198 if (!fpm_spinlock(&s->lock, nohang)) {
199 return NULL;
200 }
201 return s;
202 }
203 /* }}} */
204
fpm_scoreboard_release(struct fpm_scoreboard_s * scoreboard)205 void fpm_scoreboard_release(struct fpm_scoreboard_s *scoreboard) {
206 if (!scoreboard) {
207 return;
208 }
209
210 scoreboard->lock = 0;
211 }
212
fpm_scoreboard_proc_acquire(struct fpm_scoreboard_s * scoreboard,int child_index,int nohang)213 struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_acquire(struct fpm_scoreboard_s *scoreboard, int child_index, int nohang) /* {{{ */
214 {
215 struct fpm_scoreboard_proc_s *proc;
216
217 proc = fpm_scoreboard_proc_get(scoreboard, child_index);
218 if (!proc) {
219 return NULL;
220 }
221
222 if (!fpm_spinlock(&proc->lock, nohang)) {
223 return NULL;
224 }
225
226 return proc;
227 }
228 /* }}} */
229
fpm_scoreboard_proc_release(struct fpm_scoreboard_proc_s * proc)230 void fpm_scoreboard_proc_release(struct fpm_scoreboard_proc_s *proc) /* {{{ */
231 {
232 if (!proc) {
233 return;
234 }
235
236 proc->lock = 0;
237 }
238
fpm_scoreboard_free(struct fpm_scoreboard_s * scoreboard)239 void fpm_scoreboard_free(struct fpm_scoreboard_s *scoreboard) /* {{{ */
240 {
241 size_t scoreboard_size, scoreboard_nprocs_size;
242
243 if (!scoreboard) {
244 zlog(ZLOG_ERROR, "**scoreboard is NULL");
245 return;
246 }
247
248 scoreboard_size = sizeof(struct fpm_scoreboard_s) + (scoreboard->nprocs) * sizeof(struct fpm_scoreboard_proc_s *);
249 scoreboard_nprocs_size = sizeof(struct fpm_scoreboard_proc_s) * scoreboard->nprocs;
250
251 fpm_shm_free(scoreboard, scoreboard_size + scoreboard_nprocs_size);
252 }
253 /* }}} */
254
fpm_scoreboard_child_use(struct fpm_scoreboard_s * scoreboard,int child_index,pid_t pid)255 void fpm_scoreboard_child_use(struct fpm_scoreboard_s *scoreboard, int child_index, pid_t pid) /* {{{ */
256 {
257 struct fpm_scoreboard_proc_s *proc;
258 fpm_scoreboard = scoreboard;
259 fpm_scoreboard_i = child_index;
260 proc = fpm_scoreboard_proc_get(scoreboard, child_index);
261 if (!proc) {
262 return;
263 }
264 proc->pid = pid;
265 proc->start_epoch = time(NULL);
266 }
267 /* }}} */
268
fpm_scoreboard_proc_free(struct fpm_scoreboard_s * scoreboard,int child_index)269 void fpm_scoreboard_proc_free(struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{ */
270 {
271 if (!scoreboard) {
272 return;
273 }
274
275 if (child_index < 0 || child_index >= scoreboard->nprocs) {
276 return;
277 }
278
279 if (scoreboard->procs[child_index] && scoreboard->procs[child_index]->used > 0) {
280 memset(scoreboard->procs[child_index], 0, sizeof(struct fpm_scoreboard_proc_s));
281 }
282
283 /* set this slot as free to avoid search on next alloc */
284 scoreboard->free_proc = child_index;
285 }
286 /* }}} */
287
fpm_scoreboard_proc_alloc(struct fpm_scoreboard_s * scoreboard,int * child_index)288 int fpm_scoreboard_proc_alloc(struct fpm_scoreboard_s *scoreboard, int *child_index) /* {{{ */
289 {
290 int i = -1;
291
292 if (!scoreboard || !child_index) {
293 return -1;
294 }
295
296 /* first try the slot which is supposed to be free */
297 if (scoreboard->free_proc >= 0 && scoreboard->free_proc < scoreboard->nprocs) {
298 if (scoreboard->procs[scoreboard->free_proc] && !scoreboard->procs[scoreboard->free_proc]->used) {
299 i = scoreboard->free_proc;
300 }
301 }
302
303 if (i < 0) { /* the supposed free slot is not, let's search for a free slot */
304 zlog(ZLOG_DEBUG, "[pool %s] the proc->free_slot was not free. Let's search", scoreboard->pool);
305 for (i = 0; i < scoreboard->nprocs; i++) {
306 if (scoreboard->procs[i] && !scoreboard->procs[i]->used) { /* found */
307 break;
308 }
309 }
310 }
311
312 /* no free slot */
313 if (i < 0 || i >= scoreboard->nprocs) {
314 zlog(ZLOG_ERROR, "[pool %s] no free scoreboard slot", scoreboard->pool);
315 return -1;
316 }
317
318 scoreboard->procs[i]->used = 1;
319 *child_index = i;
320
321 /* supposed next slot is free */
322 if (i + 1 >= scoreboard->nprocs) {
323 scoreboard->free_proc = 0;
324 } else {
325 scoreboard->free_proc = i + 1;
326 }
327
328 return 0;
329 }
330 /* }}} */
331
332 #ifdef HAVE_TIMES
fpm_scoreboard_get_tick()333 float fpm_scoreboard_get_tick() /* {{{ */
334 {
335 return fpm_scoreboard_tick;
336 }
337 /* }}} */
338 #endif
339
340