1 /* 2 ProcessController © 2000, Georges-Edouard Berenger, All Rights Reserved. 3 Copyright (C) 2004 beunited.org 4 Copyright (c) 2006-2013, Haiku, Inc. All rights reserved. 5 6 This library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 This library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with this library; if not, write to the Free Software 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 22 #include "ProcessController.h" 23 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <string.h> 27 28 #include <AboutWindow.h> 29 #include <Alert.h> 30 #include <Bitmap.h> 31 #include <Catalog.h> 32 #include <debugger.h> 33 #include <Deskbar.h> 34 #include <Directory.h> 35 #include <Dragger.h> 36 #include <File.h> 37 #include <FindDirectory.h> 38 #include <MessageRunner.h> 39 #include <Path.h> 40 #include <PopUpMenu.h> 41 #include <Roster.h> 42 #include <Screen.h> 43 #include <TextView.h> 44 45 #include <scheduler.h> 46 #include <syscalls.h> 47 48 #include "AutoIcon.h" 49 #include "Colors.h" 50 #include "IconMenuItem.h" 51 #include "MemoryBarMenu.h" 52 #include "MemoryBarMenuItem.h" 53 #include "PCWorld.h" 54 #include "Preferences.h" 55 #include "QuitMenu.h" 56 #include "TeamBarMenu.h" 57 #include "TeamBarMenuItem.h" 58 #include "ThreadBarMenu.h" 59 #include "Utilities.h" 60 61 62 #undef B_TRANSLATION_CONTEXT 63 #define B_TRANSLATION_CONTEXT "ProcessController" 64 65 66 const char* kDeskbarItemName = "ProcessController"; 67 const char* kClassName = "ProcessController"; 68 69 const char* kFrameColorPref = "deskbar_frame_color"; 70 const char* kIdleColorPref = "deskbar_idle_color"; 71 const char* kActiveColorPref = "deskbar_active_color"; 72 73 static const char* const kDebuggerSignature 74 = "application/x-vnd.Haiku-Debugger"; 75 76 const rgb_color kKernelBlue = {20, 20, 231, 255}; 77 const rgb_color kIdleGreen = {110, 190,110, 255}; 78 79 ProcessController* gPCView; 80 uint32 gCPUcount; 81 rgb_color gUserColor; 82 rgb_color gUserColorSelected; 83 rgb_color gIdleColor; 84 rgb_color gIdleColorSelected; 85 rgb_color gKernelColor; 86 rgb_color gKernelColorSelected; 87 rgb_color gFrameColor; 88 rgb_color gFrameColorSelected; 89 rgb_color gMenuBackColorSelected; 90 rgb_color gMenuBackColor; 91 rgb_color gWhiteSelected; 92 ThreadBarMenu* gCurrentThreadBarMenu; 93 bool gInDeskbar = false; 94 95 #define addtopbottom(x) if (top) popup->AddItem(x); else popup->AddItem(x, 0) 96 97 status_t thread_popup(void *arg); 98 99 int32 gPopupFlag = 0; 100 thread_id gPopupThreadID = 0; 101 102 typedef struct { 103 BPoint where; 104 BRect clickToOpenRect; 105 bool top; 106 } Tpopup_param; 107 108 #define DEBUG_THREADS 1 109 110 status_t thread_quit_application(void *arg); 111 status_t thread_debug_thread(void *arg); 112 113 typedef struct { 114 thread_id thread; 115 sem_id sem; 116 time_t totalTime; 117 } Tdebug_thead_param; 118 119 // Bar layout depending on number of CPUs 120 121 typedef struct { 122 float cpu_width; 123 float cpu_inter; 124 float mem_width; 125 } layoutT; 126 127 layoutT layout[] = { 128 { 1, 1, 1 }, 129 { 5, 1, 5 }, // 1 130 { 3, 1, 4 }, // 2 131 { 2, 1, 3 }, 132 { 2, 0, 3 }, // 4 133 { 1, 1, 1 }, 134 { 1, 1, 1 }, 135 { 1, 1, 1 }, 136 { 1, 0, 3 } // 8 137 }; 138 139 140 extern "C" _EXPORT BView *instantiate_deskbar_item(void); 141 142 extern "C" _EXPORT BView * 143 instantiate_deskbar_item(void) 144 { 145 gInDeskbar = true; 146 return new ProcessController(); 147 } 148 149 150 // #pragma mark - 151 152 153 ProcessController::ProcessController(BRect frame, bool temp) 154 : BView(frame, kDeskbarItemName, B_FOLLOW_TOP_BOTTOM, 155 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE), 156 fProcessControllerIcon(kSignature), 157 fProcessorIcon(k_cpu_mini), 158 fTrackerIcon(kTrackerSig), 159 fDeskbarIcon(kDeskbarSig), 160 fTerminalIcon(kTerminalSig), 161 kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), 162 fTemp(temp), 163 fLastBarHeight(new float[kCPUCount]), 164 fCPUTimes(new double[kCPUCount]), 165 fPrevActive(new bigtime_t[kCPUCount]) 166 { 167 if (!temp) { 168 Init(); 169 170 frame.OffsetTo(B_ORIGIN); 171 frame.top = frame.bottom - 7; 172 frame.left = frame.right - 7; 173 BDragger* dragger = new BDragger(frame, this, B_FOLLOW_BOTTOM); 174 AddChild(dragger); 175 } 176 } 177 178 ProcessController::ProcessController(BMessage *data) 179 : BView(data), 180 fProcessControllerIcon(kSignature), 181 fProcessorIcon(k_cpu_mini), 182 fTrackerIcon(kTrackerSig), 183 fDeskbarIcon(kDeskbarSig), 184 fTerminalIcon(kTerminalSig), 185 kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), 186 fTemp(false), 187 fLastBarHeight(new float[kCPUCount]), 188 fCPUTimes(new double[kCPUCount]), 189 fPrevActive(new bigtime_t[kCPUCount]) 190 { 191 Init(); 192 } 193 194 195 ProcessController::ProcessController() 196 : BView(BRect (0, 0, 15, 15), kDeskbarItemName, B_FOLLOW_NONE, B_WILL_DRAW), 197 fProcessControllerIcon(kSignature), 198 fProcessorIcon(k_cpu_mini), 199 fTrackerIcon(kTrackerSig), 200 fDeskbarIcon(kDeskbarSig), 201 fTerminalIcon(kTerminalSig), 202 kCPUCount(sysconf(_SC_NPROCESSORS_CONF)), 203 fTemp(false), 204 fLastBarHeight(new float[kCPUCount]), 205 fCPUTimes(new double[kCPUCount]), 206 fPrevActive(new bigtime_t[kCPUCount]) 207 { 208 Init(); 209 } 210 211 212 ProcessController::~ProcessController() 213 { 214 if (!fTemp) { 215 if (gPopupThreadID) { 216 status_t return_value; 217 wait_for_thread (gPopupThreadID, &return_value); 218 } 219 } 220 221 delete fMessageRunner; 222 gPCView = NULL; 223 224 delete[] fPrevActive; 225 delete[] fCPUTimes; 226 delete[] fLastBarHeight; 227 } 228 229 230 void 231 ProcessController::Init() 232 { 233 memset(fLastBarHeight, 0, sizeof(float) * kCPUCount); 234 memset(fCPUTimes, 0, sizeof(double) * kCPUCount); 235 memset(fPrevActive, 0, sizeof(bigtime_t) * kCPUCount); 236 237 gPCView = this; 238 fMessageRunner = NULL; 239 fLastMemoryHeight = 0; 240 fPrevTime = 0; 241 } 242 243 244 void 245 ProcessController::_HandleDebugRequest(team_id team, thread_id thread) 246 { 247 char *argv[2]; 248 char paramString[16]; 249 char idString[16]; 250 strlcpy(paramString, thread > 0 ? "--thread" : "--team", sizeof(paramString)); 251 snprintf(idString, sizeof(idString), "%" B_PRId32, thread > 0 ? thread : team); 252 argv[0] = paramString; 253 argv[1] = idString; 254 status_t error = be_roster->Launch(kDebuggerSignature, 2, argv); 255 if (error != B_OK) { 256 // TODO: notify user 257 } 258 } 259 260 261 ProcessController* 262 ProcessController::Instantiate(BMessage *data) 263 { 264 if (!validate_instantiation(data, kClassName)) 265 return NULL; 266 267 return new ProcessController(data); 268 } 269 270 271 status_t 272 ProcessController::Archive(BMessage *data, bool deep) const 273 { 274 BView::Archive(data, deep); 275 data->AddString("add_on", kSignature); 276 data->AddString("class", kClassName); 277 return B_OK; 278 } 279 280 281 void 282 ProcessController::MessageReceived(BMessage *message) 283 { 284 team_id team; 285 thread_id thread; 286 BAlert *alert; 287 char question[1000]; 288 switch (message->what) { 289 case 'Puls': 290 Update (); 291 DoDraw (false); 292 break; 293 294 case 'QtTm': 295 if (message->FindInt32("team", &team) == B_OK) { 296 resume_thread(spawn_thread(thread_quit_application, 297 B_TRANSLATE("Quit application"), B_NORMAL_PRIORITY, 298 (void*)(addr_t)team)); 299 } 300 break; 301 302 case 'KlTm': 303 if (message->FindInt32("team", &team) == B_OK) { 304 info_pack infos; 305 if (get_team_info(team, &infos.team_info) == B_OK) { 306 get_team_name_and_icon(infos); 307 snprintf(question, sizeof(question), 308 B_TRANSLATE("What do you want to do with the team \"%s\"?"), 309 infos.team_name); 310 alert = new BAlert(B_TRANSLATE("Please confirm"), question, 311 B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this team!"), 312 B_TRANSLATE("Kill this team!"), B_WIDTH_AS_USUAL, 313 B_STOP_ALERT); 314 alert->SetShortcut(0, B_ESCAPE); 315 int result = alert->Go(); 316 switch (result) { 317 case 1: 318 _HandleDebugRequest(team, -1); 319 break; 320 case 2: 321 kill_team(team); 322 break; 323 default: 324 break; 325 } 326 } else { 327 alert = new BAlert(B_TRANSLATE("Info"), 328 B_TRANSLATE("This team is already gone"B_UTF8_ELLIPSIS), 329 B_TRANSLATE("Ok!"), NULL, NULL, B_WIDTH_AS_USUAL, 330 B_STOP_ALERT); 331 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 332 alert->Go(); 333 } 334 } 335 break; 336 337 case 'KlTh': 338 if (message->FindInt32("thread", &thread) == B_OK) { 339 thread_info thinfo; 340 if (get_thread_info(thread, &thinfo) == B_OK) { 341 #if DEBUG_THREADS 342 snprintf(question, sizeof(question), 343 B_TRANSLATE("What do you want to do " 344 "with the thread \"%s\"?"), thinfo.name); 345 alert = new BAlert(B_TRANSLATE("Please confirm"), question, 346 B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this thread!"), 347 B_TRANSLATE("Kill this thread!"), B_WIDTH_AS_USUAL, 348 B_STOP_ALERT); 349 alert->SetShortcut(0, B_ESCAPE); 350 351 #define KILL 2 352 #else 353 snprintf(question, sizeof(question), 354 B_TRANSLATE("Are you sure you want " 355 "to kill the thread \"%s\"?"), thinfo.name); 356 alert = new BAlert(B_TRANSLATE("Please confirm"), question, 357 B_TRANSLATE("Cancel"), B_TRANSLATE("Kill this thread!"), 358 NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); 359 alert->SetShortcut(0, B_ESCAPE); 360 361 #define KILL 1 362 #endif 363 alert->SetShortcut(0, B_ESCAPE); 364 int r = alert->Go(); 365 if (r == KILL) 366 kill_thread(thread); 367 #if DEBUG_THREADS 368 else if (r == 1) 369 _HandleDebugRequest(thinfo.team, thinfo.thread); 370 #endif 371 } else { 372 alert = new BAlert(B_TRANSLATE("Info"), 373 B_TRANSLATE("This thread is already gone"B_UTF8_ELLIPSIS), 374 B_TRANSLATE("Ok!"), NULL, NULL, 375 B_WIDTH_AS_USUAL, B_STOP_ALERT); 376 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 377 alert->Go(); 378 } 379 } 380 break; 381 382 case 'PrTh': 383 if (message->FindInt32("thread", &thread) == B_OK) { 384 int32 new_priority; 385 if (message->FindInt32("priority", &new_priority) == B_OK) 386 set_thread_priority(thread, new_priority); 387 } 388 break; 389 390 case 'Trac': 391 { 392 BPath trackerPath; 393 if (find_directory(B_SYSTEM_DIRECTORY, &trackerPath) == B_OK 394 && trackerPath.Append("Tracker") == B_OK) { 395 launch(kTrackerSig, trackerPath.Path()); 396 } 397 break; 398 } 399 400 case 'Dbar': 401 { 402 BPath deskbarPath; 403 if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK 404 && deskbarPath.Append("Deskbar") == B_OK) { 405 launch(kDeskbarSig, deskbarPath.Path()); 406 } 407 break; 408 } 409 410 case 'Term': 411 { 412 BPath terminalPath; 413 if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath) == B_OK 414 && terminalPath.Append("Terminal") == B_OK) { 415 launch(kTerminalSig, terminalPath.Path()); 416 } 417 break; 418 } 419 420 case 'AlDb': 421 { 422 if (!be_roster->IsRunning(kDeskbarSig)) { 423 BPath deskbarPath; 424 if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK 425 && deskbarPath.Append("Deskbar") == B_OK) { 426 launch(kDeskbarSig, deskbarPath.Path()); 427 } 428 } 429 BDeskbar deskbar; 430 if (gInDeskbar || deskbar.HasItem (kDeskbarItemName)) 431 deskbar.RemoveItem (kDeskbarItemName); 432 else 433 move_to_deskbar(deskbar); 434 break; 435 } 436 437 case 'CPU ': 438 { 439 uint32 cpu; 440 if (message->FindInt32("cpu", (int32*)&cpu) == B_OK) { 441 bool last = true; 442 for (unsigned int p = 0; p < gCPUcount; p++) { 443 if (p != cpu && _kern_cpu_enabled(p)) { 444 last = false; 445 break; 446 } 447 } 448 if (last) { 449 alert = new BAlert(B_TRANSLATE("Info"), 450 B_TRANSLATE("This is the last active processor...\n" 451 "You can't turn it off!"), 452 B_TRANSLATE("That's no Fun!"), NULL, NULL, 453 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 454 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 455 alert->Go(); 456 } else 457 _kern_set_cpu_enabled(cpu, !_kern_cpu_enabled(cpu)); 458 } 459 break; 460 } 461 462 case 'Schd': 463 { 464 int32 mode; 465 if (message->FindInt32 ("mode", &mode) == B_OK) 466 set_scheduler_mode(mode); 467 break; 468 } 469 470 case B_ABOUT_REQUESTED: 471 AboutRequested(); 472 break; 473 474 default: 475 BView::MessageReceived(message); 476 } 477 } 478 479 480 void 481 ProcessController::AboutRequested() 482 { 483 BAboutWindow* window = new BAboutWindow( 484 B_TRANSLATE_SYSTEM_NAME("ProcessController"), kSignature); 485 486 const char* extraCopyrights[] = { 487 "2004 beunited.org", 488 "1997-2001 Georges-Edouard Berenger", 489 NULL 490 }; 491 492 const char* authors[] = { 493 "Georges-Edouard Berenger", 494 NULL 495 }; 496 497 window->AddCopyright(2007, "Haiku, Inc.", extraCopyrights); 498 window->AddAuthors(authors); 499 500 window->Show(); 501 } 502 503 504 void 505 ProcessController::DefaultColors() 506 { 507 swap_color.red = 203; 508 swap_color.green = 0; 509 swap_color.blue = 0; 510 swap_color.alpha = 255; 511 bool set = false; 512 513 if (!set) { 514 active_color = kKernelBlue; 515 active_color = tint_color (active_color, B_LIGHTEN_2_TINT); 516 idle_color = active_color; 517 idle_color.green /= 3; 518 idle_color.red /= 3; 519 idle_color.blue /= 3; 520 frame_color = kBlack; 521 mix_colors (memory_color, active_color, swap_color, 0.2); 522 } 523 } 524 525 526 void 527 ProcessController::AttachedToWindow() 528 { 529 BView::AttachedToWindow(); 530 if (Parent()) 531 SetViewColor(B_TRANSPARENT_COLOR); 532 else 533 SetViewColor(kBlack); 534 535 Preferences tPreferences(kPreferencesFileName, NULL, false); 536 DefaultColors(); 537 538 system_info info; 539 get_system_info(&info); 540 gCPUcount = info.cpu_count; 541 Update(); 542 543 gIdleColor = kIdleGreen; 544 gIdleColorSelected = tint_color(gIdleColor, B_HIGHLIGHT_BACKGROUND_TINT); 545 gKernelColor = kKernelBlue; 546 gKernelColorSelected = tint_color(gKernelColor, B_HIGHLIGHT_BACKGROUND_TINT); 547 gUserColor = tint_color(gKernelColor, B_LIGHTEN_2_TINT); 548 gUserColorSelected = tint_color(gUserColor, B_HIGHLIGHT_BACKGROUND_TINT); 549 gFrameColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 550 B_HIGHLIGHT_BACKGROUND_TINT); 551 gFrameColorSelected = tint_color(gFrameColor, B_HIGHLIGHT_BACKGROUND_TINT); 552 gMenuBackColor = ui_color(B_MENU_BACKGROUND_COLOR); 553 gMenuBackColorSelected = ui_color(B_MENU_SELECTION_BACKGROUND_COLOR); 554 gWhiteSelected = tint_color(kWhite, B_HIGHLIGHT_BACKGROUND_TINT); 555 556 BMessenger messenger(this); 557 BMessage message('Puls'); 558 fMessageRunner = new BMessageRunner(messenger, &message, 250000, -1); 559 } 560 561 562 563 void 564 ProcessController::MouseDown(BPoint where) 565 { 566 if (atomic_add(&gPopupFlag, 1) > 0) { 567 atomic_add(&gPopupFlag, -1); 568 return; 569 } 570 571 Tpopup_param* param = new Tpopup_param; 572 ConvertToScreen(&where); 573 param->where = where; 574 param->clickToOpenRect = Frame (); 575 ConvertToScreen (¶m->clickToOpenRect); 576 param->top = where.y < BScreen(this->Window()).Frame().bottom-50; 577 578 gPopupThreadID = spawn_thread(thread_popup, "Popup holder thread", 579 B_URGENT_DISPLAY_PRIORITY, param); 580 resume_thread(gPopupThreadID); 581 } 582 583 584 void 585 ProcessController::Draw(BRect) 586 { 587 SetDrawingMode(B_OP_COPY); 588 DoDraw(true); 589 } 590 591 592 void 593 ProcessController::DoDraw(bool force) 594 { 595 BRect bounds(Bounds()); 596 597 float h = floorf(bounds.Height ()) - 2; 598 float top = 1, left = 1; 599 float bottom = top + h; 600 float barWidth = layout[gCPUcount].cpu_width; 601 // interspace 602 float right = left + gCPUcount * (barWidth + layout[gCPUcount].cpu_inter) 603 - layout[gCPUcount].cpu_inter; // right of CPU frame... 604 if (force && Parent()) { 605 SetHighColor(Parent()->ViewColor()); 606 FillRect(BRect(right + 1, top - 1, right + 2, bottom + 1)); 607 } 608 609 if (force) { 610 SetHighColor(frame_color); 611 StrokeRect(BRect(left - 1, top - 1, right, bottom + 1)); 612 if (gCPUcount > 1 && layout[gCPUcount].cpu_inter == 1) { 613 for (unsigned int x = 1; x < gCPUcount; x++) 614 StrokeLine(BPoint(left + x * barWidth + x - 1, top), 615 BPoint(left + x * barWidth + x - 1, bottom)); 616 } 617 } 618 float leftMem = bounds.Width() - layout[gCPUcount].mem_width; 619 if (force) 620 StrokeRect(BRect(leftMem - 1, top - 1, 621 leftMem + layout[gCPUcount].mem_width, bottom + 1)); 622 623 for (unsigned int x = 0; x < gCPUcount; x++) { 624 right = left + barWidth - 1; 625 float rem = fCPUTimes[x] * (h + 1); 626 float barHeight = floorf (rem); 627 rem -= barHeight; 628 float limit = bottom - barHeight; // horizontal line 629 float previousLimit = bottom - fLastBarHeight[x]; 630 float idleTop = top; 631 632 if (!force && previousLimit > top) 633 idleTop = previousLimit - 1; 634 if (limit > idleTop) { 635 SetHighColor(idle_color); 636 FillRect(BRect(left, idleTop, right, limit - 1)); 637 } 638 if (barHeight <= h) { 639 rgb_color fraction_color; 640 mix_colors(fraction_color, idle_color, active_color, rem); 641 SetHighColor(fraction_color); 642 StrokeLine(BPoint(left, bottom - barHeight), BPoint(right, 643 bottom - barHeight)); 644 } 645 float active_bottom = bottom; 646 if (!force && previousLimit < bottom) 647 active_bottom = previousLimit + 1; 648 if (limit < active_bottom) { 649 SetHighColor(active_color); 650 FillRect(BRect(left, limit + 1, right, active_bottom)); 651 } 652 left += layout[gCPUcount].cpu_width + layout[gCPUcount].cpu_inter; 653 fLastBarHeight[x] = barHeight; 654 } 655 656 float rightMem = bounds.Width() - 1; 657 float rem = fMemoryUsage * (h + 1); 658 float barHeight = floorf(rem); 659 rem -= barHeight; 660 661 rgb_color used_memory_color; 662 float sq = fMemoryUsage * fMemoryUsage; 663 sq *= sq; 664 sq *= sq; 665 mix_colors(used_memory_color, memory_color, swap_color, sq); 666 667 float limit = bottom - barHeight; // horizontal line 668 float previousLimit = bottom - fLastMemoryHeight; 669 float free_top = top; 670 if (!force && previousLimit > top) 671 free_top = previousLimit - 1; 672 if (limit > free_top) { 673 SetHighColor (idle_color); 674 FillRect(BRect(leftMem, free_top, rightMem, limit - 1)); 675 } 676 if (barHeight <= h) { 677 rgb_color fraction_color; 678 mix_colors(fraction_color, idle_color, used_memory_color, rem); 679 SetHighColor(fraction_color); 680 StrokeLine(BPoint(leftMem, bottom - barHeight), BPoint(rightMem, 681 bottom - barHeight)); 682 } 683 float usedBottom = bottom; 684 // if (!force && previousLimit < bottom) 685 // usedBottom = previousLimit + 1; 686 if (limit < usedBottom) { 687 SetHighColor(used_memory_color); 688 FillRect(BRect(leftMem, limit + 1, rightMem, usedBottom)); 689 } 690 fLastMemoryHeight = barHeight; 691 } 692 693 694 void 695 ProcessController::Update() 696 { 697 system_info info; 698 get_system_info(&info); 699 bigtime_t now = system_time(); 700 701 cpu_info* cpuInfos = new cpu_info[gCPUcount]; 702 get_cpu_info(0, gCPUcount, cpuInfos); 703 704 fMemoryUsage = float(info.used_pages) / float(info.max_pages); 705 // Calculate work done since last call to Update() for each CPU 706 for (unsigned int x = 0; x < gCPUcount; x++) { 707 bigtime_t load = cpuInfos[x].active_time - fPrevActive[x]; 708 bigtime_t passed = now - fPrevTime; 709 float cpuTime = float(load) / float(passed); 710 711 fPrevActive[x] = cpuInfos[x].active_time; 712 if (load > passed) 713 fPrevActive[x] -= load - passed; // save overload for next period... 714 if (cpuTime < 0) 715 cpuTime = 0; 716 if (cpuTime > 1) 717 cpuTime = 1; 718 fCPUTimes[x] = cpuTime; 719 } 720 fPrevTime = now; 721 722 delete[] cpuInfos; 723 } 724 725 726 // #pragma mark - 727 728 729 status_t 730 thread_popup(void *arg) 731 { 732 Tpopup_param* param = (Tpopup_param*) arg; 733 int32 mcookie, hcookie; 734 unsigned long m; 735 long h; 736 BMenuItem* item; 737 bool top = param->top; 738 739 system_info systemInfo; 740 get_system_info(&systemInfo); 741 info_pack* infos = new info_pack[systemInfo.used_teams]; 742 // TODO: this doesn't necessarily get all teams 743 for (m = 0, mcookie = 0; m < systemInfo.used_teams; m++) { 744 infos[m].team_icon = NULL; 745 infos[m].team_name[0] = 0; 746 infos[m].thread_info = NULL; 747 if (get_next_team_info(&mcookie, &infos[m].team_info) == B_OK) { 748 infos[m].thread_info = new thread_info[infos[m].team_info.thread_count]; 749 for (h = 0, hcookie = 0; h < infos[m].team_info.thread_count; h++) { 750 if (get_next_thread_info(infos[m].team_info.team, &hcookie, 751 &infos[m].thread_info[h]) != B_OK) 752 infos[m].thread_info[h].thread = -1; 753 } 754 get_team_name_and_icon(infos[m], true); 755 } else { 756 systemInfo.used_teams = m; 757 infos[m].team_info.team = -1; 758 } 759 } 760 761 BPopUpMenu* popup = new BPopUpMenu("Global Popup", false, false); 762 popup->SetFont(be_plain_font); 763 764 // Quit section 765 BMenu* QuitPopup = new QuitMenu(B_TRANSLATE("Quit an application"), 766 infos, systemInfo.used_teams); 767 QuitPopup->SetFont(be_plain_font); 768 popup->AddItem(QuitPopup); 769 770 // Memory Usage section 771 MemoryBarMenu* MemoryPopup = new MemoryBarMenu(B_TRANSLATE("Memory usage"), 772 infos, systemInfo); 773 int64 committedMemory = (int64)systemInfo.used_pages * B_PAGE_SIZE / 1024; 774 for (m = 0; m < systemInfo.used_teams; m++) { 775 if (infos[m].team_info.team >= 0) { 776 MemoryBarMenuItem* memoryItem = 777 new MemoryBarMenuItem(infos[m].team_name, 778 infos[m].team_info.team, infos[m].team_icon, false, NULL); 779 MemoryPopup->AddItem(memoryItem); 780 memoryItem->UpdateSituation(committedMemory); 781 } 782 } 783 784 addtopbottom(MemoryPopup); 785 786 // CPU Load section 787 TeamBarMenu* CPUPopup = new TeamBarMenu(B_TRANSLATE("Threads and CPU " 788 "usage"), infos, systemInfo.used_teams); 789 for (m = 0; m < systemInfo.used_teams; m++) { 790 if (infos[m].team_info.team >= 0) { 791 ThreadBarMenu* TeamPopup = new ThreadBarMenu(infos[m].team_name, 792 infos[m].team_info.team, infos[m].team_info.thread_count); 793 BMessage* kill_team = new BMessage('KlTm'); 794 kill_team->AddInt32("team", infos[m].team_info.team); 795 TeamBarMenuItem* item = new TeamBarMenuItem(TeamPopup, kill_team, 796 infos[m].team_info.team, infos[m].team_icon, false); 797 item->SetTarget(gPCView); 798 CPUPopup->AddItem(item); 799 } 800 } 801 802 addtopbottom(CPUPopup); 803 addtopbottom(new BSeparatorItem()); 804 805 // CPU on/off section 806 if (gCPUcount > 1) { 807 for (unsigned int i = 0; i < gCPUcount; i++) { 808 char item_name[32]; 809 sprintf (item_name, B_TRANSLATE("Processor %d"), i + 1); 810 BMessage* m = new BMessage ('CPU '); 811 m->AddInt32 ("cpu", i); 812 item = new IconMenuItem (gPCView->fProcessorIcon, item_name, m); 813 if (_kern_cpu_enabled(i)) 814 item->SetMarked (true); 815 item->SetTarget(gPCView); 816 addtopbottom(item); 817 } 818 addtopbottom (new BSeparatorItem ()); 819 } 820 821 // Scheduler modes 822 static const char* schedulerModes[] = { B_TRANSLATE_MARK("Low Latency"), 823 B_TRANSLATE_MARK("Power Saving") }; 824 unsigned int modesCount = sizeof(schedulerModes) / sizeof(const char*); 825 int32 currentMode = get_scheduler_mode(); 826 for (unsigned int i = 0; i < modesCount; i++) { 827 BMessage* m = new BMessage('Schd'); 828 m->AddInt32("mode", i); 829 item = new BMenuItem(B_TRANSLATE(schedulerModes[i]), m); 830 if ((uint32)currentMode == i) 831 item->SetMarked(true); 832 item->SetTarget(gPCView); 833 addtopbottom(item); 834 } 835 addtopbottom(new BSeparatorItem()); 836 837 if (!be_roster->IsRunning(kTrackerSig)) { 838 item = new IconMenuItem(gPCView->fTrackerIcon, 839 B_TRANSLATE("Restart Tracker"), new BMessage('Trac')); 840 item->SetTarget(gPCView); 841 addtopbottom(item); 842 } 843 if (!be_roster->IsRunning(kDeskbarSig)) { 844 item = new IconMenuItem(gPCView->fDeskbarIcon, 845 B_TRANSLATE("Restart Deskbar"), new BMessage('Dbar')); 846 item->SetTarget(gPCView); 847 addtopbottom(item); 848 } 849 850 item = new IconMenuItem(gPCView->fTerminalIcon, 851 B_TRANSLATE("New Terminal"), new BMessage('Term')); 852 item->SetTarget(gPCView); 853 addtopbottom(item); 854 855 addtopbottom(new BSeparatorItem()); 856 857 bool showLiveInDeskbarItem = gInDeskbar; 858 if (!showLiveInDeskbarItem) { 859 int32 cookie = 0; 860 image_info info; 861 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { 862 if (info.type == B_APP_IMAGE) { 863 // only show the Live in Deskbar item if a) we're running in 864 // deskbar itself, or b) we're running in PC's team. 865 if (strstr(info.name, "ProcessController") != NULL) { 866 showLiveInDeskbarItem = true; 867 break; 868 } 869 } 870 } 871 } 872 873 if (showLiveInDeskbarItem && be_roster->IsRunning(kDeskbarSig)) { 874 item = new BMenuItem(B_TRANSLATE("Live in the Deskbar"), 875 new BMessage('AlDb')); 876 BDeskbar deskbar; 877 item->SetMarked(gInDeskbar || deskbar.HasItem(kDeskbarItemName)); 878 item->SetTarget(gPCView); 879 addtopbottom(item); 880 addtopbottom(new BSeparatorItem ()); 881 } 882 883 884 item = new IconMenuItem(gPCView->fProcessControllerIcon, 885 B_TRANSLATE("About ProcessController"B_UTF8_ELLIPSIS), 886 new BMessage(B_ABOUT_REQUESTED)); 887 item->SetTarget(gPCView); 888 addtopbottom(item); 889 890 param->where.x -= 5; 891 param->where.y -= 8; 892 popup->Go(param->where, true, true, param->clickToOpenRect); 893 894 delete popup; 895 for (m = 0; m < systemInfo.used_teams; m++) { 896 if (infos[m].team_info.team >= 0) { 897 delete[] infos[m].thread_info; 898 delete infos[m].team_icon; 899 } 900 } 901 delete[] infos; 902 delete param; 903 atomic_add (&gPopupFlag, -1); 904 gPopupThreadID = 0; 905 906 return B_OK; 907 } 908 909 910 status_t 911 thread_quit_application(void *arg) 912 { 913 BMessenger messenger(NULL, (addr_t)arg); 914 messenger.SendMessage(B_QUIT_REQUESTED); 915 return B_OK; 916 } 917 918 919 status_t 920 thread_debug_thread(void *arg) 921 { 922 Tdebug_thead_param* param = (Tdebug_thead_param*) arg; 923 #ifdef __HAIKU__ 924 debug_thread(param->thread); 925 #else // !__HAIKU__ 926 thread_info thinfo; 927 get_thread_info(param->thread, &thinfo); 928 char text[4096]; 929 sprintf(text, "db %d", int(param->thread)); 930 system(text); 931 if (param->sem >= 0 && thinfo.state == B_THREAD_WAITING && param->sem 932 == thinfo.sem) { 933 snooze(1000000); 934 get_thread_info(param->thread, &thinfo); 935 if (thinfo.state == B_THREAD_WAITING 936 && param->sem == thinfo.sem 937 && param->totalTime == thinfo.user_time + thinfo.kernel_time) { 938 // the thread has been waiting for this semaphore since the before 939 // the alert, not doing anything... Let's push it out of there! 940 sem_info sinfo; 941 thread_info thinfo; 942 info_pack infos; 943 944 if (get_sem_info(param->sem, &sinfo) == B_OK 945 && get_thread_info(param->thread, &thinfo) == B_OK 946 && get_team_info(thinfo.team, &infos.team_info) == B_OK) { 947 sprintf (text, "This thread is waiting for the " 948 "semaphore called \"%s\". As long as it waits for this " 949 "semaphore, you won't be able to debug that thread.\n", 950 sinfo.name); 951 if (sinfo.team == thinfo.team) 952 strcat(text, "This semaphore belongs to the " 953 "thread's team.\n\nShould I release this semaphore?\n"); 954 else { 955 get_team_name_and_icon(infos); 956 char moreText[1024]; 957 sprintf(moreText, "\nWARNING! This semaphore " 958 "belongs to the team \"%s\"!\n\nShould I release this " 959 "semaphore anyway?\n", 960 infos.team_name); 961 strcat(text, moreText); 962 } 963 964 BAlert* alert = new BAlert("", text, "Cancel", "Release", 965 NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); 966 alert->SetShortcut(0, B_ESCAPE); 967 if (alert->Go()) { 968 get_thread_info (param->thread, &thinfo); 969 if (thinfo.state == B_THREAD_WAITING && param->sem 970 == thinfo.sem 971 && param->totalTime == thinfo.user_time 972 + thinfo.kernel_time) 973 release_sem(param->sem); 974 else { 975 alert = new BAlert("", "The semaphore wasn't released, " 976 "because it wasn't necessary anymore!", 977 "OK", NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 978 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 979 alert->Go(); 980 } 981 } 982 } 983 } 984 } 985 #endif // !__HAIKU__ 986 delete param; 987 return B_OK; 988 } 989