diff -Naur boinc-6.2.18/client/app_stats_mac.C boinc-6.2.18-mp/client/app_stats_mac.C --- boinc-6.2.18/client/app_stats_mac.C 2008-08-25 22:29:18.000000000 +0200 +++ boinc-6.2.18-mp/client/app_stats_mac.C 1970-01-01 01:00:00.000000000 +0100 @@ -1,715 +0,0 @@ -// 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., -// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -// This file is adapted from code originally supplied by Apple Computer, Inc. -// The Berkeley Open Infrastructure for Network Computing project has modified -// the original code and made additions as of September 22, 2006. The original -// Apple Public Source License statement appears below: - -/* - * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ - -// app_stats_mac.C -// - -// #define _DEBUG 1 - -// Put a safety limit on recursion -#define MAX_DESCENDANT_LEVEL 4 - -// Totals for non_BOINC processes are not useful because most OSs don't -// move idle processes out of RAM, so physical memory is always full -#define GET_NON_BOINC_INFO 0 - -// We don't need swap space info because -// http://developer.apple.com/documentation/Performance/Conceptual/ManagingMemory/Articles/AboutMemory.html says: -// Unlike most UNIX-based operating systems, Mac OS X does not use a -// preallocated swap partition for virtual memory. Instead, it uses all -// of the available space on the machineÕs boot partition. -// However, the associated overhead is not significant if we are examining -// only BOINC descendant processes. -#define GET_SWAP_SIZE 1 - -// The overhead for getting CPU times is not significant if we are -// examining only BOINC descendant processes. -#define GET_CPU_TIMES 1 - - -#include -#include -#include -#include -#include -#include - -#include "procinfo.h" - -using std::vector; - -static int get_boinc_proc_info(int my_pid, int boinc_pid); -static int build_proc_list (vector& pi, int boinc_pid); -static void output_child_totals(PROCINFO& pinfo); -static boolean_t appstats_task_update(task_t a_task, vector& piv); -static void find_all_descendants(vector& piv, int pid, int rlvl); -static void add_child_totals(PROCINFO& pi, vector& piv, int pid, int rlvl); -//static void add_others(PROCINFO&, std::vector&); -static void sig_pipe(int signo); - -#ifdef _DEBUG -static void print_procinfo(PROCINFO& pinfo); -static void vm_size_render(unsigned long long a_size); -#endif - -// BOINC helper application to get info about each of the BOINC Client's -// child processes (including all its descendants) and also totals for -// all other processes. -// On the Mac, much of this information is accessible only by the super-user, -// so this helper application must be run setuid root. - -int main(int argc, char** argv) { - int boinc_pid, my_pid; - int retval; - char buf[256]; - - if (geteuid() != 0) // This must be run setuid root - return EACCES; - - my_pid = getpid(); - boinc_pid = getppid(); // Assumes we were called by BOINC client - - if (argc == 2) - boinc_pid = atoi(argv[1]); // Pass in any desired valid pid for testing - - if (signal(SIGPIPE, sig_pipe) == SIG_ERR) { - fprintf(stderr, "signal error"); - return 0; - } - - setbuf(stdin, 0); - setbuf(stdout, 0); - - while (1) { - if (fgets(buf, sizeof(buf), stdin) == NULL) - return 0; - - if (feof(stdin)) - return 0; - - retval = get_boinc_proc_info(my_pid, boinc_pid); - } - - return 0; -} - -static int get_boinc_proc_info(int my_pid, int boinc_pid) { - int retval; - vector piv; - PROCINFO child_total; - unsigned int i; - - - retval = build_proc_list(piv, boinc_pid); - if (retval) - return retval; - - for (i=0; i& pi, int boinc_pid) { - boolean_t retval = FALSE; - kern_return_t error; - mach_port_t appstats_port; - processor_set_t *psets, pset; - task_t *tasks; - unsigned i, j, pcnt, tcnt; - PROCINFO pinfo; - int pid, mib[4]; - struct kinfo_proc kinfo; - size_t kinfosize; - - appstats_port = mach_host_self(); - - // First, get a list of all tasks / processes - - error = host_processor_sets(appstats_port, &psets, &pcnt); - if (error != KERN_SUCCESS) { - fprintf(stderr, - "Error in host_processor_sets(): %s", - mach_error_string(error)); - retval = TRUE; - goto RETURN; - } - - for (i = 0; i < pcnt; i++) { - if (retval) - break; - - error = host_processor_set_priv(appstats_port, psets[i], &pset); - if (error != KERN_SUCCESS) { - fprintf(stderr, - "Error in host_processor_set_priv(): %s", - mach_error_string(error)); - retval = TRUE; - break; - } - - error = processor_set_tasks(pset, &tasks, &tcnt); - if (error != KERN_SUCCESS) { - fprintf(stderr, - "Error in processor_set_tasks(): %s", - mach_error_string(error)); - retval = TRUE; - break; - } - - for (j = 0; j < tcnt; j++) { - if (retval) - break; - - memset(&pinfo, 0, sizeof(PROCINFO)); - - /* Get pid for this task. */ - error = pid_for_task(tasks[j], &pid); - if (error != KERN_SUCCESS) { - /* Not a process, or the process is gone. */ - continue; - } - - // Get parent pid for each process - /* Get kinfo structure for this task. */ - kinfosize = sizeof(struct kinfo_proc); - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = pid; - - if (sysctl(mib, 4, &kinfo, &kinfosize, NULL, 0) == -1) { - fprintf(stderr, - "%s(): Error in sysctl(): %s", __FUNCTION__, - strerror(errno)); - retval = TRUE; - break; - } - - if (kinfo.kp_proc.p_stat == 0) { - /* Zombie process. */ - continue; - } - - pinfo.id = pid; - pinfo.parentid = kinfo.kp_eproc.e_ppid; - - pi.push_back(pinfo); - } - } - -#if ! GET_NON_BOINC_INFO - // Next, find all BOINC's decendants and mark them for further study - if (! retval) - find_all_descendants(pi, boinc_pid, 0); -#endif - - // Now get the process information for each descendant - for (i = 0; i < pcnt; i++) { - for (j = 0; j < tcnt; j++) { - if (! retval) - if (appstats_task_update(tasks[j], pi)) { - retval = TRUE; - goto RETURN; - } - - /* Delete task port if it isn't our own. */ - if (tasks[j] != mach_task_self()) { - mach_port_deallocate(mach_task_self(), - tasks[j]); - } - } - - error = vm_deallocate((vm_map_t)mach_task_self(), - (vm_address_t)tasks, tcnt * sizeof(task_t)); - if (error != KERN_SUCCESS) { - if (!retval) - fprintf(stderr, - "Error in vm_deallocate(): %s", - mach_error_string(error)); - retval = TRUE; - goto RETURN; - } - if ((error = mach_port_deallocate(mach_task_self(), - pset)) != KERN_SUCCESS - || (error = mach_port_deallocate(mach_task_self(), - psets[i])) != KERN_SUCCESS) { - if (!retval) - fprintf(stderr, - "Error in mach_port_deallocate(): %s", - mach_error_string(error)); - retval = TRUE; - goto RETURN; - } - } - - error = vm_deallocate((vm_map_t)mach_task_self(), - (vm_address_t)psets, pcnt * sizeof(processor_set_t)); - if (error != KERN_SUCCESS) { - if (!retval) - fprintf(stderr, - "Error in vm_deallocate(): %s", - mach_error_string(error)); - retval = TRUE; - goto RETURN; - } - - RETURN: - return retval; - -} - -/* Update statistics for task a_task. */ -static boolean_t appstats_task_update(task_t a_task, vector& piv) -{ - boolean_t retval; - kern_return_t error; - mach_msg_type_number_t count; - task_basic_info_data_t ti; - vm_address_t address; - mach_port_t object_name; - vm_region_top_info_data_t info; - vm_size_t size; - thread_array_t thread_table; - unsigned int table_size; - thread_basic_info_t thi; - thread_basic_info_data_t thi_data; - unsigned i; - task_events_info_data_t events; - vm_size_t vsize, rsize; - PROCINFO *pinfo; - int pid; - - /* Get pid for this task. */ - error = pid_for_task(a_task, &pid); - if (error != KERN_SUCCESS) { - /* Not a process, or the process is gone. */ - retval = FALSE; - goto GONE; - } - - for (i=0; iid == pid) - break; - } - - if (pinfo->id != pid) { - fprintf(stderr, "pid %d missing from list\n", pid); - retval = FALSE; - goto RETURN; - } - -#if ! GET_NON_BOINC_INFO - if (!pinfo->is_boinc_app) { - retval = FALSE; - goto RETURN; - } -#endif - /* - * Get task_info, which is used for memory usage and CPU usage - * statistics. - */ - count = TASK_BASIC_INFO_COUNT; - error = task_info(a_task, TASK_BASIC_INFO, (task_info_t)&ti, &count); - if (error != KERN_SUCCESS) { - retval = FALSE; - goto GONE; - } - - /* - * Get memory usage statistics. - */ - - /* - * Set rsize and vsize; they require no calculation. (Well, actually, - * we adjust vsize if traversing memory objects to not include the - * globally shared text and data regions). - */ - rsize = ti.resident_size; -#if GET_SWAP_SIZE - vsize = ti.virtual_size; - /* - * Iterate through the VM regions of the process and determine - * the amount of memory of various types it has mapped. - */ - for (address = 0; ; address += size) { - /* Get memory region. */ - count = VM_REGION_TOP_INFO_COUNT; - if (vm_region(a_task, &address, &size, - VM_REGION_TOP_INFO, (vm_region_info_t)&info, &count, - &object_name) != KERN_SUCCESS) { - /* No more memory regions. */ - break; - } - - if (address >= GLOBAL_SHARED_TEXT_SEGMENT - && address < (GLOBAL_SHARED_DATA_SEGMENT - + SHARED_DATA_REGION_SIZE)) { - /* This region is private shared. */ - - /* - * Check if this process has the globally shared - * text and data regions mapped in. If so, adjust - * virtual memory size and exit loop. - */ - if (info.share_mode == SM_EMPTY) { - vm_region_basic_info_data_64_t b_info; - - count = VM_REGION_BASIC_INFO_COUNT_64; - if (vm_region_64(a_task, &address, - &size, VM_REGION_BASIC_INFO, - (vm_region_info_t)&b_info, &count, - &object_name) != KERN_SUCCESS) { - break; - } - - if (b_info.reserved) { - vsize -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE); - break; - } - } - } - } -#else - vsize = 0; -#endif // GET_SWAP_SIZE - pinfo->working_set_size = rsize; - pinfo->swap_size = vsize; - - /* - * Get CPU usage statistics. - */ - - pinfo->user_time = (double)ti.user_time.seconds + (((double)ti.user_time.microseconds)/1000000.); - pinfo->kernel_time = (double)ti.system_time.seconds + (((double)ti.system_time.microseconds)/1000000.); - - /* Get number of threads. */ - error = task_threads(a_task, &thread_table, &table_size); - if (error != KERN_SUCCESS) { - retval = FALSE; - goto RETURN; - } - -#if GET_CPU_TIMES - /* Iterate through threads and collect usage stats. */ - thi = &thi_data; - for (i = 0; i < table_size; i++) { - count = THREAD_BASIC_INFO_COUNT; - if (thread_info(thread_table[i], THREAD_BASIC_INFO, - (thread_info_t)thi, &count) == KERN_SUCCESS) { - if ((thi->flags & TH_FLAGS_IDLE) == 0) { - pinfo->user_time += (double)thi->user_time.seconds + (((double)thi->user_time.microseconds)/1000000.); - pinfo->kernel_time += (double)thi->system_time.seconds + (((double)thi->system_time.microseconds)/1000000.); - } - } - if (a_task != mach_task_self()) { - if ((error = mach_port_deallocate(mach_task_self(), - thread_table[i])) != KERN_SUCCESS) { - fprintf(stderr, - "Error in mach_port_deallocate(): %s", - mach_error_string(error)); - retval = TRUE; - goto RETURN; - } - } - } - if ((error = vm_deallocate(mach_task_self(), (vm_offset_t)thread_table, - table_size * sizeof(thread_array_t)) != KERN_SUCCESS)) { - fprintf(stderr, - "Error in vm_deallocate(): %s", - mach_error_string(error)); - retval = TRUE; - goto RETURN; - } -#endif GET_CPU_TIMES - - /* - * Get event counters. - */ - - count = TASK_EVENTS_INFO_COUNT; - if (task_info(a_task, TASK_EVENTS_INFO, - (task_info_t)&events, &count) != KERN_SUCCESS) { - /* Error. */ - retval = FALSE; - goto RETURN; - } else { - pinfo->page_fault_count = events.pageins; - } - - retval = FALSE; - RETURN: - GONE: - - return retval; -} - -// Scan the process table marking all the decendants of the parent -// process. Loop thru entire table as the entries aren't in order. -// Recurse at most 5 times to get additional child processes. -// -static void find_all_descendants(vector& piv, int pid, int rlvl) { - unsigned int i; - - if (rlvl > MAX_DESCENDANT_LEVEL) { - return; - } - for (i=0; i& piv, int pid, int rlvl) { - unsigned int i; - - if (rlvl > (MAX_DESCENDANT_LEVEL - 1)) { - return; - } - for (i=0; i& piv) { - unsigned int i; - - memset(&pi, 0, sizeof(pi)); - for (i=0; i. - */ - - -#ifdef __cplusplus -extern "C" { -#endif - - -#define OLD_GDB_DYLD_INTERFACE __ppc__ || __i386__ - -#if OLD_GDB_DYLD_INTERFACE -/* - * gdb_dyld_version is the version of gdb interface that dyld is currently - * exporting. For the interface described in this header file gdb_dyld_version - * is 2. As the gdb/dyld interface changes this number will be incremented and - * comments will be added as to what are the are changes for the various - * versions. - */ -extern unsigned int gdb_dyld_version; - -/* - * gdb_dyld_state_changed is the internal dyld routine called by dyld to notify - * gdb that the state of the data structures has changed. gdb is expected to - * put a break point on this routine and re-read the internal dyld data - * structures below when this break point is hit. - */ -extern void gdb_dyld_state_changed(void); - -/* - * gdb looks directly at parts of two of dyld's internal data structures. The - * list of object file images and the list of library images. The parts of - * these structures that gdb looks at will not change unless the value of - * gdb_dyld_version changes. The size of these structures and the other fields - * that gdb does not look at may change. - * - * struct object_images { - * struct object_image images[NOBJECT_IMAGES]; - * unsigned long nimages; - * struct object_images *next_images; - * ... - * }; - * - * struct library_images { - * struct library_image images[NLIBRARY_IMAGES]; - * unsigned long nimages; - * struct library_images *next_images; - * ... - * }; - * - * Both the object_image structure and the library_image structure - * start with a structure containing the following fields: - * - * struct image { - * char *physical_name; physical image name (file name) - * unsigned long vmaddr_slide; the slide from the staticly linked address - * struct mach_header *mh; address of the mach header of the image - * unsigned long valid; TRUE if this is struct is valid - * char *name; image name for reporting errors - * ... - * }; - * - * In gdb_dyld_version 1 the first field was "name". In gdb_dyld_version 2 the - * first field was changed to "physical_name" and a new fifth field "name" was - * added. These two fields are set to the same values except in the case of - * zero-link. In zero-link the NSLinkModule() option - * NSLINKMODULE_OPTION_TRAILING_PHYS_NAME is used and then the physical_name is - * the file name of the module zero-link loaded that is part of the logical - * image "name". - */ - -/* object_images is the global object_images structure */ - -/* the number of gdb_object_image structures present per bucket */ -extern unsigned int gdb_nobject_images; - -/* the size of each gdb_object_image structure */ -extern unsigned int gdb_object_image_size; - -/* library_images is the global library_images structure */ - -/* the number of gdb_library_image structures present per bucket */ -extern unsigned int gdb_nlibrary_images; - -/* the size of each gdb_library_image structure */ -extern unsigned int gdb_library_image_size; - -#endif /* OLD_GDB_DYLD_INTERFACE */ - - -/* - * Beginning in Mac OS X 10.4, there is a new mechanism for dyld to notify gdb and other about new images. - * - * - */ - -enum dyld_image_mode { dyld_image_adding=0, dyld_image_removing=1 }; - -struct dyld_image_info { - const struct mach_header* imageLoadAddress; /* base address image is mapped into */ - const char* imageFilePath; /* path dyld used to load the image */ - uintptr_t imageFileModDate; /* time_t of image file */ - /* if stat().st_mtime of imageFilePath does not match imageFileModDate, */ - /* then file has been modified since dyld loaded it */ -}; - - -typedef void (*dyld_image_notifier)(enum dyld_image_mode mode, uint32_t infoCount, const struct dyld_image_info info[]); - -/* - * gdb looks for the symbol "_dyld_all_image_infos" in dyld. It contains the fields below. - * - * For a snap shot of what images are currently loaded, the infoArray fields contain a pointer - * to an array of all images. If infoArray is NULL, it means it is being modified, come back later. - * - * To be notified of changes, gdb sets a break point on the notification field. The function - * it points to is called by dyld with an array of information about what images have been added - * (dyld_image_adding) or are about to be removed (dyld_image_removing). - * - * The notification is called after infoArray is updated. This means that if gdb attaches to a process - * and infoArray is NULL, gdb can set a break point on notification and let the proccess continue to - * run until the break point. Then gdb can inspect the full infoArray. - */ - struct dyld_all_image_infos { - uint32_t version; /* == 1 in Mac OS X 10.4 */ - uint32_t infoArrayCount; - const struct dyld_image_info* infoArray; - dyld_image_notifier notification; - bool processDetachedFromSharedRegion; -}; -extern struct dyld_all_image_infos dyld_all_image_infos; - - - - -#ifdef __cplusplus -} -#endif - -#endif /* _DYLD_GDB_ */