X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8f6c56a50524aa785f7e596d52dddfb331e18961..89b3af67bb32e691275bf6fa803d1834b2284115:/osfmk/i386/perfmon.c diff --git a/osfmk/i386/perfmon.c b/osfmk/i386/perfmon.c index f2cb2b850..109ab1e7a 100644 --- a/osfmk/i386/perfmon.c +++ b/osfmk/i386/perfmon.c @@ -36,13 +36,24 @@ #include #include #include +#include -#ifdef DEBUG +#if DEBUG #define DBG(x...) kprintf(x) #else #define DBG(x...) #endif +decl_simple_lock_data(,pmc_lock) +static task_t pmc_owner = TASK_NULL; +static int pmc_thread_count = 0; + +/* PMC Facility Owner: + * TASK_NULL - no one owns it + * kernel_task - owned by pmc + * other task - owned by another task + */ + /* * Table of ESCRs and addresses associated with performance counters/CCCRs. * See Intel SDM Vol 3, Table 15-4 (section 15.9): @@ -280,24 +291,18 @@ pmc_p6_intr(void *state) (*pmc_table->ovf_func[id])(id, state); } -int -pmc_init(void) +void * +pmc_alloc(void) { int ret; - cpu_core_t *my_core; pmc_table_t *pmc_table; pmc_machine_t pmc_type; - my_core = cpu_core(); - assert(my_core); - pmc_type = _pmc_machine_type(); if (pmc_type == pmc_none) { - return KERN_FAILURE; + return NULL; } - pmc_table = (pmc_table_t *) my_core->pmc; - if (pmc_table == NULL) { ret = kmem_alloc(kernel_map, (void *) &pmc_table, sizeof(pmc_table_t)); if (ret != KERN_SUCCESS) @@ -321,18 +326,10 @@ pmc_init(void) default: break; } - if (!atomic_cmpxchg((uint32_t *) &my_core->pmc, - 0, (uint32_t) pmc_table)) { - kmem_free(kernel_map, - (vm_offset_t) pmc_table, sizeof(pmc_table_t)); - } - } - DBG("pmc_init() done for cpu %d my_core->pmc=0x%x type=%d\n", - cpu_number(), my_core->pmc, pmc_type); - - return KERN_SUCCESS; + return (void *) pmc_table; } + static inline pmc_table_t * pmc_table_valid(pmc_id_t id) { @@ -556,3 +553,81 @@ pmc_set_ovf_func(pmc_id_t id, pmc_ovf_func_t func) return KERN_SUCCESS; } + +int +pmc_acquire(task_t task) +{ + kern_return_t retval = KERN_SUCCESS; + + simple_lock(&pmc_lock); + + if(pmc_owner == task) { + DBG("pmc_acquire - " + "ACQUIRED: already owner\n"); + retval = KERN_SUCCESS; + /* already own it */ + } else if(pmc_owner == TASK_NULL) { /* no one owns it */ + pmc_owner = task; + pmc_thread_count = 0; + DBG("pmc_acquire - " + "ACQUIRED: no current owner - made new owner\n"); + retval = KERN_SUCCESS; + } else { /* someone already owns it */ + if(pmc_owner == kernel_task) { + if(pmc_thread_count == 0) { + /* kernel owns it but no threads using it */ + pmc_owner = task; + pmc_thread_count = 0; + DBG("pmc_acquire - " + "ACQUIRED: owned by kernel, no threads\n"); + retval = KERN_SUCCESS; + } else { + DBG("pmc_acquire - " + "DENIED: owned by kernel, in use\n"); + retval = KERN_RESOURCE_SHORTAGE; + } + } else { /* non-kernel owner */ + DBG("pmc_acquire - " + "DENIED: owned by another task\n"); + retval = KERN_RESOURCE_SHORTAGE; + } + } + + simple_unlock(&pmc_lock); + return retval; +} + +int +pmc_release(task_t task) +{ + kern_return_t retval = KERN_SUCCESS; + task_t old_pmc_owner = pmc_owner; + + simple_lock(&pmc_lock); + + if(task != pmc_owner) { + retval = KERN_NO_ACCESS; + } else { + if(old_pmc_owner == kernel_task) { + if(pmc_thread_count>0) { + DBG("pmc_release - " + "NOT RELEASED: owned by kernel, in use\n"); + retval = KERN_NO_ACCESS; + } else { + DBG("pmc_release - " + "RELEASED: was owned by kernel\n"); + pmc_owner = TASK_NULL; + retval = KERN_SUCCESS; + } + } else { + DBG("pmc_release - " + "RELEASED: was owned by user\n"); + pmc_owner = TASK_NULL; + retval = KERN_SUCCESS; + } + } + + simple_unlock(&pmc_lock); + return retval; +} +