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