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