TraceScreen.c 6.47 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, LISTITEM_CLASS, false, ListItem_compare);
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
90
91
92
}

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);
      fcntl(fdpair[1], F_SETFL, O_NONBLOCK);
      sprintf(buffer, "%d", this->process->pid);
      execlp("strace", "strace", "-p", buffer, NULL);
93
94
      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
95
96
97
98
      exit(1);
   }
   fcntl(fdpair[0], F_SETFL, O_NONBLOCK);
   FILE* strace = fdopen(fdpair[0], "r");
Hisham Muhammad's avatar
Hisham Muhammad committed
99
   Panel* panel = this->display;
Hisham Muhammad's avatar
Hisham Muhammad committed
100
101
102
103
104
   int fd_strace = fileno(strace);
   CRT_disableDelay();
   bool contLine = false;
   bool follow = false;
   bool looping = true;
105
106
107
108
109
110
111
112

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

   Vector* lines = Vector_new(panel->items->type, true, DEFAULT_SIZE, ListItem_compare);

   TraceScreen_draw(this, inc);
   
Hisham Muhammad's avatar
Hisham Muhammad committed
113
   while (looping) {
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145

      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);
         FD_SET(STDIN_FILENO, &fds);
         FD_SET(fd_strace, &fds);
         //struct timeval tv;
         //tv.tv_sec = 0; tv.tv_usec = 500;
         int ready = select(fd_strace+1, &fds, NULL, NULL, NULL/*&tv*/);
         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
146
147
               }
            }
148
149
150
151
152
153
154
            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
155
156
         }
      }
157
            
Hisham Muhammad's avatar
Hisham Muhammad committed
158
159
160
161
      if (ch == KEY_MOUSE) {
         MEVENT mevent;
         int ok = getmouse(&mevent);
         if (ok == OK)
Hisham Muhammad's avatar
Hisham Muhammad committed
162
163
            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
164
165
166
               follow = false;
               ch = 0;
            } if (mevent.y == LINES - 1)
167
               ch = FunctionBar_synthesizeEvent(inc->bar, mevent.x);
Hisham Muhammad's avatar
Hisham Muhammad committed
168
      }
169
170
171
172
173
174
      
      if (inc->active) {
         IncSet_handleKey(inc, ch, panel, IncSet_getListItemValue, lines);
         continue;
      }
      
Hisham Muhammad's avatar
Hisham Muhammad committed
175
176
177
      switch(ch) {
      case ERR:
         continue;
178
179
180
181
182
183
      case KEY_HOME:
         Panel_setSelected(panel, 0);
         break;
      case KEY_END:
         Panel_setSelected(panel, Panel_size(panel)-1);
         break;
184
185
186
187
      case KEY_F(3):
      case '/':
         IncSet_activate(inc, INC_SEARCH);
         break;
Hisham Muhammad's avatar
Hisham Muhammad committed
188
      case KEY_F(4):
189
190
191
192
193
      case '\\':
         IncSet_activate(inc, INC_FILTER);
         break;
      case 'f':
      case KEY_F(8):
Hisham Muhammad's avatar
Hisham Muhammad committed
194
195
         follow = !follow;
         if (follow)
Hisham Muhammad's avatar
Hisham Muhammad committed
196
            Panel_setSelected(panel, Panel_size(panel)-1);
Hisham Muhammad's avatar
Hisham Muhammad committed
197
         break;
198
199
200
201
202
203
      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
204
205
      case 'q':
      case 27:
206
      case KEY_F(10):
Hisham Muhammad's avatar
Hisham Muhammad committed
207
208
209
         looping = false;
         break;
      case KEY_RESIZE:
Hisham Muhammad's avatar
Hisham Muhammad committed
210
         Panel_resize(panel, COLS, LINES-2);
211
         TraceScreen_draw(this, inc);
Hisham Muhammad's avatar
Hisham Muhammad committed
212
213
214
         break;
      default:
         follow = false;
Hisham Muhammad's avatar
Hisham Muhammad committed
215
         Panel_onKey(panel, ch);
Hisham Muhammad's avatar
Hisham Muhammad committed
216
217
      }
   }
218
219
220
221
   
   IncSet_delete(inc);
   FunctionBar_delete((Object*)bar);
   
Hisham Muhammad's avatar
Hisham Muhammad committed
222
   kill(child, SIGTERM);
223
   waitpid(child, NULL, 0);
Hisham Muhammad's avatar
Hisham Muhammad committed
224
   fclose(strace);
Hisham Muhammad's avatar
Hisham Muhammad committed
225
   CRT_enableDelay();
Hisham Muhammad's avatar
Hisham Muhammad committed
226
}