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 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 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 } else {
114 if (scoreboard->idle + idle > 0) {
115 scoreboard->idle += idle;
116 } else {
117 scoreboard->idle = 0;
118 }
119
120 if (scoreboard->active + active > 0) {
121 scoreboard->active += active;
122 } else {
123 scoreboard->active = 0;
124 }
125
126 if (scoreboard->requests + requests > 0) {
127 scoreboard->requests += requests;
128 } else {
129 scoreboard->requests = 0;
130 }
131
132 if (scoreboard->max_children_reached + max_children_reached > 0) {
133 scoreboard->max_children_reached += max_children_reached;
134 } else {
135 scoreboard->max_children_reached = 0;
136 }
137 }
138
139 if (scoreboard->active > scoreboard->active_max) {
140 scoreboard->active_max = scoreboard->active;
141 }
142
143 fpm_unlock(scoreboard->lock);
144 }
145 /* }}} */
146
fpm_scoreboard_get()147 struct fpm_scoreboard_s *fpm_scoreboard_get() /* {{{*/
148 {
149 return fpm_scoreboard;
150 }
151 /* }}} */
152
fpm_scoreboard_proc_get(struct fpm_scoreboard_s * scoreboard,int child_index)153 struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get(struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{*/
154 {
155 if (!scoreboard) {
156 scoreboard = fpm_scoreboard;
157 }
158
159 if (!scoreboard) {
160 return NULL;
161 }
162
163 if (child_index < 0) {
164 child_index = fpm_scoreboard_i;
165 }
166
167 if (child_index < 0 || child_index >= scoreboard->nprocs) {
168 return NULL;
169 }
170
171 return scoreboard->procs[child_index];
172 }
173 /* }}} */
174
fpm_scoreboard_acquire(struct fpm_scoreboard_s * scoreboard,int nohang)175 struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang) /* {{{ */
176 {
177 struct fpm_scoreboard_s *s;
178
179 s = scoreboard ? scoreboard : fpm_scoreboard;
180 if (!s) {
181 return NULL;
182 }
183
184 if (!fpm_spinlock(&s->lock, nohang)) {
185 return NULL;
186 }
187 return s;
188 }
189 /* }}} */
190
fpm_scoreboard_release(struct fpm_scoreboard_s * scoreboard)191 void fpm_scoreboard_release(struct fpm_scoreboard_s *scoreboard) {
192 if (!scoreboard) {
193 return;
194 }
195
196 scoreboard->lock = 0;
197 }
198
fpm_scoreboard_proc_acquire(struct fpm_scoreboard_s * scoreboard,int child_index,int nohang)199 struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_acquire(struct fpm_scoreboard_s *scoreboard, int child_index, int nohang) /* {{{ */
200 {
201 struct fpm_scoreboard_proc_s *proc;
202
203 proc = fpm_scoreboard_proc_get(scoreboard, child_index);
204 if (!proc) {
205 return NULL;
206 }
207
208 if (!fpm_spinlock(&proc->lock, nohang)) {
209 return NULL;
210 }
211
212 return proc;
213 }
214 /* }}} */
215
fpm_scoreboard_proc_release(struct fpm_scoreboard_proc_s * proc)216 void fpm_scoreboard_proc_release(struct fpm_scoreboard_proc_s *proc) /* {{{ */
217 {
218 if (!proc) {
219 return;
220 }
221
222 proc->lock = 0;
223 }
224
fpm_scoreboard_free(struct fpm_scoreboard_s * scoreboard)225 void fpm_scoreboard_free(struct fpm_scoreboard_s *scoreboard) /* {{{ */
226 {
227 int i;
228
229 if (!scoreboard) {
230 zlog(ZLOG_ERROR, "**scoreboard is NULL");
231 return;
232 }
233
234 for (i = 0; i < scoreboard->nprocs; i++) {
235 if (!scoreboard->procs[i]) {
236 continue;
237 }
238 fpm_shm_free(scoreboard->procs[i], sizeof(struct fpm_scoreboard_proc_s));
239 }
240 fpm_shm_free(scoreboard, sizeof(struct fpm_scoreboard_s));
241 }
242 /* }}} */
243
fpm_scoreboard_child_use(struct fpm_scoreboard_s * scoreboard,int child_index,pid_t pid)244 void fpm_scoreboard_child_use(struct fpm_scoreboard_s *scoreboard, int child_index, pid_t pid) /* {{{ */
245 {
246 struct fpm_scoreboard_proc_s *proc;
247 fpm_scoreboard = scoreboard;
248 fpm_scoreboard_i = child_index;
249 proc = fpm_scoreboard_proc_get(scoreboard, child_index);
250 if (!proc) {
251 return;
252 }
253 proc->pid = pid;
254 proc->start_epoch = time(NULL);
255 }
256 /* }}} */
257
fpm_scoreboard_proc_free(struct fpm_scoreboard_s * scoreboard,int child_index)258 void fpm_scoreboard_proc_free(struct fpm_scoreboard_s *scoreboard, int child_index) /* {{{ */
259 {
260 if (!scoreboard) {
261 return;
262 }
263
264 if (child_index < 0 || child_index >= scoreboard->nprocs) {
265 return;
266 }
267
268 if (scoreboard->procs[child_index] && scoreboard->procs[child_index]->used > 0) {
269 memset(scoreboard->procs[child_index], 0, sizeof(struct fpm_scoreboard_proc_s));
270 }
271
272 /* set this slot as free to avoid search on next alloc */
273 scoreboard->free_proc = child_index;
274 }
275 /* }}} */
276
fpm_scoreboard_proc_alloc(struct fpm_scoreboard_s * scoreboard,int * child_index)277 int fpm_scoreboard_proc_alloc(struct fpm_scoreboard_s *scoreboard, int *child_index) /* {{{ */
278 {
279 int i = -1;
280
281 if (!scoreboard || !child_index) {
282 return -1;
283 }
284
285 /* first try the slot which is supposed to be free */
286 if (scoreboard->free_proc >= 0 && scoreboard->free_proc < scoreboard->nprocs) {
287 if (scoreboard->procs[scoreboard->free_proc] && !scoreboard->procs[scoreboard->free_proc]->used) {
288 i = scoreboard->free_proc;
289 }
290 }
291
292 if (i < 0) { /* the supposed free slot is not, let's search for a free slot */
293 zlog(ZLOG_DEBUG, "[pool %s] the proc->free_slot was not free. Let's search", scoreboard->pool);
294 for (i = 0; i < scoreboard->nprocs; i++) {
295 if (scoreboard->procs[i] && !scoreboard->procs[i]->used) { /* found */
296 break;
297 }
298 }
299 }
300
301 /* no free slot */
302 if (i < 0 || i >= scoreboard->nprocs) {
303 zlog(ZLOG_ERROR, "[pool %s] no free scoreboard slot", scoreboard->pool);
304 return -1;
305 }
306
307 scoreboard->procs[i]->used = 1;
308 *child_index = i;
309
310 /* supposed next slot is free */
311 if (i + 1 >= scoreboard->nprocs) {
312 scoreboard->free_proc = 0;
313 } else {
314 scoreboard->free_proc = i + 1;
315 }
316
317 return 0;
318 }
319 /* }}} */
320
321 #ifdef HAVE_TIMES
fpm_scoreboard_get_tick()322 float fpm_scoreboard_get_tick() /* {{{ */
323 {
324 return fpm_scoreboard_tick;
325 }
326 /* }}} */
327 #endif
328
329