Import version 1.8.3
[s390-tools.git] / cpuplugd / main.c
blobc280342a40712a29ffd61eeaa770098df9cff1ea
1 /*
2 * Copyright IBM Corp 2007
3 * Author: Hans-Joachim Picht <hans@linux.vnet.ibm.com>
5 * Linux for System z Hotplug Daemon
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 #include <ctype.h>
18 #include <getopt.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <fcntl.h>
25 #include <sys/stat.h>
26 #include <sys/wait.h>
27 #include <sys/types.h>
28 #include <signal.h>
29 #include <syslog.h>
30 #include <pthread.h>
31 #include <setjmp.h>
32 #include "cpuplugd.h"
34 pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
35 static jmp_buf buf;
36 struct sigaction action_signal;
37 sigset_t set;
38 /* save the initial values for the cleanup procedure */
39 int num_cpu_start;
40 int cmm_pagesize_start;
41 int memory;
42 int cpu;
43 struct config cfg;
44 int sem;
47 * this functions handles the sigfpe signal which we
48 * might catch during rule evaluating
50 void handler(int sig)
52 signal(SIGFPE, handler);
53 longjmp(buf, 1);
56 void eval_cpu_rules(struct config *cfg)
58 struct symbols symbols;
59 int cpu, nr_cpus;
60 int onumcpus, runable_proc;
61 long long idle_ticks;
63 onumcpus = get_num_online_cpus();
64 runable_proc = get_runable_proc();
65 idle_ticks = get_idle_ticks();
66 symbols.loadavg = (double) get_loadavg();
67 symbols.onumcpus = (double) onumcpus;
68 symbols.runable_proc = (double) runable_proc;
69 symbols.idle = (double) (idle_ticks - cfg->idle_ticks) / cfg->update;
70 cfg->idle_ticks = idle_ticks;
71 nr_cpus = get_numcpus();
73 /* only use this for development and testing */
74 if (debug && foreground == 1) {
75 printf("---------------------------------------------\n");
76 printf("update_interval: %d s\n", cfg->update);
77 printf("cpu_min: %d\n", cfg->cpu_min);
78 printf("cpu_max: %d\n", cfg->cpu_max);
79 printf("loadavg: %f \n", symbols.loadavg);
80 printf("idle percent = %f\n", symbols.idle);
81 printf("numcpus %d\n", nr_cpus);
82 printf("runable_proc: %d\n", runable_proc);
83 printf("---------------------------------------------\n");
84 printf("onumcpus: %d\n", onumcpus);
85 printf("---------------------------------------------\n");
86 if (cfg->hotplug) {
87 printf("hotplug: ");
88 print_term(cfg->hotplug);
90 printf("\n");
91 if (cfg->hotunplug) {
92 printf("hotunplug: ");
93 print_term(cfg->hotunplug);
95 printf("\n");
96 printf("---------------------------------------------\n");
98 /* Evaluate the hotplug rule. */
99 if (cfg->hotplug && eval_term(cfg->hotplug, &symbols)) {
100 /* check the cpu nr limit */
101 if (onumcpus + 1 > cfg->cpu_max) {
102 /* cpu limit reached */
103 if (debug) {
104 if (foreground == 1)
105 printf("maximum cpu limit is "
106 "reached\n");
107 if (foreground == 0)
108 syslog(LOG_INFO, "maximum cpu"
109 " limit is reached\n");
111 return;
113 /* try to find a offline cpu */
114 for (cpu = 0; cpu < nr_cpus; cpu++)
115 if (is_online(cpu) == 0 && cpu_is_configured(cpu) != 0)
116 break;
117 if (cpu < nr_cpus) {
118 if (debug && foreground == 1)
119 printf("cpu with id %d is currently "
120 "offline and will be enabled\n",
121 cpu);
122 if (debug && foreground == 0)
123 syslog(LOG_INFO, "CPU with id %d is "
124 "currently offline and will be "
125 "enabled\n", cpu);
126 if (hotplug(cpu) == -1) {
127 if (debug && foreground == 1)
128 printf("unable to find a cpu which "
129 "can be enabled\n");
130 if (debug && foreground == 0)
131 syslog(LOG_INFO, "unable to find a cpu"
132 " which can be enabled\n");
134 } else {
136 * in case we tried to enable a cpu but this failed.
137 * this is the case if a cpu is deconfigured
139 if (debug && foreground == 1)
140 printf("unable to find a cpu which can be"
141 " enabled\n");
142 if (debug && foreground == 0)
143 syslog(LOG_INFO, "unable to find a cpu which"
144 "can be enabled\n");
146 return;
148 /* Evaluate the hotplug rule. */
149 if (cfg->hotunplug && eval_term(cfg->hotunplug, &symbols)) {
150 /* check cpu nr limit */
151 if (onumcpus <= cfg->cpu_min) {
152 if (debug) {
153 if (foreground == 1)
154 printf("minimum cpu limit "
155 "is reached\n");
156 if (foreground == 0)
157 syslog(LOG_INFO, "minimum cpu"
158 " limit is reached\n");
160 return;
162 /* try to find a online cpu */
163 for (cpu = get_numcpus() - 1; cpu >= 0; cpu--) {
164 if (is_online(cpu) != 0)
165 break;
167 if (cpu > 0) {
168 if (debug && foreground == 1)
169 printf("cpu with id %d is currently "
170 "online and will be disabled\n",
171 cpu);
172 if (debug && foreground == 0)
173 syslog(LOG_INFO, "CPU with id %d is "
174 "currently online and will be "
175 "disabled\n", cpu);
176 hotunplug(cpu);
178 return;
182 void eval_mem_rules(struct config *cfg)
184 struct symbols symbols;
185 int cmmpages_size;
186 int free_memory = get_free_memsize();
188 if (free_memory == -1) {
189 if (foreground == 1)
190 printf("Failed to retrieve the free mem size: "
191 "Aborting.\n");
192 if (foreground == 0)
193 syslog(LOG_INFO, "Failed to retrieve the free mem size:"
194 " Aborting.\n");
195 clean_up();
197 cmmpages_size = get_cmmpages_size();
198 symbols.apcr = apcr;
199 symbols.swaprate = swaprate;
200 symbols.freemem = free_memory;
202 /* only use this for development and testing */
203 if (debug && foreground == 1) {
204 printf("---------------------------------------------\n");
205 printf("update_interval: %d s\n", cfg->update);
206 printf("cmm_min: %d\n", cfg->cmm_min);
207 printf("cmm_max: %d\n", cfg->cmm_max);
208 printf("swaprate: %d\n", swaprate);
209 printf("apcr: %d\n", apcr);
210 printf("cmm_inc: %d\n", cfg->cmm_inc);
211 printf("free memory: %d MB\n", free_memory);
212 printf("---------------------------------------------\n");
213 printf("cmm_pages: %d\n", cmmpages_size);
214 printf("---------------------------------------------\n");
215 if (cfg->memplug) {
216 printf("memplug: ");
217 print_term(cfg->memplug);
219 printf("\n");
220 if (cfg->memunplug) {
221 printf("memunplug: ");
222 print_term(cfg->memunplug);
224 printf("\n");
225 printf("---------------------------------------------\n");
227 /* Evaluate the memunplug rule. */
228 if (cfg->memunplug && eval_term(cfg->memunplug, &symbols)) {
230 * case where cmm has asynchronously increased
231 * cmm_pages after cpuplugd reset it to cmm_max
232 * at cpuplugd startup.
235 if (cmmpages_size > cfg->cmm_max) {
236 if (debug) {
237 if (foreground == 1)
238 printf("Found cmm_pages above Limit. "
239 "Resetting value to %d\n"
240 , cfg->cmm_max);
241 if (foreground == 0)
242 syslog(LOG_INFO, "Found cmm_pages above"
243 "Limit. Resetting value to %d\n"
244 , cfg->cmm_max);
246 set_cmm_pages(cfg->cmm_max);
247 return;
249 /* check memory limit */
250 if (cmmpages_size + cfg->cmm_inc > cfg->cmm_max) {
251 if (debug) {
252 if (foreground == 1)
253 printf("maximum memory limit "
254 "is reached\n");
255 if (foreground == 0)
256 syslog(LOG_INFO, "maximum memory"
257 " limit is reached\n");
259 if (cmmpages_size < cfg->cmm_max) {
260 /* if the next increment would exceed
261 * the maximum we advance to the
262 * maximum
264 set_cmm_pages(cfg->cmm_max);
265 return;
267 } else {
268 memunplug(cfg->cmm_inc);
269 return;
272 /* Evaluate the memplug rule. */
273 if (cfg->memplug && eval_term(cfg->memplug, &symbols)) {
274 /* check memory limit */
275 if (cmmpages_size - cfg->cmm_inc < cfg->cmm_min) {
276 if (debug) {
277 if (foreground == 1)
278 printf("minimum memory limit "
279 "is reached\n");
280 if (foreground == 0)
281 syslog(LOG_INFO, "minimum memory"
282 " limit is reached\n");
283 if (cmmpages_size > cfg->cmm_min) {
284 /* if the next increment would exceed
285 * the minimum we advance to the
286 * minimum
288 set_cmm_pages(cfg->cmm_min);
289 return;
292 } else {
293 memplug(cfg->cmm_inc);
294 return;
299 int main(int argc, char *argv[])
301 int rc;
302 /* This is needed to validate the config file */
303 sem = 1;
304 cfg.cpu_max = -1;
305 cfg.cpu_min = -1;
306 cfg.update = -1;
307 cfg.cmm_min = -1;
308 cfg.cmm_max = -1;
309 cfg.cmm_inc = -1;
310 cfg.memplug = NULL;
311 cfg.memunplug = NULL;
312 cfg.hotplug = NULL;
313 cfg.hotunplug = NULL;
314 /* parse the command line options */
315 parse_options(argc, argv);
316 /* make sure that the daemon is not started multiple times */
317 check_if_started_twice();
318 /* Store daemon pid also in foreground mode */
319 handle_signals();
320 handle_sighup();
321 /* arguments taken from the configuration file */
322 parse_configfile(&cfg, configfile);
323 /*check if the required settings are found in the configuration file*/
324 check_config(&cfg);
325 check_max(&cfg);
326 if (!foreground) {
327 rc = daemon(1, 0);
328 if (rc < 0) {
329 if (foreground == 1)
330 fprintf(stderr, "Detach from terminal failed: "
331 "%s\n", strerror(errno));
332 if (foreground == 0)
333 syslog(LOG_INFO, "Detach from terminal failed: "
334 "%s\n", strerror(errno));
335 clean_up();
338 /* Store daemon pid */
339 store_pid();
340 /* thread to collect vmstat data */
341 pthread_t thread_id1;
342 struct vmstat *vs = malloc(sizeof(struct vmstat));
343 if (vs == NULL) {
344 if (foreground == 1)
345 printf("Out of memory: Aborting.\n");
346 if (foreground == 0)
347 syslog(LOG_INFO, "Out of memory: Aborting.\n");
348 clean_up();
351 * If the thread routine requires multiple arguments, they must be
352 * passed bundled up in an array or a structure
354 struct thread1_params t1args;
355 t1args.vs = vs;
356 t1args.pm = m;
357 if (pthread_create(&thread_id1, NULL, &get_info, &t1args)) {
358 if (foreground == 1)
359 printf("Failed to start thread.\n");
360 if (foreground == 0)
361 syslog(LOG_INFO, "Failed to start thread\n");
363 /* ensure that reliable data from vmstat is gathered */
364 while (memory == 1 && vs->available == 0)
365 sleep(1);
367 /* main loop */
368 cfg.idle_ticks = get_idle_ticks();
369 while (1) {
370 if (sem == 0) {
371 sleep(cfg.update);
372 continue;
374 if (setjmp(buf) == 0) {
376 /* install signal handler for floating point
377 * exceptions
379 sigemptyset(&set);
380 sigaddset(&set, SIGFPE);
381 action_signal.sa_flags = 0;
382 sigemptyset(&action_signal.sa_mask);
383 action_signal.sa_handler = handler;
384 sigaction(SIGFPE, &action_signal, NULL);
385 /* Run code that may signal failure via longjmp. */
386 if (cpu == 1)
387 eval_cpu_rules(&cfg);
388 if (memory == 1)
389 eval_mem_rules(&cfg);
390 sleep(cfg.update);
391 } else {
392 sleep(cfg.update);
393 sigprocmask(SIG_UNBLOCK, &set , NULL);
394 continue;
397 return 0;