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