The Pedigree Project  0.1
ThreadsCommand.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #if defined(THREADS)
21 
22 #include "pedigree/kernel/debugger/commands/ThreadsCommand.h"
23 #include "pedigree/kernel/debugger/DebuggerIO.h"
24 #include "pedigree/kernel/linker/KernelElf.h"
25 #include "pedigree/kernel/process/Process.h"
26 #include "pedigree/kernel/process/Scheduler.h"
27 #include "pedigree/kernel/process/Thread.h"
28 #include "pedigree/kernel/processor/Processor.h"
29 #include "pedigree/kernel/processor/ProcessorInformation.h"
30 #include "pedigree/kernel/utilities/demangle.h"
31 
33  : DebuggerCommand(), Scrollable(), m_SelectedLine(0), m_nLines(0)
34 {
35 }
36 
38 {
39 }
40 
42  const HugeStaticString &input, HugeStaticString &output)
43 {
44 }
45 
47  const HugeStaticString &input, HugeStaticString &output,
48  InterruptState &state, DebuggerIO *pScreen)
49 {
50  // How many lines do we have?
51  m_nLines = 0;
52  for (size_t i = 0; i < Scheduler::instance().getNumProcesses(); i++)
53  {
54  m_nLines++; // For the process.
55  m_nLines += Scheduler::instance().getProcess(i)->getNumThreads();
56  }
57 
58  // Let's enter 'raw' screen mode.
59  pScreen->disableCli();
60 
61  // Initialise the Scrollable class
62  move(0, 1);
63  resize(pScreen->getWidth(), pScreen->getHeight() - 2);
64  setScrollKeys('j', 'k');
65 
66  // Clear the top status lines.
67  pScreen->drawHorizontalLine(
68  ' ', 0, 0, pScreen->getWidth() - 1, DebuggerIO::White,
69  DebuggerIO::Green);
70 
71  // Write the correct text in the upper status line.
72  pScreen->drawString(
73  "Pedigree debugger - Thread selector", 0, 0, DebuggerIO::White,
74  DebuggerIO::Green);
75 
76  // Clear the bottom status lines.
77  // TODO: If we use arrow keys and page up/down keys we actually can remove
78  // the status line
79  // because the interface is then intuitive enough imho.
80  pScreen->drawHorizontalLine(
81  ' ', pScreen->getHeight() - 1, 0, pScreen->getWidth() - 1,
82  DebuggerIO::White, DebuggerIO::Green);
83 
84  // Write some helper text in the lower status line.
85  // TODO FIXME: Drawing this might screw the top status bar
86  pScreen->drawString(
87  "backspace: Page up. space: Page down. q: Quit. enter: Switch to "
88  "thread",
89  pScreen->getHeight() - 1, 0, DebuggerIO::White, DebuggerIO::Green);
90  pScreen->drawString(
91  "backspace", pScreen->getHeight() - 1, 0, DebuggerIO::Yellow,
92  DebuggerIO::Green);
93  pScreen->drawString(
94  "space", pScreen->getHeight() - 1, 20, DebuggerIO::Yellow,
95  DebuggerIO::Green);
96  pScreen->drawString(
97  "q", pScreen->getHeight() - 1, 38, DebuggerIO::Yellow,
98  DebuggerIO::Green);
99  pScreen->drawString(
100  "enter", pScreen->getHeight() - 1, 47, DebuggerIO::Yellow,
101  DebuggerIO::Green);
102 
103  // Main loop.
104  bool bStop = false;
105  bool bReturn = true;
106  while (!bStop)
107  {
108  refresh(pScreen);
109 
110  // Wait for input.
111  char c = 0;
112  while (!(c = pScreen->getChar()))
113  ;
114 
115  // TODO: Use arrow keys and page up/down someday
116  if (c == 'j')
117  {
118  scroll(-1);
119  if (static_cast<ssize_t>(m_SelectedLine) - 1 >= 0)
120  m_SelectedLine--;
121  }
122  else if (c == 'k')
123  {
124  scroll(1);
125  if (m_SelectedLine + 1 < getLineCount())
126  m_SelectedLine++;
127  }
128  else if (c == ' ')
129  {
130  scroll(static_cast<ssize_t>(height()));
131  if (m_SelectedLine + height() < getLineCount())
132  m_SelectedLine += height();
133  else
134  m_SelectedLine = getLineCount() - 1;
135  }
136  else if (c == 0x08)
137  {
138  scroll(-static_cast<ssize_t>(height()));
139  if (static_cast<ssize_t>(m_SelectedLine) -
140  static_cast<ssize_t>(height()) >=
141  0)
142  m_SelectedLine -= height();
143  else
144  m_SelectedLine = 0;
145  }
146  else if (c == '\n' || c == '\r')
147  {
148  // if(swapThread(state, pScreen))
149  // {
150  // bStop = true;
151  // bReturn = false;
152  // }
153  }
154  else if (c == 'q')
155  bStop = true;
156  }
157 
158  // HACK:: Serial connections will fill the screen with the last background
159  // colour used.
160  // Here we write a space with black background so the CLI screen
161  // doesn't get filled by some random colour!
162  pScreen->drawString(" ", 1, 0, DebuggerIO::White, DebuggerIO::Black);
163  pScreen->enableCli();
164  return bReturn;
165 }
166 
167 const char *ThreadsCommand::getLine1(
168  size_t index, DebuggerIO::Colour &colour, DebuggerIO::Colour &bgColour)
169 {
170  static NormalStaticString Line;
171  Line.clear();
172 
173  // Work through our process list.
174  size_t idx = 0;
175  Process *tehProcess = 0;
176  Thread *tehThread = 0;
177  bool stop = false;
178  for (size_t i = 0; i < Scheduler::instance().getNumProcesses(); i++)
179  {
180  tehProcess = Scheduler::instance().getProcess(i);
181  if (index == idx)
182  {
183  tehThread = 0;
184  break;
185  }
186  idx++;
187 
188  for (size_t j = 0; j < tehProcess->getNumThreads(); j++)
189  {
190  if (index == idx)
191  {
192  tehThread = tehProcess->getThread(j);
193  stop = true;
194  break;
195  }
196  idx++;
197  }
198  if (stop)
199  break;
200  }
201 
202  if (!tehProcess)
203  {
204  // No processes, or the index does not match.
205  return Line;
206  }
207 
208  // If this is just a process line.
209  colour = DebuggerIO::Yellow;
210  if (index == m_SelectedLine)
211  bgColour = DebuggerIO::Blue;
212  else
213  bgColour = DebuggerIO::Black;
214  if (tehThread == 0)
215  {
216  Line += "[";
217  Line += tehProcess->getId();
218  Line += "] ";
219  Line += tehProcess->description();
220  }
221  else
222  {
223  Line += " | ";
224  }
225 
226  return Line;
227 }
228 const char *ThreadsCommand::getLine2(
229  size_t index, size_t &colOffset, DebuggerIO::Colour &colour,
230  DebuggerIO::Colour &bgColour)
231 {
232  static LargeStaticString Line;
233  Line.clear();
234 
235  // Work through our process list.
236  size_t idx = 0;
237  Process *tehProcess = 0;
238  Thread *tehThread = 0;
239  bool stop = false;
240  for (size_t i = 0; i < Scheduler::instance().getNumProcesses(); i++)
241  {
242  tehProcess = Scheduler::instance().getProcess(i);
243  if (index == idx)
244  {
245  tehThread = 0;
246  break;
247  }
248  idx++;
249  for (size_t j = 0; j < tehProcess->getNumThreads(); j++)
250  {
251  if (index == idx)
252  {
253  tehThread = tehProcess->getThread(j);
254  stop = true;
255  break;
256  }
257  idx++;
258  }
259  if (stop)
260  break;
261  }
262 
263  if (tehThread != 0 &&
264  tehThread != Processor::information().getCurrentThread())
265  {
266  Thread::Status status = tehThread->getStatus();
267  switch (status)
268  {
269  case Thread::Running:
270  Line += "r";
271  break;
272  case Thread::Ready:
273  Line += "R";
274  break;
275  case Thread::Sleeping:
276  Line += "S";
277  break;
278  case Thread::Zombie:
279  Line += "Z";
280  break;
281  case Thread::AwaitingJoin:
282  Line += "J";
283  break;
284  case Thread::Suspended:
285  Line += "s";
286  break;
287  }
288 
289  Line += "[";
290  Line += "CPU";
291  Line += tehThread->getCpuId();
292  Line += ":";
293  Line += tehThread->getId();
294  Line += "] ";
295 
296  uintptr_t ip = 0;
297  Thread::DebugState state = tehThread->getDebugState(ip);
298  if (state != Thread::None)
299  {
300  if (state == Thread::SemWait)
301  Line += "Sem-Wait @ ";
302  else if (state == Thread::Joining)
303  Line += "Joining @";
304  else if (state == Thread::CondWait)
305  Line += "Cond-Wait @";
306  else
307  Line += "<unknown DebugState> @";
308  Line.append(ip, 16);
309 
310  uintptr_t symStart;
311  const char *pSym =
312  KernelElf::instance().globalLookupSymbol(ip, &symStart);
313  if (pSym)
314  {
315  LargeStaticString sym;
316  demangle_full(LargeStaticString(pSym), sym);
317  Line += ": ";
318  Line += sym;
319  }
320  }
321  colour = DebuggerIO::LightGrey;
322  }
323  else if (tehThread != 0) // tehThread == g_pCurrentThread
324  {
325  Thread::Status status = tehThread->getStatus();
326  switch (status)
327  {
328  case Thread::Running:
329  Line += "r";
330  break;
331  case Thread::Ready:
332  Line += "R";
333  break;
334  case Thread::Sleeping:
335  Line += "S";
336  break;
337  case Thread::Zombie:
338  Line += "Z";
339  break;
340  case Thread::AwaitingJoin:
341  Line += "J";
342  break;
343  case Thread::Suspended:
344  Line += "s";
345  break;
346  }
347  Line += "[";
348  Line += "CPU";
349  Line += tehThread->getCpuId();
350  Line += ":";
351  Line += tehThread->getId();
352  Line += "] - CURRENT";
353 
354  uintptr_t ip = 0;
355  Thread::DebugState state = tehThread->getDebugState(ip);
356  if (state != Thread::None)
357  {
358  if (state == Thread::SemWait)
359  Line += "Sem-Wait @ ";
360  else if (state == Thread::Joining)
361  Line += "Joining @";
362  else if (state == Thread::CondWait)
363  Line += "Cond-Wait @";
364  else
365  Line += "<unknown DebugState> @";
366  Line.append(ip, 16);
367 
368  uintptr_t symStart;
369  const char *pSym =
370  KernelElf::instance().globalLookupSymbol(ip, &symStart);
371  if (pSym)
372  {
373  LargeStaticString sym;
374  demangle_full(LargeStaticString(pSym), sym);
375  Line += ": ";
376  Line += sym;
377  }
378  }
379 
380  colour = DebuggerIO::Yellow;
381  }
382 
383  if (index == m_SelectedLine)
384  bgColour = DebuggerIO::Blue;
385  else
386  bgColour = DebuggerIO::Black;
387  colOffset = 3;
388  return Line;
389 }
390 
391 size_t ThreadsCommand::getLineCount()
392 {
393  return m_nLines;
394 }
395 
396 bool ThreadsCommand::swapThread(InterruptState &state, DebuggerIO *pScreen)
397 {
398  // Work through our process list.
399  size_t idx = 0;
400  Process *tehProcess = 0;
401  Thread *tehThread = 0;
402  bool stop = false;
403  for (size_t i = 0; i < Scheduler::instance().getNumProcesses(); i++)
404  {
405  tehProcess = Scheduler::instance().getProcess(i);
406  if (m_SelectedLine == idx)
407  {
408  tehThread = 0;
409  break;
410  }
411  idx++;
412  for (size_t j = 0; j < tehProcess->getNumThreads(); j++)
413  {
414  if (m_SelectedLine == idx)
415  {
416  tehThread = tehProcess->getThread(j);
417  stop = true;
418  break;
419  }
420  idx++;
421  }
422  if (stop)
423  break;
424  }
425 
426  // We can only swap to threads, not entire processes!
427  if (tehThread == 0)
428  return false;
429 
430  pScreen->destroy();
431  // Scheduler::instance().switchToAndDebug(state, tehThread);
432 
433  return true;
434 }
435 
436 #endif
virtual size_t getWidth()=0
virtual void enableCli()=0
size_t getId()
Definition: Process.h:108
virtual char getChar()=0
static ProcessorInformation & information()
Definition: Processor.cc:45
static KernelElf & instance()
Definition: KernelElf.h:129
DebugState
Definition: Thread.h:73
Status
Definition: Thread.h:62
bool execute(const HugeStaticString &input, HugeStaticString &output, InterruptState &state, DebuggerIO *screen)
size_t getNumProcesses()
Definition: Scheduler.cc:140
uintptr_t globalLookupSymbol(const char *pName)
Definition: KernelElf.cc:1031
static Scheduler & instance()
Definition: Scheduler.h:48
Process * getProcess(size_t n)
Definition: Scheduler.cc:149
size_t getNumThreads()
Definition: Process.cc:219
virtual void drawString(const char *str, size_t row, size_t col, Colour foreColour, Colour backColour)=0
Thread * getThread(size_t n)
Definition: Process.cc:225
Status getStatus() const
Definition: Thread.h:192
Definition: Thread.h:54
LargeStaticString & description()
Definition: Process.h:114
size_t getId()
Definition: Thread.h:210
virtual void drawHorizontalLine(char c, size_t row, size_t colStart, size_t colEnd, Colour foreColour, Colour backColour)=0
size_t getCpuId()
Definition: Thread.h:378
void autocomplete(const HugeStaticString &input, HugeStaticString &output)
DebugState getDebugState(uintptr_t &address)
Definition: Thread.h:288