// Berkeley Open Infrastructure for Network Computing // http://boinc.berkeley.edu // Copyright (C) 2006 University of California // // This is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; // either version 2.1 of the License, or (at your option) any later version. // // This software is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // See the GNU Lesser General Public License for more details. // // To view the GNU Lesser General Public License visit // http://www.gnu.org/copyleft/lesser.html // or write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // procinfo_mac.C // #define SHOW_TIMING 0 #include "config.h" #include #include #include #include #include #include #include #include #if SHOW_TIMING #include #endif #include "procinfo.h" #include "client_msgs.h" #include "file_names.h" #include "client_state.h" #include "hostinfo.h" using std::vector; // Routines to determine cpu time, memory usage and page fault count for // BOINC Client's child processes (including all their descendants) and also // totals for all other processes. This also sets host_info.m_swap. // // On the Mac, most of this information is only accessible by the super-user, // so this code calls a helper application AppStats which is run setuid root // to do most of the work. // // Since AppStats is called from the BOINC Client, it gets the BOINC Client's // pid using getppid(). It then searches the process list for all other // processes with the same parent. // // For each child of BOINC Client, AppStats totals the cpu times, memory usage // and page fault counts for the child and all its descendants, and prints the // totals to stdout. // // Finally, AppStats computes these totals for all remaining processes and // prints them to stdout (with a value of 0 for the pid). // // This code doesn't use PROCINFO.is_boinc_app, but we set it to be consistent // with the code for other platforms. static int bidirectional_popen(char *path, int *fd); int procinfo_setup(vector& pi) { static int fd[2] = {0, 0}; static int failed_retries = 0; char appstats_path[100]; PROCINFO p; int c, result, retry_count = 0; char buf[256]; struct statfs fs_info; #if SHOW_TIMING UnsignedWide start, end, elapsed; start = UpTime(); #endif if (fd[0] == 0) { // Launch AppStats helper application with a bidirectional pipe RELAUNCH: if (failed_retries > 4) // Give up after failures on 5 consecutive calls return ERR_EXEC; // of procinfo_setup() if (retry_count > 1) { ++failed_retries; return ERR_EXEC; } sprintf(appstats_path, "%s/%s", SWITCHER_DIR, APP_STATS_FILE_NAME); result = bidirectional_popen(appstats_path, fd); #if SHOW_TIMING msg_printf(NULL, MSG_ERROR, "bidirectional_popen returned %d\n", result); #endif if (result) { ++retry_count; goto RELAUNCH; } } c = write(fd[0], "\n", 1); // Request a set of process info from AppStats helper application if (c < 0) { // AppStats application exited ++retry_count; goto RELAUNCH; } while (1) { memset(&p, 0, sizeof(p)); for (unsigned int i=0; i& piv) { unsigned int i; // AppStat returned totals for each of BOINC's children and its descendants // as a single PROCINFO struct with the id field set to the pid of BOINC's // direct child. for (i=0; i& piv) { // AppStat returned total for all other processes as a single PROCINFO // struct with id field set to zero. memset(&pi, 0, sizeof(pi)); procinfo_app(pi, piv); } #endif static int bidirectional_popen(char *path, int *fd) { pid_t pid; char *appname; appname = strrchr(path, '/'); if (! appname) appname = path; if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) { /* only need a single stream pipe */ msg_printf(NULL, MSG_ERROR, "%s: pipe error %d: %s\n", appname, errno, strerror(errno)); return ERR_SOCKET; } if ( (pid = fork()) < 0) { close(fd[0]); close(fd[1]); fd[0] = 0; fd[1] = 0; msg_printf(NULL, MSG_ERROR, "%s: fork error\n", appname); return ERR_FORK; } else if (pid > 0) { /* parent */ close(fd[1]); } else { /* child */ close(fd[0]); if (fd[1] != STDIN_FILENO) { if (dup2(fd[1], STDIN_FILENO) != STDIN_FILENO) { fprintf(stderr, "dup2 error to stdin"); exit (1); } } if (fd[1] != STDOUT_FILENO) { if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) { fprintf(stderr, "dup2 error to stdout"); exit (1); } } if (execl(path, appname, NULL) < 0) { printf("-1\n"); fprintf(stderr, "execl error"); } } return 0; }