linux/tools/thermal/tmon/tmon.c
<<
>>
Prefs
   1/*
   2 * tmon.c Thermal Monitor (TMON) main function and entry point
   3 *
   4 * Copyright (C) 2012 Intel Corporation. All rights reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License version
   8 * 2 or later as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * Author: Jacob Pan <jacob.jun.pan@linux.intel.com>
  16 *
  17 */
  18
  19#include <getopt.h>
  20#include <unistd.h>
  21#include <stdio.h>
  22#include <stdlib.h>
  23#include <string.h>
  24#include <sys/types.h>
  25#include <sys/stat.h>
  26#include <ncurses.h>
  27#include <ctype.h>
  28#include <time.h>
  29#include <signal.h>
  30#include <limits.h>
  31#include <sys/time.h>
  32#include <pthread.h>
  33#include <math.h>
  34#include <stdarg.h>
  35#include <syslog.h>
  36
  37#include "tmon.h"
  38
  39unsigned long ticktime = 1; /* seconds */
  40unsigned long no_control = 1; /* monitoring only or use cooling device for
  41                               * temperature control.
  42                               */
  43double time_elapsed = 0.0;
  44unsigned long target_temp_user = 65; /* can be select by tui later */
  45int dialogue_on;
  46int tmon_exit;
  47static short    daemon_mode;
  48static int logging; /* for recording thermal data to a file */
  49static int debug_on;
  50FILE *tmon_log;
  51/*cooling device used for the PID controller */
  52char ctrl_cdev[CDEV_NAME_SIZE] = "None";
  53int target_thermal_zone; /* user selected target zone instance */
  54static void     start_daemon_mode(void);
  55
  56pthread_t event_tid;
  57pthread_mutex_t input_lock;
  58void usage()
  59{
  60        printf("Usage: tmon [OPTION...]\n");
  61        printf("  -c, --control         cooling device in control\n");
  62        printf("  -d, --daemon          run as daemon, no TUI\n");
  63        printf("  -g, --debug           debug message in syslog\n");
  64        printf("  -h, --help            show this help message\n");
  65        printf("  -l, --log             log data to /var/tmp/tmon.log\n");
  66        printf("  -t, --time-interval   sampling time interval, > 1 sec.\n");
  67        printf("  -v, --version         show version\n");
  68        printf("  -z, --zone            target thermal zone id\n");
  69
  70        exit(0);
  71}
  72
  73void version()
  74{
  75        printf("TMON version %s\n", VERSION);
  76        exit(EXIT_SUCCESS);
  77}
  78
  79static void tmon_cleanup(void)
  80{
  81
  82        syslog(LOG_INFO, "TMON exit cleanup\n");
  83        fflush(stdout);
  84        refresh();
  85        if (tmon_log)
  86                fclose(tmon_log);
  87        if (event_tid) {
  88                pthread_mutex_lock(&input_lock);
  89                pthread_cancel(event_tid);
  90                pthread_mutex_unlock(&input_lock);
  91                pthread_mutex_destroy(&input_lock);
  92        }
  93        closelog();
  94        /* relax control knobs, undo throttling */
  95        set_ctrl_state(0);
  96
  97        keypad(stdscr, FALSE);
  98        echo();
  99        nocbreak();
 100        close_windows();
 101        endwin();
 102        free_thermal_data();
 103
 104        exit(1);
 105}
 106
 107
 108static void tmon_sig_handler(int sig)
 109{
 110        syslog(LOG_INFO, "TMON caught signal %d\n", sig);
 111        refresh();
 112        switch (sig) {
 113        case SIGTERM:
 114                printf("sigterm, exit and clean up\n");
 115                fflush(stdout);
 116                break;
 117        case SIGKILL:
 118                printf("sigkill, exit and clean up\n");
 119                fflush(stdout);
 120                break;
 121        case SIGINT:
 122                printf("ctrl-c, exit and clean up\n");
 123                fflush(stdout);
 124                break;
 125        default:
 126                break;
 127        }
 128        tmon_exit = true;
 129}
 130
 131
 132static void start_syslog(void)
 133{
 134        if (debug_on)
 135                setlogmask(LOG_UPTO(LOG_DEBUG));
 136        else
 137                setlogmask(LOG_UPTO(LOG_ERR));
 138        openlog("tmon.log", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL0);
 139        syslog(LOG_NOTICE, "TMON started by User %d", getuid());
 140}
 141
 142static void prepare_logging(void)
 143{
 144        int i;
 145
 146        if (!logging)
 147                return;
 148        /* open local data log file */
 149        tmon_log = fopen(TMON_LOG_FILE, "w+");
 150        if (!tmon_log) {
 151                syslog(LOG_ERR, "failed to open log file %s\n", TMON_LOG_FILE);
 152                return;
 153        }
 154
 155        fprintf(tmon_log, "#----------- THERMAL SYSTEM CONFIG -------------\n");
 156        for (i = 0; i < ptdata.nr_tz_sensor; i++) {
 157                char binding_str[33]; /* size of long + 1 */
 158                int j;
 159
 160                memset(binding_str, 0, sizeof(binding_str));
 161                for (j = 0; j < 32; j++)
 162                        binding_str[j] = (ptdata.tzi[i].cdev_binding & 1<<j) ?
 163                                '1' : '0';
 164
 165                fprintf(tmon_log, "#thermal zone %s%02d cdevs binding: %32s\n",
 166                        ptdata.tzi[i].type,
 167                        ptdata.tzi[i].instance,
 168                        binding_str);
 169                for (j = 0; j < ptdata.tzi[i].nr_trip_pts; j++) {
 170                        fprintf(tmon_log, "#\tTP%02d type:%s, temp:%lu\n", j,
 171                                trip_type_name[ptdata.tzi[i].tp[j].type],
 172                                ptdata.tzi[i].tp[j].temp);
 173                }
 174
 175        }
 176
 177        for (i = 0; i < ptdata.nr_cooling_dev; i++)
 178                fprintf(tmon_log, "#cooling devices%02d: %s\n",
 179                        i, ptdata.cdi[i].type);
 180
 181        fprintf(tmon_log, "#---------- THERMAL DATA LOG STARTED -----------\n");
 182        fprintf(tmon_log, "Samples TargetTemp ");
 183        for (i = 0; i < ptdata.nr_tz_sensor; i++) {
 184                fprintf(tmon_log, "%s%d    ", ptdata.tzi[i].type,
 185                        ptdata.tzi[i].instance);
 186        }
 187        for (i = 0; i < ptdata.nr_cooling_dev; i++)
 188                fprintf(tmon_log, "%s%d ", ptdata.cdi[i].type,
 189                        ptdata.cdi[i].instance);
 190
 191        fprintf(tmon_log, "\n");
 192}
 193
 194static struct option opts[] = {
 195        { "control", 1, NULL, 'c' },
 196        { "daemon", 0, NULL, 'd' },
 197        { "time-interval", 1, NULL, 't' },
 198        { "log", 0, NULL, 'l' },
 199        { "help", 0, NULL, 'h' },
 200        { "version", 0, NULL, 'v' },
 201        { "debug", 0, NULL, 'g' },
 202        { 0, 0, NULL, 0 }
 203};
 204
 205
 206int main(int argc, char **argv)
 207{
 208        int err = 0;
 209        int id2 = 0, c;
 210        double yk = 0.0; /* controller output */
 211        int target_tz_index;
 212
 213        if (geteuid() != 0) {
 214                printf("TMON needs to be run as root\n");
 215                exit(EXIT_FAILURE);
 216        }
 217
 218        while ((c = getopt_long(argc, argv, "c:dlht:vgz:", opts, &id2)) != -1) {
 219                switch (c) {
 220                case 'c':
 221                        no_control = 0;
 222                        strncpy(ctrl_cdev, optarg, CDEV_NAME_SIZE);
 223                        break;
 224                case 'd':
 225                        start_daemon_mode();
 226                        printf("Run TMON in daemon mode\n");
 227                        break;
 228                case 't':
 229                        ticktime = strtod(optarg, NULL);
 230                        if (ticktime < 1)
 231                                ticktime = 1;
 232                        break;
 233                case 'l':
 234                        printf("Logging data to /var/tmp/tmon.log\n");
 235                        logging = 1;
 236                        break;
 237                case 'h':
 238                        usage();
 239                        break;
 240                case 'v':
 241                        version();
 242                        break;
 243                case 'g':
 244                        debug_on = 1;
 245                        break;
 246                case 'z':
 247                        target_thermal_zone = strtod(optarg, NULL);
 248                        break;
 249                default:
 250                        break;
 251                }
 252        }
 253        if (pthread_mutex_init(&input_lock, NULL) != 0) {
 254                fprintf(stderr, "\n mutex init failed, exit\n");
 255                return 1;
 256        }
 257        start_syslog();
 258        if (signal(SIGINT, tmon_sig_handler) == SIG_ERR)
 259                syslog(LOG_DEBUG, "Cannot handle SIGINT\n");
 260        if (signal(SIGTERM, tmon_sig_handler) == SIG_ERR)
 261                syslog(LOG_DEBUG, "Cannot handle SIGINT\n");
 262
 263        if (probe_thermal_sysfs()) {
 264                pthread_mutex_destroy(&input_lock);
 265                closelog();
 266                return -1;
 267        }
 268        initialize_curses();
 269        setup_windows();
 270        signal(SIGWINCH, resize_handler);
 271        show_title_bar();
 272        show_sensors_w();
 273        show_cooling_device();
 274        update_thermal_data();
 275        show_data_w();
 276        prepare_logging();
 277        init_thermal_controller();
 278
 279        nodelay(stdscr, TRUE);
 280        err = pthread_create(&event_tid, NULL, &handle_tui_events, NULL);
 281        if (err != 0) {
 282                printf("\ncan't create thread :[%s]", strerror(err));
 283                tmon_cleanup();
 284                exit(EXIT_FAILURE);
 285        }
 286
 287        /* validate range of user selected target zone, default to the first
 288         * instance if out of range
 289         */
 290        target_tz_index = zone_instance_to_index(target_thermal_zone);
 291        if (target_tz_index < 0) {
 292                target_thermal_zone = ptdata.tzi[0].instance;
 293                syslog(LOG_ERR, "target zone is not found, default to %d\n",
 294                        target_thermal_zone);
 295        }
 296        while (1) {
 297                sleep(ticktime);
 298                show_title_bar();
 299                show_sensors_w();
 300                update_thermal_data();
 301                if (!dialogue_on) {
 302                        show_data_w();
 303                        show_cooling_device();
 304                }
 305                cur_thermal_record++;
 306                time_elapsed += ticktime;
 307                controller_handler(trec[0].temp[target_tz_index] / 1000,
 308                                &yk);
 309                trec[0].pid_out_pct = yk;
 310                if (!dialogue_on)
 311                        show_control_w();
 312                if (tmon_exit)
 313                        break;
 314        }
 315        tmon_cleanup();
 316        return 0;
 317}
 318
 319static void start_daemon_mode()
 320{
 321        daemon_mode = 1;
 322        /* fork */
 323        pid_t   sid, pid = fork();
 324        if (pid < 0) {
 325                exit(EXIT_FAILURE);
 326        } else if (pid > 0)
 327                /* kill parent */
 328                exit(EXIT_SUCCESS);
 329
 330        /* disable TUI, it may not be necessary, but saves some resource */
 331        disable_tui();
 332
 333        /* change the file mode mask */
 334        umask(0);
 335
 336        /* new SID for the daemon process */
 337        sid = setsid();
 338        if (sid < 0)
 339                exit(EXIT_FAILURE);
 340
 341        /* change working directory */
 342        if ((chdir("/")) < 0)
 343                exit(EXIT_FAILURE);
 344
 345
 346        sleep(10);
 347
 348        close(STDIN_FILENO);
 349        close(STDOUT_FILENO);
 350        close(STDERR_FILENO);
 351
 352}
 353