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