root/terminal.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dmtcp_Terminal_EventHook
  2. save_term_settings
  3. safe_tcsetattr
  4. restore_term_settings

   1 #include <termios.h>
   2 #include <signal.h>
   3 #include <sys/ioctl.h>
   4 #include "config.h"
   5 #ifdef HAS_PR_SET_PTRACER
   6 # include <sys/prctl.h>
   7 #endif
   8 #include "dmtcp.h"
   9 #include "../jalib/jassert.h"
  10 
  11 /*************************************************************************
  12  *
  13  *  Save and restore terminal settings.
  14  *
  15  *************************************************************************/
  16 
  17 static int saved_termios_exists = 0;
  18 static struct termios saved_termios;
  19 static struct winsize win;
  20 
  21 static void save_term_settings();
  22 static void restore_term_settings();
  23 
  24 void dmtcp_Terminal_EventHook(DmtcpEvent_t event, DmtcpEventData_t *data)
  25 {
  26   switch (event) {
  27     case DMTCP_EVENT_THREADS_SUSPEND:
  28       save_term_settings();
  29       break;
  30 
  31     case DMTCP_EVENT_THREADS_RESUME:
  32       if (data->resumeInfo.isRestart) {
  33         restore_term_settings();
  34         /* If DMTCP_RESTART_PAUSE2 set, sleep 15 seconds to allow gdb attach.*/
  35         if (getenv("MTCP_RESTART_PAUSE2") || getenv("DMTCP_RESTART_PAUSE2")) {
  36 #ifdef HAS_PR_SET_PTRACER
  37           prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0); //For: gdb attach
  38 #endif
  39           struct timespec delay = {15, 0}; /* 15 seconds */
  40           printf("Pausing 15 seconds. Do:  gdb <PROGNAME> %d\n",
  41           dmtcp_virtual_to_real_pid(getpid()));
  42           nanosleep(&delay, NULL);
  43 #ifdef HAS_PR_SET_PTRACER
  44           prctl(PR_SET_PTRACER, 0, 0, 0, 0); // Revert permission to default.
  45 #endif
  46         }
  47       }
  48       break;
  49 
  50     default:
  51       break;
  52   }
  53 }
  54 
  55 static void save_term_settings()
  56 {
  57   /* Drain stdin and stdout before checkpoint */
  58   tcdrain(STDOUT_FILENO);
  59   tcdrain(STDERR_FILENO);
  60 
  61   saved_termios_exists = ( isatty(STDIN_FILENO)
  62                            && tcgetattr(STDIN_FILENO, &saved_termios) >= 0 );
  63   if (saved_termios_exists)
  64     ioctl (STDIN_FILENO, TIOCGWINSZ, (char *) &win);
  65 }
  66 
  67 static int safe_tcsetattr(int fd, int optional_actions,
  68                           const struct termios *termios_p)
  69 {
  70   struct termios old_termios, new_termios;
  71   /* We will compare old and new, and we don't want uninitialized data */
  72   memset(&new_termios, 0, sizeof(new_termios));
  73   /* tcgetattr returns success as long as at least one of requested
  74    * changes was executed.  So, repeat until no more changes.
  75    */
  76   do {
  77     memcpy(&old_termios, &new_termios, sizeof(new_termios));
  78     if (tcsetattr(fd, TCSANOW, termios_p) == -1) return -1;
  79     if (tcgetattr(fd, &new_termios) == -1) return -1;
  80   } while (memcmp(&new_termios, &old_termios, sizeof(new_termios)) != 0);
  81   return 0;
  82 }
  83 
  84 // FIXME: Handle Virtual Pids
  85 static void restore_term_settings()
  86 {
  87   if (saved_termios_exists){
  88     /* First check if we are in foreground. If not, skip this and print
  89      *   warning.  If we try to call tcsetattr in background, we will hang up.
  90      */
  91     int foreground = (tcgetpgrp(STDIN_FILENO) == getpgrp());
  92     JTRACE("restore terminal attributes, check foreground status first")
  93       (foreground);
  94     if (foreground) {
  95       if ( ( ! isatty(STDIN_FILENO)
  96              || safe_tcsetattr(STDIN_FILENO, TCSANOW, &saved_termios) == -1) )
  97         JWARNING(false) .Text("failed to restore terminal");
  98       else {
  99         struct winsize cur_win;
 100         JTRACE("restored terminal");
 101         ioctl (STDIN_FILENO, TIOCGWINSZ, (char *) &cur_win);
 102         /* ws_row/ws_col was probably not 0/0 prior to checkpoint.  We change
 103          * it back to last known row/col prior to checkpoint, and then send a
 104          * SIGWINCH (see below) to notify process that window might have changed
 105          */
 106         if (cur_win.ws_row == 0 && cur_win.ws_col == 0)
 107           ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win);
 108       }
 109     } else {
 110       JWARNING(false)
 111         .Text(":skip restore terminal step -- we are in BACKGROUND");
 112     }
 113   }
 114   /*
 115    * NOTE:
 116    * Apache, when running in debug mode (-X), uses SIGWINCH
 117    * as a signal for stopping gracefully. Please comment out
 118    * the next line to prevent DMTCP from sending a SIGWINCH
 119    * on restart when testing with Apache.
 120    *
 121    * TODO:
 122    * This should be done automatically by wrapping it in an ifdef
 123    * or if condition that disables the SIGWINCH using configure or
 124    * a runtime option (--no-sigwinch).
 125    */
 126   if (kill(getpid(), SIGWINCH) == -1) {}  /* No remedy if error */
 127 }
 128 

/* [<][>][^][v][top][bottom][index][help] */