TraceScreen.c 6.49 KB
Newer Older
Hisham Muhammad's avatar
Hisham Muhammad committed
1
2
/*
htop - TraceScreen.c
Hisham Muhammad's avatar
Hisham Muhammad committed
3
(C) 2005-2006 Hisham H. Muhammad
Hisham Muhammad's avatar
Hisham Muhammad committed
4
5
6
7
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/

Hisham Muhammad's avatar
Hisham Muhammad committed
8
9
10
11
12
#include "TraceScreen.h"

#include "CRT.h"
#include "ProcessList.h"
#include "ListItem.h"
13
14
#include "IncSet.h"
#include "String.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
15

Hisham Muhammad's avatar
Hisham Muhammad committed
16
17
#include <stdio.h>
#include <unistd.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
18
19
#include <string.h>
#include <stdlib.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
20
21
22
#include <stdbool.h>
#include <unistd.h>
#include <fcntl.h>
23
24
#include <sys/types.h>
#include <sys/wait.h>
25
#include <signal.h>
Hisham Muhammad's avatar
Hisham Muhammad committed
26

Hisham Muhammad's avatar
Hisham Muhammad committed
27
/*{
Hisham Muhammad's avatar
Hisham Muhammad committed
28
#include "Process.h"
29
#include "Panel.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
30
#include "FunctionBar.h"
Hisham Muhammad's avatar
Hisham Muhammad committed
31
32
33

typedef struct TraceScreen_ {
   Process* process;
34
   Panel* display;
Hisham Muhammad's avatar
Hisham Muhammad committed
35
36
37
38
39
   bool tracing;
} TraceScreen;

}*/

40
static const char* tsFunctions[] = {"Search ", "Filter ", "AutoScroll ", "Stop Tracing   ", "Done   ", NULL};
Hisham Muhammad's avatar
Hisham Muhammad committed
41

42
static const char* tsKeys[] = {"F3", "F4", "F8", "F9", "Esc"};
Hisham Muhammad's avatar
Hisham Muhammad committed
43

44
static int tsEvents[] = {KEY_F(3), KEY_F(4), KEY_F(8), KEY_F(9), 27};
Hisham Muhammad's avatar
Hisham Muhammad committed
45
46
47
48

TraceScreen* TraceScreen_new(Process* process) {
   TraceScreen* this = (TraceScreen*) malloc(sizeof(TraceScreen));
   this->process = process;
49
   this->display = Panel_new(0, 1, COLS, LINES-2, false, Class(ListItem));
Hisham Muhammad's avatar
Hisham Muhammad committed
50
51
52
53
54
   this->tracing = true;
   return this;
}

void TraceScreen_delete(TraceScreen* this) {
55
   Panel_delete((Object*)this->display);
Hisham Muhammad's avatar
Hisham Muhammad committed
56
57
58
   free(this);
}

59
static void TraceScreen_draw(TraceScreen* this, IncSet* inc) {
Hisham Muhammad's avatar
Hisham Muhammad committed
60
61
62
63
   attrset(CRT_colors[PANEL_HEADER_FOCUS]);
   mvhline(0, 0, ' ', COLS);
   mvprintw(0, 0, "Trace of process %d - %s", this->process->pid, this->process->comm);
   attrset(CRT_colors[DEFAULT_COLOR]);
64
65
66
67
68
69
70
71
72
73
74
75
76
77
   IncSet_drawBar(inc);
}

static inline void addLine(const char* line, Vector* lines, Panel* panel, const char* incFilter) {
   Vector_add(lines, (Object*) ListItem_new(line, 0));
   if (!incFilter || String_contains_i(line, incFilter))
      Panel_add(panel, (Object*)Vector_get(lines, Vector_size(lines)-1));
}

static inline void appendLine(const char* line, Vector* lines, Panel* panel, const char* incFilter) {
   ListItem* last = (ListItem*)Vector_get(lines, Vector_size(lines)-1);
   ListItem_append(last, line);
   if (incFilter && Panel_get(panel, Panel_size(panel)-1) != (Object*)last && String_contains_i(line, incFilter))
      Panel_add(panel, (Object*)last);
Hisham Muhammad's avatar
Hisham Muhammad committed
78
79
80
81
82
83
84
85
86
87
88
89
}

void TraceScreen_run(TraceScreen* this) {
//   if (this->process->pid == getpid()) return;
   char buffer[1001];
   int fdpair[2];
   int err = pipe(fdpair);
   if (err == -1) return;
   int child = fork();
   if (child == -1) return;
   if (child == 0) {
      dup2(fdpair[1], STDERR_FILENO);
90
91
92
93
94
      int ok = fcntl(fdpair[1], F_SETFL, O_NONBLOCK);
      if (ok != -1) {
         sprintf(buffer, "%d", this->process->pid);
         execlp("strace", "strace", "-p", buffer, NULL);
      }
95
96
      const char* message = "Could not execute 'strace'. Please make sure it is available in your $PATH.";
      write(fdpair[1], message, strlen(message));
Hisham Muhammad's avatar
Hisham Muhammad committed
97
98
99
100
      exit(1);
   }
   fcntl(fdpair[0], F_SETFL, O_NONBLOCK);
   FILE* strace = fdopen(fdpair[0], "r");
Hisham Muhammad's avatar
Hisham Muhammad committed
101
   Panel* panel = this->display;
Hisham Muhammad's avatar
Hisham Muhammad committed
102
103
104
105
106
   int fd_strace = fileno(strace);
   CRT_disableDelay();
   bool contLine = false;
   bool follow = false;
   bool looping = true;
107
108
109
110

   FunctionBar* bar = FunctionBar_new(tsFunctions, tsKeys, tsEvents);
   IncSet* inc = IncSet_new(bar);

111
   Vector* lines = Vector_new(panel->items->type, true, DEFAULT_SIZE);
112
113
114

   TraceScreen_draw(this, inc);
   
Hisham Muhammad's avatar
Hisham Muhammad committed
115
   while (looping) {
116
117
118
119
120
121
122
123
124
125
126

      Panel_draw(panel, true);
      const char* incFilter = IncSet_filter(inc);

      if (inc->active)
         move(LINES-1, CRT_cursorX);
      int ch = getch();
      
      if (ch == ERR) {
         fd_set fds;
         FD_ZERO(&fds);
127
//         FD_SET(STDIN_FILENO, &fds);
128
         FD_SET(fd_strace, &fds);
129
130
131
         struct timeval tv;
         tv.tv_sec = 0; tv.tv_usec = 500;
         int ready = select(fd_strace+1, &fds, NULL, NULL, &tv);
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
         int nread = 0;
         if (ready > 0 && FD_ISSET(fd_strace, &fds))
            nread = fread(buffer, 1, 1000, strace);
         if (nread && this->tracing) {
            char* line = buffer;
            buffer[nread] = '\0';
            for (int i = 0; i < nread; i++) {
               if (buffer[i] == '\n') {
                  buffer[i] = '\0';
                  if (contLine) {
                     appendLine(line, lines, panel, incFilter);
                     contLine = false;
                  } else {
                     addLine(line, lines, panel, incFilter);
                  }
                  line = buffer+i+1;
Hisham Muhammad's avatar
Hisham Muhammad committed
148
149
               }
            }
150
151
152
153
154
155
156
            if (line < buffer+nread) {
               addLine(line, lines, panel, incFilter);
               buffer[nread] = '\0';
               contLine = true;
            }
            if (follow)
               Panel_setSelected(panel, Panel_size(panel)-1);
Hisham Muhammad's avatar
Hisham Muhammad committed
157
158
         }
      }
159
            
Hisham Muhammad's avatar
Hisham Muhammad committed
160
161
162
163
      if (ch == KEY_MOUSE) {
         MEVENT mevent;
         int ok = getmouse(&mevent);
         if (ok == OK)
Hisham Muhammad's avatar
Hisham Muhammad committed
164
165
            if (mevent.y >= panel->y && mevent.y < LINES - 1) {
               Panel_setSelected(panel, mevent.y - panel->y + panel->scrollV);
Hisham Muhammad's avatar
Hisham Muhammad committed
166
167
168
               follow = false;
               ch = 0;
            } if (mevent.y == LINES - 1)
169
               ch = FunctionBar_synthesizeEvent(inc->bar, mevent.x);
Hisham Muhammad's avatar
Hisham Muhammad committed
170
      }
171
172
173
174
175
176
      
      if (inc->active) {
         IncSet_handleKey(inc, ch, panel, IncSet_getListItemValue, lines);
         continue;
      }
      
Hisham Muhammad's avatar
Hisham Muhammad committed
177
178
179
      switch(ch) {
      case ERR:
         continue;
180
181
182
183
184
185
      case KEY_HOME:
         Panel_setSelected(panel, 0);
         break;
      case KEY_END:
         Panel_setSelected(panel, Panel_size(panel)-1);
         break;
186
187
188
189
      case KEY_F(3):
      case '/':
         IncSet_activate(inc, INC_SEARCH);
         break;
Hisham Muhammad's avatar
Hisham Muhammad committed
190
      case KEY_F(4):
191
192
193
194
195
      case '\\':
         IncSet_activate(inc, INC_FILTER);
         break;
      case 'f':
      case KEY_F(8):
Hisham Muhammad's avatar
Hisham Muhammad committed
196
197
         follow = !follow;
         if (follow)
Hisham Muhammad's avatar
Hisham Muhammad committed
198
            Panel_setSelected(panel, Panel_size(panel)-1);
Hisham Muhammad's avatar
Hisham Muhammad committed
199
         break;
200
201
202
203
204
205
      case 't':
      case KEY_F(9):
         this->tracing = !this->tracing;
         FunctionBar_setLabel(bar, KEY_F(9), this->tracing?"Stop Tracing   ":"Resume Tracing ");
         TraceScreen_draw(this, inc);
         break;
Hisham Muhammad's avatar
Hisham Muhammad committed
206
207
      case 'q':
      case 27:
208
      case KEY_F(10):
Hisham Muhammad's avatar
Hisham Muhammad committed
209
210
211
         looping = false;
         break;
      case KEY_RESIZE:
Hisham Muhammad's avatar
Hisham Muhammad committed
212
         Panel_resize(panel, COLS, LINES-2);
213
         TraceScreen_draw(this, inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
214
215
216
         break;
      default:
         follow = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
217
         Panel_onKey(panel, ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
218
219
      }
   }
220
221
222
   
   IncSet_delete(inc);
   FunctionBar_delete((Object*)bar);
223
   Vector_delete(lines);
224
   
Hisham Muhammad's avatar
Hisham Muhammad committed
225
   kill(child, SIGTERM);
226
   waitpid(child, NULL, 0);
Hisham Muhammad's avatar
Hisham Muhammad committed
227
   fclose(strace);
Hisham Muhammad's avatar
Hisham Muhammad committed
228
   CRT_enableDelay();
Hisham Muhammad's avatar
Hisham Muhammad committed
229
}