// Fill in the given PROCINFO (initially zero except for id) // with totals from that process and all its descendants. // Set PROCINFO.is_boinc_app for all of them. // void procinfo_app( PROCINFO& pi, vector<int>* other_pids, PROC_MAP& pm, char* graphics_exec_file ) { PROC_MAP::iterator i; for (i=pm.begin(); i!=pm.end(); i++) { PROCINFO& p = i->second; if (p.id == pi.id || (other_pids && in_vector(p.id, *other_pids)) ) { pi.kernel_time += p.kernel_time; pi.user_time += p.user_time; pi.swap_size += p.swap_size; pi.working_set_size += p.working_set_size; p.is_boinc_app = true; p.scanned = true; // look for child processes // add_child_totals(pi, pm, i); return; } if (graphics_exec_file && !strcmp(p.command, graphics_exec_file)) { p.is_boinc_app = true; } } }
// Scan the process table adding in CPU time and mem usage. // void add_child_totals(PROCINFO& pi, PROC_MAP& pm, PROC_MAP::iterator i) { PROCINFO parent = i->second; for (unsigned int j=0; j<parent.children.size(); j++) { int child_pid = parent.children[j]; PROC_MAP::iterator i2 = pm.find(child_pid); if (i2 == pm.end()) continue; PROCINFO& p = i2->second; if (p.scanned) { return; // cycle in graph - shouldn't happen } pi.kernel_time += p.kernel_time; pi.user_time += p.user_time; p.scanned = true; // only count process with most swap and memory if (p.swap_size > pi.swap_size) { pi.swap_size = p.swap_size; } if (p.working_set_size > pi.working_set_size) { pi.working_set_size = p.working_set_size; } p.is_boinc_app = true; add_child_totals(pi, pm, i2); // recursion - woo hoo! } }
void find_children(PROC_MAP& pm) { PROC_MAP::iterator i; for (i=pm.begin(); i!=pm.end(); i++) { int parentid = i->second.parentid; PROC_MAP::iterator j = pm.find(parentid); if (j == pm.end()) continue; // should never happen j->second.children.push_back(i->first); } }
static void get_descendants_aux(PROC_MAP& pm, int pid, vector<int>& pids) { PROC_MAP::iterator i = pm.find(pid); if (i == pm.end()) return; for (unsigned int j=0; j<i->second.children.size(); j++) { int child_pid = i->second.children[j]; pids.push_back(child_pid); get_descendants_aux(pm, child_pid, pids); } }
bool app_running(PROC_MAP& pm, const char* p) { PROC_MAP::iterator i; for (i=pm.begin(); i!=pm.end(); ++i) { PROCINFO& pi = i->second; //msg_printf(0, MSG_INFO, "running: [%s]", pi.command); if (!strcasecmp(pi.command, p)) { return true; } } return false; }
static void get_descendants_aux(PROC_MAP& pm, int pid, vector<int>& pids) { PROC_MAP::iterator i = pm.find(pid); if (i == pm.end()) return; PROCINFO& p = i->second; if (p.scanned) return; // avoid infinite recursion p.scanned = true; for (unsigned int j=0; j<p.children.size(); j++) { int child_pid = p.children[j]; pids.push_back(child_pid); get_descendants_aux(pm, child_pid, pids); } }
void procinfo_show(PROCINFO& pi, PROC_MAP& pm) { unsigned int i; memset(&pi, 0, sizeof(pi)); PROC_MAP::iterator i; for (i=pm.begin(); i!=pm.end(); i++) { PROCINFO& p = i->second; pi.kernel_time += p.kernel_time; pi.user_time += p.user_time; msg_printf(NULL, MSG_INFO, "%d %s: boinc %d low %d (%f %f) total (%f %f)", p.id, p.command, p.is_boinc_app, p.is_low_priority, p.kernel_time, p.user_time, pi.kernel_time, pi.user_time ); } }
// get resource usage of non-BOINC apps // void procinfo_non_boinc(PROCINFO& pi, PROC_MAP& pm) { pi.clear(); PROC_MAP::iterator i; for (i=pm.begin(); i!=pm.end(); i++) { PROCINFO& p = i->second; #ifdef _WIN32 if (p.id == 0) continue; // idle process #endif if (p.is_boinc_app) continue; if (p.is_low_priority) continue; pi.kernel_time += p.kernel_time; pi.user_time += p.user_time; pi.swap_size += p.swap_size; pi.working_set_size += p.working_set_size; } }
/// /// Determines if another instance of BOINC Manager is running. /// /// @return /// true if another instance of BOINC Manager is running, otherwise false. /// /// Note: will always return false on Win95, Win98, WinME /// int CBOINCGUIApp::IsAnotherInstanceRunning() { PROC_MAP pm; int retval; char myName[256]; int otherInstanceID = 0; int myPid; // Look for BOINC Manager in list of all running processes retval = procinfo_setup(pm); if (retval) return false; // Should never happen #ifdef _WIN32 myPid = (int)GetCurrentProcessId(); #else myPid = getpid(); #endif // Get the name of this Application myName[0] = 0; PROC_MAP::iterator i; for (i=pm.begin(); i!=pm.end(); i++) { PROCINFO& procinfo = i->second; if (procinfo.id == myPid) { strncpy(myName, procinfo.command, sizeof(myName)); break; } } if (myName[0] == 0) { return false; // Should never happen } // Search process list for other applications with same name for (i=pm.begin(); i!=pm.end(); i++) { PROCINFO& procinfo = i->second; if (procinfo.id == myPid) continue; if (!strcmp(procinfo.command, myName)) { otherInstanceID = procinfo.id; break; } } return otherInstanceID; }
bool CBOINCClientManager::IsBOINCCoreRunning() { wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Function Begin")); bool running = false; PROC_MAP pm; int retval; #ifndef __WXMSW__ if (m_lBOINCCoreProcessId) { // Prevent client from being a zombie if (waitpid(m_lBOINCCoreProcessId, 0, WNOHANG) == m_lBOINCCoreProcessId) { m_lBOINCCoreProcessId = 0; } } #endif // Look for BOINC Client in list of all running processes retval = procinfo_setup(pm); if (retval) return false; // Should never happen PROC_MAP::iterator i; for (i=pm.begin(); i!=pm.end(); ++i) { PROCINFO& pi = i->second; #ifdef __WXMSW__ if (!strcmp(pi.command, "boinc.exe")) #else if (!strcmp(pi.command, "boinc")) #endif { running = true; break; } if (!strcmp(pi.command, "boinc_client")) { running = true; break; } } wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Returning '%d'"), (int)running); wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Function End")); return running; }
void procinfo_show(PROC_MAP& pm) { PROCINFO pi; pi.clear(); PROC_MAP::iterator i; for (i=pm.begin(); i!=pm.end(); ++i) { PROCINFO& p = i->second; msg_printf(NULL, MSG_INFO, "%d %s: boinc? %d low_pri %d (u%f k%f)", p.id, p.command, p.is_boinc_app, p.is_low_priority, p.user_time, p.kernel_time ); #ifdef _WIN32 if (p.id == 0) continue; #endif if (p.is_boinc_app) continue; if (p.is_low_priority) continue; pi.kernel_time += p.kernel_time; pi.user_time += p.user_time; } msg_printf(NULL, MSG_INFO, "non-boinc: u%f k%f", pi.user_time, pi.kernel_time); }
void CBOINCClientManager::KillClient() { PROC_MAP pm; int retval; if (m_lBOINCCoreProcessId) { kill_program(m_lBOINCCoreProcessId); return; } retval = procinfo_setup(pm); if (retval) return; // Should never happen PROC_MAP::iterator i; for (i=pm.begin(); i!=pm.end(); i++) { PROCINFO& procinfo = i->second; if (!strcmp(procinfo.command, "boinc")) { kill_program(procinfo.id); break; } } }
bool CBOINCClientManager::IsBOINCCoreRunning() { wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Function Begin")); bool running = false; #ifdef __WXMSW__ char buf[MAX_PATH] = ""; if (is_daemon_installed()) { running = (FALSE != is_daemon_starting()) || (FALSE != is_daemon_running()); } else { // Global mutex on Win2k and later // safe_strcpy(buf, "Global\\"); strcat( buf, RUN_MUTEX); HANDLE h = CreateMutexA(NULL, true, buf); DWORD err = GetLastError(); if ((h==0) || (err == ERROR_ALREADY_EXISTS)) { running = true; } if (h) { CloseHandle(h); } } #elif defined(__WXMAC__) char path[1024]; static FILE_LOCK file_lock; sprintf(path, "%s/%s", (const char *)wxGetApp().GetDataDirectory().mb_str(), LOCK_FILE_NAME); if (boinc_file_exists(path)) { // If there is no lock file, core is not running if (file_lock.lock(path)) { running = true; } else { file_lock.unlock(path); } } #else PROC_MAP pm; int retval; if (m_lBOINCCoreProcessId) { // Prevent client from being a zombie if (waitpid(m_lBOINCCoreProcessId, 0, WNOHANG) == m_lBOINCCoreProcessId) { m_lBOINCCoreProcessId = 0; } } // Look for BOINC Client in list of all running processes retval = procinfo_setup(pm); if (retval) return false; // Should never happen PROC_MAP::iterator i; for (i=pm.begin(); i!=pm.end(); i++) { PROCINFO& pi = i->second; if (!strcmp(pi.command, "boinc")) { running = true; break; } if (!strcmp(pi.command, "boinc_client")) { running = true; break; } } #endif wxLogTrace(wxT("Function Status"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Returning '%d'"), (int)running); wxLogTrace(wxT("Function Start/End"), wxT("CBOINCClientManager::IsBOINCCoreRunning - Function End")); return running; }
// build table of all processes in system // int procinfo_setup(PROC_MAP& pm) { DIR *dir; dirent *piddir; FILE* fd; PROC_STAT ps; char pidpath[MAXPATHLEN]; char buf[1024]; int pid = getpid(); int retval; dir = opendir("/proc"); if (!dir) { fprintf(stderr, "procinfo_setup(): can't open /proc\n"); return 0; } while (1) { piddir = readdir(dir); if (!piddir) break; if (!isdigit(piddir->d_name[0])) continue; #if defined(HAVE_PROCFS_H) && defined(HAVE__PROC_SELF_PSINFO) // solaris psinfo_t psinfo; sprintf(pidpath, "/proc/%s/psinfo", piddir->d_name); fd = fopen(pidpath, "r"); if (!fd) continue; PROCINFO p; p.clear(); if (fread(&psinfo, sizeof(psinfo_t), 1, fd) == 1) { p.id = psinfo.pr_pid; p.parentid = psinfo.pr_ppid; p.swap_size = psinfo.pr_size*1024.; p.working_set_size = psinfo.pr_rssize * 1024.; strlcpy(p.command, psinfo.pr_fname, sizeof(p.command)); } fclose(fd); sprintf(pidpath, "/proc/%s/usage", piddir->d_name); prusage_t prusage; fd = fopen(pidpath, "r"); if (!fd) continue; if (fread(&prusage, sizeof(prusage_t), 1, fd) == 1) { p.user_time = (float)prusage.pr_utime.tv_sec + ((float)prusage.pr_utime.tv_nsec)/1e+9; p.kernel_time = (float)prusage.pr_stime.tv_sec + ((float)prusage.pr_utime.tv_nsec)/1e+9; // page faults: I/O + non I/O p.page_fault_count = prusage.pr_majf + prusage.pr_minf; } fclose(fd); p.is_boinc_app = (p.id == pid || strcasestr(p.command, "boinc")); pm.insert(std::pair(p.id, p)); #else // linux sprintf(pidpath, "/proc/%s/stat", piddir->d_name); fd = fopen(pidpath, "r"); if (!fd) continue; if (fgets(buf, sizeof(buf), fd) == NULL) { retval = ERR_NULL; } else { retval = ps.parse(buf); } fclose(fd); if (retval) { // ps.parse() returns an error if the executable name contains ). // In that case skip this process. // continue; } PROCINFO p; p.clear(); p.id = ps.pid; p.parentid = ps.ppid; p.swap_size = ps.vsize; // rss = pages, need bytes // assumes page size = 4k p.working_set_size = ps.rss * (float)getpagesize(); // page faults: I/O + non I/O p.page_fault_count = ps.majflt + ps.minflt; // times are in jiffies, need seconds // assumes 100 jiffies per second p.user_time = ps.utime / 100.; p.kernel_time = ps.stime / 100.; strlcpy(p.command, ps.comm, sizeof(p.command)); p.is_boinc_app = (p.id == pid || strcasestr(p.command, "boinc")); p.is_low_priority = (ps.priority == 39); // Internally Linux stores the process priority as nice + 20 // as -ve values are error codes. Thus this generally gives // a process priority range of 39..0 pm.insert(std::pair<int, PROCINFO>(p.id, p)); #endif } closedir(dir); find_children(pm); return 0; }
// build table of all processes in system // int procinfo_setup(PROC_MAP& pm) { int pid = getpid(); FILE* fd; PROCINFO p; int c, real_mem, virtual_mem, hours; char* lf; static long iBrandID = -1; int priority; if (iBrandID < 0) { iBrandID = BOINC_BRAND_ID; // For GridRepublic or ProgressThruProcessors, the Mac // installer put a branding file in our data directory FILE *f = fopen("/Library/Application Support/BOINC Data/Branding", "r"); if (f) { fscanf(f, "BrandId=%ld\n", &iBrandID); fclose(f); } } #if SHOW_TIMING UnsignedWide start, end, elapsed; start = UpTime(); #endif // Some values of possible interest available from 'ps' command: // %cpu percentage cpu usage (alias pcpu) // %mem percentage memory usage (alias pmem) // command command (executable name) // majflt total page faults // minflt total page reclaims // nswap total swaps in/out // pagein pageins (same as majflt) // pid process ID // ppid parent process ID // poip pageouts in progress // pri scheduling priority // rss resident set size in Kbytes // time accumulated cpu time, user + system // vsz virtual size in Kbytes // // Unfortunately, the selectors majflt, minflt, pagein do not work on OS X, // and ps does not return kernel time separately from user time. // // Earlier versions of procinf_mac.C launched a small helper application // AppStats using a bi-directional pipe. AppStats used mach ports to get // all the information, including page fault counts, kernel and user times. // In order to use mach ports, AppStats must run setuid root. // // But these three items are not actually used (page fault counts aren't // available from Windows either) so we have reverted to using the ps // utility, even though it takes more cpu time than AppStats did. // This eliminates the need to install our own application which runs setuid // root; this was perceived by some users as a security risk. fd = popen("ps -axcopid,ppid,rss,vsz,pagein,pri,time,command", "r"); if (!fd) return ERR_FOPEN; // Skip over the header line do { c = fgetc(fd); if (c == EOF) { pclose(fd); return ERR_GETS; } } while (c != '\n'); while (1) { p.clear(); c = fscanf(fd, "%d%d%d%d%lu%d%d:%lf ", &p.id, &p.parentid, &real_mem, &virtual_mem, &p.page_fault_count, &priority, &hours, &p.user_time ); if (c < 7) break; if (fgets(p.command, sizeof(p.command) , fd) == NULL) break; lf = strchr(p.command, '\n'); if (lf) *lf = '\0'; // Strip trailing linefeed p.working_set_size = (double)real_mem * 1024.; p.swap_size = (double)virtual_mem * 1024.; p.user_time += 60. * (float)hours; p.is_boinc_app = (p.id == pid || strcasestr(p.command, "boinc")); p.is_low_priority = (priority <= 12); switch (iBrandID) { case GRIDREPUBLIC_BRAND_ID: if (!strcasestr(p.command, "GridRepublic")) { p.is_boinc_app = true; } break; case PROGRESSTHRUPROCESSORS_BRAND_ID: if (!strcasestr(p.command, "Progress Thru Processors")) { p.is_boinc_app = true; } break; case CHARITYENGINE_BRAND_ID: if (!strcasestr(p.command, "Charity Engine")) { p.is_boinc_app = true; } break; } pm.insert(std::pair<int, PROCINFO>(p.id, p)); } pclose(fd); #if SHOW_TIMING end = UpTime(); elapsed = AbsoluteToNanoseconds(SubAbsoluteFromAbsolute(end, start)); msg_printf(NULL, MSG_INFO, "elapsed time = %llu, m_swap = %lf\n", elapsed, gstate.host_info.m_swap); #endif find_children(pm); return 0; }
// Note: the following will work on both NT and XP, // because the NT process structure differs only at the end // int get_procinfo_XP(PROC_MAP& pm) { ULONG cbBuffer = 128*1024; // 128k initial buffer PVOID pBuffer = NULL; PSYSTEM_PROCESSES pProcesses = NULL; static DWORD pid = 0; if (!pid) { pid = GetCurrentProcessId(); } #if 0 printf("FILETIME: %d\n", sizeof(FILETIME)); printf("LARGE_INTEGER: %d\n", sizeof(LARGE_INTEGER)); printf("DWORD: %d\n", sizeof(DWORD)); printf("UNICODE_STRING: %d\n", sizeof(UNICODE_STRING)); printf("KPRIORITY: %d\n", sizeof(KPRIORITY)); printf("ULONG: %d\n", sizeof(ULONG)); printf("SIZE_T: %d\n", sizeof(SIZE_T)); #endif get_process_information(&pBuffer, &cbBuffer); pProcesses = (PSYSTEM_PROCESSES)pBuffer; while (pProcesses) { PROCINFO p; p.clear(); p.id = pProcesses->ProcessId; p.parentid = pProcesses->InheritedFromProcessId; p.swap_size = pProcesses->VmCounters.PagefileUsage; p.working_set_size = pProcesses->VmCounters.WorkingSetSize; p.page_fault_count = pProcesses->VmCounters.PageFaultCount; p.user_time = ((double) pProcesses->UserTime.QuadPart)/1e7; p.kernel_time = ((double) pProcesses->KernelTime.QuadPart)/1e7; p.id = pProcesses->ProcessId; p.parentid = pProcesses->InheritedFromProcessId; p.is_low_priority = (pProcesses->BasePriority <= 4); WideCharToMultiByte(CP_ACP, 0, pProcesses->ProcessName.Buffer, pProcesses->ProcessName.Length, p.command, sizeof(p.command), NULL, NULL ); p.is_boinc_app = (p.id == (int)pid) || (strcasestr(p.command, "boinc") != NULL); #ifdef _GRIDREPUBLIC if (!strcmp(p.command, "gridrepublic.exe")) { p.is_boinc_app = true; } #endif #ifdef _PROGRESSTHRUPROCESSORS if (!strcmp(p.command, "progressthruprocessors.exe")) { p.is_boinc_app = true; } #endif pm.insert(std::pair<int, PROCINFO>(p.id, p)); if (!pProcesses->NextEntryDelta) { break; } pProcesses = (PSYSTEM_PROCESSES)(((LPBYTE)pProcesses) + pProcesses->NextEntryDelta); } if (pBuffer) HeapFree(GetProcessHeap(), NULL, pBuffer); find_children(pm); return 0; }
// Launch VboxSVC.exe before going any further. if we don't, it'll be launched by // svchost.exe with its environment block which will not contain the reference // to VBOX_USER_HOME which is required for running in the BOINC account-based // sandbox on Windows. int VBOX_BASE::launch_vboxsvc() { APP_INIT_DATA aid; PROC_MAP pm; PROCINFO p; string command; int retval = ERR_EXEC; #ifdef _WIN32 char buf[256]; STARTUPINFO si; PROCESS_INFORMATION pi; int pidVboxSvc = 0; HANDLE hVboxSvc = NULL; memset(&si, 0, sizeof(si)); memset(&pi, 0, sizeof(pi)); boinc_get_init_data_p(&aid); if (aid.using_sandbox) { if (!vboxsvc_pid_handle || !process_exists(vboxsvc_pid_handle)) { if (vboxsvc_pid_handle) CloseHandle(vboxsvc_pid_handle); procinfo_setup(pm); for (PROC_MAP::iterator i = pm.begin(); i != pm.end(); ++i) { p = i->second; // We are only looking for vboxsvc if (0 != stricmp(p.command, "vboxsvc.exe")) continue; // Store process id for later use pidVboxSvc = p.id; // Is this the vboxsvc for the current user? // Non-service install it would be the current username // Service install it would be boinc_project hVboxSvc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, p.id); if (hVboxSvc) break; } if (pidVboxSvc && hVboxSvc) { vboxlog_msg("Status Report: Detected vboxsvc.exe. (PID = '%d')", pidVboxSvc); vboxsvc_pid = pidVboxSvc; vboxsvc_pid_handle = hVboxSvc; retval = BOINC_SUCCESS; } else { si.cb = sizeof(STARTUPINFO); si.dwFlags |= STARTF_FORCEOFFFEEDBACK | STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; command = "\"VBoxSVC.exe\" --logrotate 1"; CreateProcess( NULL, (LPTSTR)command.c_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, (LPTSTR)virtualbox_home_directory.c_str(), &si, &pi ); if (pi.hThread) CloseHandle(pi.hThread); if (pi.hProcess) { vboxlog_msg("Status Report: Launching vboxsvc.exe. (PID = '%d')", pi.dwProcessId); vboxsvc_pid = pi.dwProcessId; vboxsvc_pid_handle = pi.hProcess; retval = BOINC_SUCCESS; } else { vboxlog_msg("Status Report: Launching vboxsvc.exe failed!."); vboxlog_msg(" Error: %s", windows_format_error_string(GetLastError(), buf, sizeof(buf))); #ifdef _DEBUG vboxlog_msg("Vbox Version: '%s'", virtualbox_version_raw.c_str()); vboxlog_msg("Vbox Install Directory: '%s'", virtualbox_install_directory.c_str()); vboxlog_msg("Vbox Home Directory: '%s'", virtualbox_home_directory.c_str()); #endif } string s = string(""); vbm_trace(command, s, retval); } } } #endif return retval; }
// build table of all processes in system // int procinfo_setup(PROC_MAP& pm) { #if HAVE_DIRENT_H DIR *dir; dirent *piddir; FILE* fd; PROC_STAT ps; PROCINFO p; char pidpath[MAXPATHLEN]; char buf[1024]; int pid = getpid(); int retval, final_retval = 0; dir = opendir("/proc"); if (!dir) return 0; while (1) { piddir = readdir(dir); if (!piddir) break; if (!isdigit(piddir->d_name[0])) continue; #if defined(HAVE_PROCFS_H) && defined(HAVE__PROC_SELF_PSINFO) // solaris psinfo_t psinfo; sprintf(pidpath, "/proc/%s/psinfo", piddir->d_name); fd = fopen(pidpath, "r"); if (fd) { p.clear(); if (fread(&psinfo, sizeof(psinfo_t), 1, fd) == 1) { p.id = psinfo.pr_pid; p.parentid = psinfo.pr_ppid; p.swap_size = psinfo.pr_size*1024.; p.working_set_size = psinfo.pr_rssize * 1024.; strlcpy(p.command, psinfo.pr_fname, sizeof(p.command)); } fclose(fd); sprintf(pidpath, "/proc/%s/usage", piddir->d_name); prusage_t prusage; fd = fopen(pidpath, "r"); if (fd) { if (fread(&prusage, sizeof(prusage_t), 1, fd) == 1) { p.user_time = (float)prusage.pr_utime.tv_sec + ((float)prusage.pr_utime.tv_nsec)/1e+9; p.kernel_time = (float)prusage.pr_stime.tv_sec + ((float)prusage.pr_utime.tv_nsec)/1e+9; // page faults: I/O + non I/O p.page_fault_count = prusage.pr_majf + prusage.pr_minf; } fclose(fd); p.is_boinc_app = (p.id == pid || strcasestr(p.command, "boinc")); pm.insert(std::pair(p.id, p)); } } #else // linux sprintf(pidpath, "/proc/%s/stat", piddir->d_name); fd = fopen(pidpath, "r"); if (fd) { fgets(buf, sizeof(buf), fd); retval = ps.parse(buf); fclose(fd); if (retval) { final_retval = retval; } else { p.clear(); p.id = ps.pid; p.parentid = ps.ppid; p.swap_size = ps.vsize; // rss = pages, need bytes // assumes page size = 4k p.working_set_size = ps.rss * (float)getpagesize(); // page faults: I/O + non I/O p.page_fault_count = ps.majflt + ps.minflt; // times are in jiffies, need seconds // assumes 100 jiffies per second p.user_time = ps.utime / 100.; p.kernel_time = ps.stime / 100.; strlcpy(p.command, ps.comm, sizeof(p.command)); p.is_boinc_app = (p.id == pid || strcasestr(p.command, "boinc")); p.is_low_priority = (ps.priority == 39); // Linux seems to add 20 here, // but this isn't documented anywhere pm.insert(std::pair<int, PROCINFO>(p.id, p)); } } #endif } closedir(dir); #endif find_children(pm); return final_retval; }