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