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 memset(fLastBarHeight, 0, sizeof(fLastBarHeight)); 240 fLastMemoryHeight = 0; 241 memset(fCPUTimes, 0, sizeof(fCPUTimes)); 242 memset(fPrevActive, 0, sizeof(fPrevActive)); 243 fPrevTime = 0; 244 } 245 246 247 void 248 ProcessController::_HandleDebugRequest(team_id team, thread_id thread) 249 { 250 char *argv[2]; 251 char paramString[16]; 252 char idString[16]; 253 strlcpy(paramString, thread > 0 ? "--thread" : "--team", sizeof(paramString)); 254 snprintf(idString, sizeof(idString), "%" B_PRId32, thread > 0 ? thread : team); 255 argv[0] = paramString; 256 argv[1] = idString; 257 status_t error = be_roster->Launch(kDebuggerSignature, 2, argv); 258 if (error != B_OK) { 259 // TODO: notify user 260 } 261 } 262 263 264 ProcessController* 265 ProcessController::Instantiate(BMessage *data) 266 { 267 if (!validate_instantiation(data, kClassName)) 268 return NULL; 269 270 return new ProcessController(data); 271 } 272 273 274 status_t 275 ProcessController::Archive(BMessage *data, bool deep) const 276 { 277 BView::Archive(data, deep); 278 data->AddString("add_on", kSignature); 279 data->AddString("class", kClassName); 280 return B_OK; 281 } 282 283 284 void 285 ProcessController::MessageReceived(BMessage *message) 286 { 287 team_id team; 288 thread_id thread; 289 BAlert *alert; 290 char question[1000]; 291 switch (message->what) { 292 case 'Puls': 293 Update (); 294 DoDraw (false); 295 break; 296 297 case 'QtTm': 298 if (message->FindInt32("team", &team) == B_OK) { 299 resume_thread(spawn_thread(thread_quit_application, 300 B_TRANSLATE("Quit application"), B_NORMAL_PRIORITY, 301 (void*)(addr_t)team)); 302 } 303 break; 304 305 case 'KlTm': 306 if (message->FindInt32("team", &team) == B_OK) { 307 info_pack infos; 308 if (get_team_info(team, &infos.team_info) == B_OK) { 309 get_team_name_and_icon(infos); 310 snprintf(question, sizeof(question), 311 B_TRANSLATE("What do you want to do with the team \"%s\"?"), 312 infos.team_name); 313 alert = new BAlert(B_TRANSLATE("Please confirm"), question, 314 B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this team!"), 315 B_TRANSLATE("Kill this team!"), B_WIDTH_AS_USUAL, 316 B_STOP_ALERT); 317 alert->SetShortcut(0, B_ESCAPE); 318 int result = alert->Go(); 319 switch (result) { 320 case 1: 321 _HandleDebugRequest(team, -1); 322 break; 323 case 2: 324 kill_team(team); 325 break; 326 default: 327 break; 328 } 329 } else { 330 alert = new BAlert(B_TRANSLATE("Info"), 331 B_TRANSLATE("This team is already gone"B_UTF8_ELLIPSIS), 332 B_TRANSLATE("Ok!"), NULL, NULL, B_WIDTH_AS_USUAL, 333 B_STOP_ALERT); 334 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 335 alert->Go(); 336 } 337 } 338 break; 339 340 case 'KlTh': 341 if (message->FindInt32("thread", &thread) == B_OK) { 342 thread_info thinfo; 343 if (get_thread_info(thread, &thinfo) == B_OK) { 344 #if DEBUG_THREADS 345 snprintf(question, sizeof(question), 346 B_TRANSLATE("What do you want to do " 347 "with the thread \"%s\"?"), thinfo.name); 348 alert = new BAlert(B_TRANSLATE("Please confirm"), question, 349 B_TRANSLATE("Cancel"), B_TRANSLATE("Debug this thread!"), 350 B_TRANSLATE("Kill this thread!"), B_WIDTH_AS_USUAL, 351 B_STOP_ALERT); 352 alert->SetShortcut(0, B_ESCAPE); 353 354 #define KILL 2 355 #else 356 snprintf(question, sizeof(question), 357 B_TRANSLATE("Are you sure you want " 358 "to kill the thread \"%s\"?"), thinfo.name); 359 alert = new BAlert(B_TRANSLATE("Please confirm"), question, 360 B_TRANSLATE("Cancel"), B_TRANSLATE("Kill this thread!"), 361 NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); 362 alert->SetShortcut(0, B_ESCAPE); 363 364 #define KILL 1 365 #endif 366 alert->SetShortcut(0, B_ESCAPE); 367 int r = alert->Go(); 368 if (r == KILL) 369 kill_thread(thread); 370 #if DEBUG_THREADS 371 else if (r == 1) 372 _HandleDebugRequest(thinfo.team, thinfo.thread); 373 #endif 374 } else { 375 alert = new BAlert(B_TRANSLATE("Info"), 376 B_TRANSLATE("This thread is already gone"B_UTF8_ELLIPSIS), 377 B_TRANSLATE("Ok!"), NULL, NULL, 378 B_WIDTH_AS_USUAL, B_STOP_ALERT); 379 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 380 alert->Go(); 381 } 382 } 383 break; 384 385 case 'PrTh': 386 if (message->FindInt32("thread", &thread) == B_OK) { 387 int32 new_priority; 388 if (message->FindInt32("priority", &new_priority) == B_OK) 389 set_thread_priority(thread, new_priority); 390 } 391 break; 392 393 case 'Trac': 394 { 395 BPath trackerPath; 396 if (find_directory(B_SYSTEM_DIRECTORY, &trackerPath) == B_OK 397 && trackerPath.Append("Tracker") == B_OK) { 398 launch(kTrackerSig, trackerPath.Path()); 399 } 400 break; 401 } 402 403 case 'Dbar': 404 { 405 BPath deskbarPath; 406 if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK 407 && deskbarPath.Append("Deskbar") == B_OK) { 408 launch(kDeskbarSig, deskbarPath.Path()); 409 } 410 break; 411 } 412 413 case 'Term': 414 { 415 BPath terminalPath; 416 if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath) == B_OK 417 && terminalPath.Append("Terminal") == B_OK) { 418 launch(kTerminalSig, terminalPath.Path()); 419 } 420 break; 421 } 422 423 case 'AlDb': 424 { 425 if (!be_roster->IsRunning(kDeskbarSig)) { 426 BPath deskbarPath; 427 if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK 428 && deskbarPath.Append("Deskbar") == B_OK) { 429 launch(kDeskbarSig, deskbarPath.Path()); 430 } 431 } 432 BDeskbar deskbar; 433 if (gInDeskbar || deskbar.HasItem (kDeskbarItemName)) 434 deskbar.RemoveItem (kDeskbarItemName); 435 else 436 move_to_deskbar(deskbar); 437 break; 438 } 439 440 case 'CPU ': 441 { 442 uint32 cpu; 443 if (message->FindInt32("cpu", (int32*)&cpu) == B_OK) { 444 bool last = true; 445 for (unsigned int p = 0; p < gCPUcount; p++) { 446 if (p != cpu && _kern_cpu_enabled(p)) { 447 last = false; 448 break; 449 } 450 } 451 if (last) { 452 alert = new BAlert(B_TRANSLATE("Info"), 453 B_TRANSLATE("This is the last active processor...\n" 454 "You can't turn it off!"), 455 B_TRANSLATE("That's no Fun!"), NULL, NULL, 456 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 457 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 458 alert->Go(); 459 } else 460 _kern_set_cpu_enabled(cpu, !_kern_cpu_enabled(cpu)); 461 } 462 break; 463 } 464 465 case 'Schd': 466 { 467 int32 mode; 468 if (message->FindInt32 ("mode", &mode) == B_OK) 469 set_scheduler_mode(mode); 470 break; 471 } 472 473 case B_ABOUT_REQUESTED: 474 AboutRequested(); 475 break; 476 477 default: 478 BView::MessageReceived(message); 479 } 480 } 481 482 483 void 484 ProcessController::AboutRequested() 485 { 486 BAboutWindow* window = new BAboutWindow( 487 B_TRANSLATE_SYSTEM_NAME("ProcessController"), kSignature); 488 489 const char* extraCopyrights[] = { 490 "2004 beunited.org", 491 "1997-2001 Georges-Edouard Berenger", 492 NULL 493 }; 494 495 const char* authors[] = { 496 "Georges-Edouard Berenger", 497 NULL 498 }; 499 500 window->AddCopyright(2007, "Haiku, Inc.", extraCopyrights); 501 window->AddAuthors(authors); 502 503 window->Show(); 504 } 505 506 507 void 508 ProcessController::DefaultColors() 509 { 510 swap_color.red = 203; 511 swap_color.green = 0; 512 swap_color.blue = 0; 513 swap_color.alpha = 255; 514 bool set = false; 515 516 if (!set) { 517 active_color = kKernelBlue; 518 active_color = tint_color (active_color, B_LIGHTEN_2_TINT); 519 idle_color = active_color; 520 idle_color.green /= 3; 521 idle_color.red /= 3; 522 idle_color.blue /= 3; 523 frame_color = kBlack; 524 mix_colors (memory_color, active_color, swap_color, 0.2); 525 } 526 } 527 528 529 void 530 ProcessController::AttachedToWindow() 531 { 532 BView::AttachedToWindow(); 533 if (Parent()) 534 SetViewColor(B_TRANSPARENT_COLOR); 535 else 536 SetViewColor(kBlack); 537 538 Preferences tPreferences(kPreferencesFileName, NULL, false); 539 DefaultColors(); 540 541 system_info info; 542 get_system_info(&info); 543 gCPUcount = info.cpu_count; 544 Update(); 545 546 gIdleColor = kIdleGreen; 547 gIdleColorSelected = tint_color(gIdleColor, B_HIGHLIGHT_BACKGROUND_TINT); 548 gKernelColor = kKernelBlue; 549 gKernelColorSelected = tint_color(gKernelColor, B_HIGHLIGHT_BACKGROUND_TINT); 550 gUserColor = tint_color(gKernelColor, B_LIGHTEN_2_TINT); 551 gUserColorSelected = tint_color(gUserColor, B_HIGHLIGHT_BACKGROUND_TINT); 552 gFrameColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), 553 B_HIGHLIGHT_BACKGROUND_TINT); 554 gFrameColorSelected = tint_color(gFrameColor, B_HIGHLIGHT_BACKGROUND_TINT); 555 gMenuBackColor = ui_color(B_MENU_BACKGROUND_COLOR); 556 gMenuBackColorSelected = ui_color(B_MENU_SELECTION_BACKGROUND_COLOR); 557 gWhiteSelected = tint_color(kWhite, B_HIGHLIGHT_BACKGROUND_TINT); 558 559 BMessenger messenger(this); 560 BMessage message('Puls'); 561 fMessageRunner = new BMessageRunner(messenger, &message, 250000, -1); 562 } 563 564 565 566 void 567 ProcessController::MouseDown(BPoint where) 568 { 569 if (atomic_add(&gPopupFlag, 1) > 0) { 570 atomic_add(&gPopupFlag, -1); 571 return; 572 } 573 574 Tpopup_param* param = new Tpopup_param; 575 ConvertToScreen(&where); 576 param->where = where; 577 param->clickToOpenRect = Frame (); 578 ConvertToScreen (¶m->clickToOpenRect); 579 param->top = where.y < BScreen(this->Window()).Frame().bottom-50; 580 581 gPopupThreadID = spawn_thread(thread_popup, "Popup holder thread", 582 B_URGENT_DISPLAY_PRIORITY, param); 583 resume_thread(gPopupThreadID); 584 } 585 586 587 void 588 ProcessController::Draw(BRect) 589 { 590 SetDrawingMode(B_OP_COPY); 591 DoDraw(true); 592 } 593 594 595 void 596 ProcessController::DoDraw(bool force) 597 { 598 BRect bounds(Bounds()); 599 600 float h = floorf(bounds.Height ()) - 2; 601 float top = 1, left = 1; 602 float bottom = top + h; 603 float barWidth = layout[gCPUcount].cpu_width; 604 // interspace 605 float right = left + gCPUcount * (barWidth + layout[gCPUcount].cpu_inter) 606 - layout[gCPUcount].cpu_inter; // right of CPU frame... 607 if (force && Parent()) { 608 SetHighColor(Parent()->ViewColor()); 609 FillRect(BRect(right + 1, top - 1, right + 2, bottom + 1)); 610 } 611 612 if (force) { 613 SetHighColor(frame_color); 614 StrokeRect(BRect(left - 1, top - 1, right, bottom + 1)); 615 if (gCPUcount > 1 && layout[gCPUcount].cpu_inter == 1) { 616 for (unsigned int x = 1; x < gCPUcount; x++) 617 StrokeLine(BPoint(left + x * barWidth + x - 1, top), 618 BPoint(left + x * barWidth + x - 1, bottom)); 619 } 620 } 621 float leftMem = bounds.Width() - layout[gCPUcount].mem_width; 622 if (force) 623 StrokeRect(BRect(leftMem - 1, top - 1, 624 leftMem + layout[gCPUcount].mem_width, bottom + 1)); 625 626 for (unsigned int x = 0; x < gCPUcount; x++) { 627 right = left + barWidth - 1; 628 float rem = fCPUTimes[x] * (h + 1); 629 float barHeight = floorf (rem); 630 rem -= barHeight; 631 float limit = bottom - barHeight; // horizontal line 632 float previousLimit = bottom - fLastBarHeight[x]; 633 float idleTop = top; 634 635 if (!force && previousLimit > top) 636 idleTop = previousLimit - 1; 637 if (limit > idleTop) { 638 SetHighColor(idle_color); 639 FillRect(BRect(left, idleTop, right, limit - 1)); 640 } 641 if (barHeight <= h) { 642 rgb_color fraction_color; 643 mix_colors(fraction_color, idle_color, active_color, rem); 644 SetHighColor(fraction_color); 645 StrokeLine(BPoint(left, bottom - barHeight), BPoint(right, 646 bottom - barHeight)); 647 } 648 float active_bottom = bottom; 649 if (!force && previousLimit < bottom) 650 active_bottom = previousLimit + 1; 651 if (limit < active_bottom) { 652 SetHighColor(active_color); 653 FillRect(BRect(left, limit + 1, right, active_bottom)); 654 } 655 left += layout[gCPUcount].cpu_width + layout[gCPUcount].cpu_inter; 656 fLastBarHeight[x] = barHeight; 657 } 658 659 float rightMem = bounds.Width() - 1; 660 float rem = fMemoryUsage * (h + 1); 661 float barHeight = floorf(rem); 662 rem -= barHeight; 663 664 rgb_color used_memory_color; 665 float sq = fMemoryUsage * fMemoryUsage; 666 sq *= sq; 667 sq *= sq; 668 mix_colors(used_memory_color, memory_color, swap_color, sq); 669 670 float limit = bottom - barHeight; // horizontal line 671 float previousLimit = bottom - fLastMemoryHeight; 672 float free_top = top; 673 if (!force && previousLimit > top) 674 free_top = previousLimit - 1; 675 if (limit > free_top) { 676 SetHighColor (idle_color); 677 FillRect(BRect(leftMem, free_top, rightMem, limit - 1)); 678 } 679 if (barHeight <= h) { 680 rgb_color fraction_color; 681 mix_colors(fraction_color, idle_color, used_memory_color, rem); 682 SetHighColor(fraction_color); 683 StrokeLine(BPoint(leftMem, bottom - barHeight), BPoint(rightMem, 684 bottom - barHeight)); 685 } 686 float usedBottom = bottom; 687 // if (!force && previousLimit < bottom) 688 // usedBottom = previousLimit + 1; 689 if (limit < usedBottom) { 690 SetHighColor(used_memory_color); 691 FillRect(BRect(leftMem, limit + 1, rightMem, usedBottom)); 692 } 693 fLastMemoryHeight = barHeight; 694 } 695 696 697 void 698 ProcessController::Update() 699 { 700 system_info info; 701 get_system_info(&info); 702 bigtime_t now = system_time(); 703 704 cpu_info* cpuInfos = new cpu_info[gCPUcount]; 705 get_cpu_info(0, gCPUcount, cpuInfos); 706 707 fMemoryUsage = float(info.used_pages) / float(info.max_pages); 708 // Calculate work done since last call to Update() for each CPU 709 for (unsigned int x = 0; x < gCPUcount; x++) { 710 bigtime_t load = cpuInfos[x].active_time - fPrevActive[x]; 711 bigtime_t passed = now - fPrevTime; 712 float cpuTime = float(load) / float(passed); 713 714 fPrevActive[x] = cpuInfos[x].active_time; 715 if (load > passed) 716 fPrevActive[x] -= load - passed; // save overload for next period... 717 if (cpuTime < 0) 718 cpuTime = 0; 719 if (cpuTime > 1) 720 cpuTime = 1; 721 fCPUTimes[x] = cpuTime; 722 } 723 fPrevTime = now; 724 725 delete[] cpuInfos; 726 } 727 728 729 // #pragma mark - 730 731 732 status_t 733 thread_popup(void *arg) 734 { 735 Tpopup_param* param = (Tpopup_param*) arg; 736 int32 mcookie, hcookie; 737 unsigned long m; 738 long h; 739 BMenuItem* item; 740 bool top = param->top; 741 742 system_info systemInfo; 743 get_system_info(&systemInfo); 744 info_pack* infos = new info_pack[systemInfo.used_teams]; 745 // TODO: this doesn't necessarily get all teams 746 for (m = 0, mcookie = 0; m < systemInfo.used_teams; m++) { 747 infos[m].team_icon = NULL; 748 infos[m].team_name[0] = 0; 749 infos[m].thread_info = NULL; 750 if (get_next_team_info(&mcookie, &infos[m].team_info) == B_OK) { 751 infos[m].thread_info = new thread_info[infos[m].team_info.thread_count]; 752 for (h = 0, hcookie = 0; h < infos[m].team_info.thread_count; h++) { 753 if (get_next_thread_info(infos[m].team_info.team, &hcookie, 754 &infos[m].thread_info[h]) != B_OK) 755 infos[m].thread_info[h].thread = -1; 756 } 757 get_team_name_and_icon(infos[m], true); 758 } else { 759 systemInfo.used_teams = m; 760 infos[m].team_info.team = -1; 761 } 762 } 763 764 BPopUpMenu* popup = new BPopUpMenu("Global Popup", false, false); 765 popup->SetFont(be_plain_font); 766 767 // Quit section 768 BMenu* QuitPopup = new QuitMenu(B_TRANSLATE("Quit an application"), 769 infos, systemInfo.used_teams); 770 QuitPopup->SetFont(be_plain_font); 771 popup->AddItem(QuitPopup); 772 773 // Memory Usage section 774 MemoryBarMenu* MemoryPopup = new MemoryBarMenu(B_TRANSLATE("Memory usage"), 775 infos, systemInfo); 776 int64 committedMemory = (int64)systemInfo.used_pages * B_PAGE_SIZE / 1024; 777 for (m = 0; m < systemInfo.used_teams; m++) { 778 if (infos[m].team_info.team >= 0) { 779 MemoryBarMenuItem* memoryItem = 780 new MemoryBarMenuItem(infos[m].team_name, 781 infos[m].team_info.team, infos[m].team_icon, false, NULL); 782 MemoryPopup->AddItem(memoryItem); 783 memoryItem->UpdateSituation(committedMemory); 784 } 785 } 786 787 addtopbottom(MemoryPopup); 788 789 // CPU Load section 790 TeamBarMenu* CPUPopup = new TeamBarMenu(B_TRANSLATE("Threads and CPU " 791 "usage"), infos, systemInfo.used_teams); 792 for (m = 0; m < systemInfo.used_teams; m++) { 793 if (infos[m].team_info.team >= 0) { 794 ThreadBarMenu* TeamPopup = new ThreadBarMenu(infos[m].team_name, 795 infos[m].team_info.team, infos[m].team_info.thread_count); 796 BMessage* kill_team = new BMessage('KlTm'); 797 kill_team->AddInt32("team", infos[m].team_info.team); 798 TeamBarMenuItem* item = new TeamBarMenuItem(TeamPopup, kill_team, 799 infos[m].team_info.team, infos[m].team_icon, false); 800 item->SetTarget(gPCView); 801 CPUPopup->AddItem(item); 802 } 803 } 804 805 addtopbottom(CPUPopup); 806 addtopbottom(new BSeparatorItem()); 807 808 // CPU on/off section 809 if (gCPUcount > 1) { 810 for (unsigned int i = 0; i < gCPUcount; i++) { 811 char item_name[32]; 812 sprintf (item_name, B_TRANSLATE("Processor %d"), i + 1); 813 BMessage* m = new BMessage ('CPU '); 814 m->AddInt32 ("cpu", i); 815 item = new IconMenuItem (gPCView->fProcessorIcon, item_name, m); 816 if (_kern_cpu_enabled(i)) 817 item->SetMarked (true); 818 item->SetTarget(gPCView); 819 addtopbottom(item); 820 } 821 addtopbottom (new BSeparatorItem ()); 822 } 823 824 // Scheduler modes 825 static const char* schedulerModes[] = { "Low Latency", "Power Saving" }; 826 unsigned int modesCount = sizeof(schedulerModes) / sizeof(const char*); 827 int32 currentMode = get_scheduler_mode(); 828 for (unsigned int i = 0; i < modesCount; i++) { 829 BMessage* m = new BMessage('Schd'); 830 m->AddInt32("mode", i); 831 item = new BMenuItem(B_TRANSLATE(schedulerModes[i]), m); 832 if ((uint32)currentMode == i) 833 item->SetMarked(true); 834 item->SetTarget(gPCView); 835 addtopbottom(item); 836 } 837 addtopbottom(new BSeparatorItem()); 838 839 if (!be_roster->IsRunning(kTrackerSig)) { 840 item = new IconMenuItem(gPCView->fTrackerIcon, 841 B_TRANSLATE("Restart Tracker"), new BMessage('Trac')); 842 item->SetTarget(gPCView); 843 addtopbottom(item); 844 } 845 if (!be_roster->IsRunning(kDeskbarSig)) { 846 item = new IconMenuItem(gPCView->fDeskbarIcon, 847 B_TRANSLATE("Restart Deskbar"), new BMessage('Dbar')); 848 item->SetTarget(gPCView); 849 addtopbottom(item); 850 } 851 852 item = new IconMenuItem(gPCView->fTerminalIcon, 853 B_TRANSLATE("New Terminal"), new BMessage('Term')); 854 item->SetTarget(gPCView); 855 addtopbottom(item); 856 857 addtopbottom(new BSeparatorItem()); 858 859 bool showLiveInDeskbarItem = gInDeskbar; 860 if (!showLiveInDeskbarItem) { 861 int32 cookie = 0; 862 image_info info; 863 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { 864 if (info.type == B_APP_IMAGE) { 865 // only show the Live in Deskbar item if a) we're running in 866 // deskbar itself, or b) we're running in PC's team. 867 if (strstr(info.name, "ProcessController") != NULL) { 868 showLiveInDeskbarItem = true; 869 break; 870 } 871 } 872 } 873 } 874 875 if (showLiveInDeskbarItem && be_roster->IsRunning(kDeskbarSig)) { 876 item = new BMenuItem(B_TRANSLATE("Live in the Deskbar"), 877 new BMessage('AlDb')); 878 BDeskbar deskbar; 879 item->SetMarked(gInDeskbar || deskbar.HasItem(kDeskbarItemName)); 880 item->SetTarget(gPCView); 881 addtopbottom(item); 882 addtopbottom(new BSeparatorItem ()); 883 } 884 885 886 item = new IconMenuItem(gPCView->fProcessControllerIcon, 887 B_TRANSLATE("About ProcessController"B_UTF8_ELLIPSIS), 888 new BMessage(B_ABOUT_REQUESTED)); 889 item->SetTarget(gPCView); 890 addtopbottom(item); 891 892 param->where.x -= 5; 893 param->where.y -= 8; 894 popup->Go(param->where, true, true, param->clickToOpenRect); 895 896 delete popup; 897 for (m = 0; m < systemInfo.used_teams; m++) { 898 if (infos[m].team_info.team >= 0) { 899 delete[] infos[m].thread_info; 900 delete infos[m].team_icon; 901 } 902 } 903 delete[] infos; 904 delete param; 905 atomic_add (&gPopupFlag, -1); 906 gPopupThreadID = 0; 907 908 return B_OK; 909 } 910 911 912 status_t 913 thread_quit_application(void *arg) 914 { 915 BMessenger messenger(NULL, (addr_t)arg); 916 messenger.SendMessage(B_QUIT_REQUESTED); 917 return B_OK; 918 } 919 920 921 status_t 922 thread_debug_thread(void *arg) 923 { 924 Tdebug_thead_param* param = (Tdebug_thead_param*) arg; 925 #ifdef __HAIKU__ 926 debug_thread(param->thread); 927 #else // !__HAIKU__ 928 thread_info thinfo; 929 get_thread_info(param->thread, &thinfo); 930 char text[4096]; 931 sprintf(text, "db %d", int(param->thread)); 932 system(text); 933 if (param->sem >= 0 && thinfo.state == B_THREAD_WAITING && param->sem 934 == thinfo.sem) { 935 snooze(1000000); 936 get_thread_info(param->thread, &thinfo); 937 if (thinfo.state == B_THREAD_WAITING 938 && param->sem == thinfo.sem 939 && param->totalTime == thinfo.user_time + thinfo.kernel_time) { 940 // the thread has been waiting for this semaphore since the before 941 // the alert, not doing anything... Let's push it out of there! 942 sem_info sinfo; 943 thread_info thinfo; 944 info_pack infos; 945 946 if (get_sem_info(param->sem, &sinfo) == B_OK 947 && get_thread_info(param->thread, &thinfo) == B_OK 948 && get_team_info(thinfo.team, &infos.team_info) == B_OK) { 949 sprintf (text, "This thread is waiting for the " 950 "semaphore called \"%s\". As long as it waits for this " 951 "semaphore, you won't be able to debug that thread.\n", 952 sinfo.name); 953 if (sinfo.team == thinfo.team) 954 strcat(text, "This semaphore belongs to the " 955 "thread's team.\n\nShould I release this semaphore?\n"); 956 else { 957 get_team_name_and_icon(infos); 958 char moreText[1024]; 959 sprintf(moreText, "\nWARNING! This semaphore " 960 "belongs to the team \"%s\"!\n\nShould I release this " 961 "semaphore anyway?\n", 962 infos.team_name); 963 strcat(text, moreText); 964 } 965 966 BAlert* alert = new BAlert("", text, "Cancel", "Release", 967 NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); 968 alert->SetShortcut(0, B_ESCAPE); 969 if (alert->Go()) { 970 get_thread_info (param->thread, &thinfo); 971 if (thinfo.state == B_THREAD_WAITING && param->sem 972 == thinfo.sem 973 && param->totalTime == thinfo.user_time 974 + thinfo.kernel_time) 975 release_sem(param->sem); 976 else { 977 alert = new BAlert("", "The semaphore wasn't released, " 978 "because it wasn't necessary anymore!", 979 "OK", NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 980 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 981 alert->Go(); 982 } 983 } 984 } 985 } 986 } 987 #endif // !__HAIKU__ 988 delete param; 989 return B_OK; 990 } 991