xref: /PHP-7.0/sapi/fpm/fpm/fpm_scoreboard.c (revision a22175b0)
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