[sre] Remove MonoDynamicImage:handleref_managed field
[mono.git] / mono / metadata / mono-perfcounters.c
index 7479a564360b9a935ed3dd9e1b6c5e75cc581add..1a3123a30aad58811bbf8d07c6d0581ac029474e 100644 (file)
@@ -1,5 +1,5 @@
-/*
- * mono-perfcounters.c
+/**
+ * \file
  *
  * Performance counters support.
  *
@@ -7,6 +7,7 @@
  *
  * Copyright 2008-2009 Novell, Inc (http://www.novell.com)
  * 2011 Xamarin, Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include "config.h"
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
-#if defined (__NetBSD__) || defined (__APPLE__)
+#if defined (__APPLE__)
+#include <mach/message.h>
+#include <mach/mach_host.h>
+#include <mach/host_info.h>
 #include <sys/sysctl.h>
 #endif
+#if defined (__NetBSD__)
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/vmmeter.h>
+#endif
 #include "metadata/mono-perfcounters.h"
 #include "metadata/appdomain.h"
 #include "metadata/object-internals.h"
@@ -39,7 +48,7 @@
 #include "utils/mono-networkinterfaces.h"
 #include "utils/mono-error-internals.h"
 #include "utils/atomic.h"
-#include <mono/io-layer/io-layer.h>
+#include "utils/unlocked.h"
 
 /* map of CounterSample.cs */
 struct _MonoCounterSample {
@@ -148,8 +157,8 @@ enum {
 };
 
 static mono_mutex_t perfctr_mutex;
-#define perfctr_lock() mono_mutex_lock (&perfctr_mutex)
-#define perfctr_unlock() mono_mutex_unlock (&perfctr_mutex)
+#define perfctr_lock() mono_os_mutex_lock (&perfctr_mutex)
+#define perfctr_unlock() mono_os_mutex_unlock (&perfctr_mutex)
 
 typedef struct {
        char reserved [16];
@@ -224,6 +233,9 @@ typedef struct {
        int num_instances;
        /* variable length data follows */
        char name [1];
+       // string name
+       // string help
+       // SharedCounter counters_info [num_counters]
 } SharedCategory;
 
 typedef struct {
@@ -231,6 +243,7 @@ typedef struct {
        unsigned int category_offset;
        /* variable length data follows */
        char instance_name [1];
+       // string name
 } SharedInstance;
 
 typedef struct {
@@ -238,6 +251,8 @@ typedef struct {
        guint8 seq_num;
        /* variable length data follows */
        char name [1];
+       // string name
+       // string help
 } SharedCounter;
 
 typedef struct {
@@ -348,9 +363,9 @@ load_sarea_for_pid (int pid)
        perfctr_lock ();
        if (pid_to_shared_area == NULL)
                pid_to_shared_area = g_hash_table_new (NULL, NULL);
-       data = g_hash_table_lookup (pid_to_shared_area, GINT_TO_POINTER (pid));
+       data = (ExternalSArea *)g_hash_table_lookup (pid_to_shared_area, GINT_TO_POINTER (pid));
        if (!data) {
-               area = mono_shared_area_for_pid (GINT_TO_POINTER (pid));
+               area = (MonoSharedArea *)mono_shared_area_for_pid (GINT_TO_POINTER (pid));
                if (area) {
                        data = g_new (ExternalSArea, 1);
                        data->sarea = area;
@@ -358,7 +373,7 @@ load_sarea_for_pid (int pid)
                        g_hash_table_insert (pid_to_shared_area, GINT_TO_POINTER (pid), data);
                }
        } else {
-               area = data->sarea;
+               area = (MonoSharedArea *)data->sarea;
                data->refcount ++;
        }
        perfctr_unlock ();
@@ -369,7 +384,7 @@ static void
 unref_pid_unlocked (int pid)
 {
        ExternalSArea *data;
-       data = g_hash_table_lookup (pid_to_shared_area, GINT_TO_POINTER (pid));
+       data = (ExternalSArea *)g_hash_table_lookup (pid_to_shared_area, GINT_TO_POINTER (pid));
        if (data) {
                data->refcount--;
                if (!data->refcount) {
@@ -413,7 +428,7 @@ mono_determine_physical_ram_size (void)
        int mib[2] = {
                CTL_HW,
 #ifdef __NetBSD__
-               HW_PHYSMEM
+               HW_PHYSMEM64
 #else
                HW_MEMSIZE
 #endif
@@ -449,6 +464,77 @@ mono_determine_physical_ram_size (void)
 #endif
 }
 
+static guint64
+mono_determine_physical_ram_available_size (void)
+{
+#if defined (TARGET_WIN32)
+       MEMORYSTATUSEX memstat;
+
+       memstat.dwLength = sizeof (memstat);
+       GlobalMemoryStatusEx (&memstat);
+       return (guint64)memstat.ullAvailPhys;
+
+#elif defined (__NetBSD__)
+       struct vmtotal vm_total;
+       guint64 page_size;
+       int mib[2];
+       size_t len;
+
+       mib[0] = CTL_VM;
+       mib[1] = VM_METER;
+
+       len = sizeof (vm_total);
+       sysctl (mib, 2, &vm_total, &len, NULL, 0);
+
+       mib[0] = CTL_HW;
+       mib[1] = HW_PAGESIZE;
+
+       len = sizeof (page_size);
+       sysctl (mib, 2, &page_size, &len, NULL, 0);
+
+       return ((guint64) vm_total.t_free * page_size) / 1024;
+#elif defined (__APPLE__)
+       mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+       mach_port_t host = mach_host_self();
+       vm_size_t page_size;
+       vm_statistics_data_t vmstat;
+       kern_return_t ret;
+       do {
+               ret = host_statistics(host, HOST_VM_INFO, (host_info_t)&vmstat, &count);
+       } while (ret == KERN_ABORTED);
+
+       if (ret != KERN_SUCCESS) {
+               g_warning ("Mono was unable to retrieve memory usage!");
+               return 0;
+       }
+
+       host_page_size(host, &page_size);
+       return (guint64) vmstat.free_count * page_size;
+
+#elif defined (HAVE_SYSCONF)
+       guint64 page_size = 0, num_pages = 0;
+
+       /* sysconf works on most *NIX operating systems, if your system doesn't have it or if it
+        * reports invalid values, please add your OS specific code below. */
+#ifdef _SC_PAGESIZE
+       page_size = (guint64)sysconf (_SC_PAGESIZE);
+#endif
+
+#ifdef _SC_AVPHYS_PAGES
+       num_pages = (guint64)sysconf (_SC_AVPHYS_PAGES);
+#endif
+
+       if (!page_size || !num_pages) {
+               g_warning ("Your operating system's sysconf (3) function doesn't correctly report physical memory size!");
+               return 0;
+       }
+
+       return page_size * num_pages;
+#else
+       return 0;
+#endif
+}
+
 void
 mono_perfcounters_init (void)
 {
@@ -456,9 +542,9 @@ mono_perfcounters_init (void)
        d_offset += 7;
        d_offset &= ~7;
 
-       mono_mutex_init_recursive (&perfctr_mutex);
+       mono_os_mutex_init_recursive (&perfctr_mutex);
 
-       shared_area = mono_shared_area ();
+       shared_area = (MonoSharedArea *)mono_shared_area ();
        shared_area->counters_start = G_STRUCT_OFFSET (MonoSharedArea, counters);
        shared_area->counters_size = sizeof (MonoPerfCounters);
        shared_area->data_start = d_offset;
@@ -564,7 +650,7 @@ typedef struct {
 static gboolean
 category_search (SharedHeader *header, void *data)
 {
-       CatSearch *search = data;
+       CatSearch *search = (CatSearch *)data;
        if (header->ftype == FTYPE_CATEGORY) {
                SharedCategory *cat = (SharedCategory*)header;
                if (mono_string_compare_ascii (search->name, cat->name) == 0) {
@@ -588,7 +674,7 @@ find_custom_category (MonoString *name)
 static gboolean
 category_collect (SharedHeader *header, void *data)
 {
-       GSList **list = data;
+       GSList **list = (GSList **)data;
        if (header->ftype == FTYPE_CATEGORY) {
                *list = g_slist_prepend (*list, header);
        }
@@ -629,7 +715,7 @@ find_custom_counter (SharedCategory* cat, MonoString *name)
 typedef struct {
        unsigned int cat_offset;
        SharedCategory* cat;
-       MonoString *instance;
+       char *name;
        SharedInstance* result;
        GSList *list;
 } InstanceSearch;
@@ -637,12 +723,12 @@ typedef struct {
 static gboolean
 instance_search (SharedHeader *header, void *data)
 {
-       InstanceSearch *search = data;
+       InstanceSearch *search = (InstanceSearch *)data;
        if (header->ftype == FTYPE_INSTANCE) {
                SharedInstance *ins = (SharedInstance*)header;
                if (search->cat_offset == ins->category_offset) {
-                       if (search->instance) {
-                               if (mono_string_compare_ascii (search->instance, ins->instance_name) == 0) {
+                       if (search->name) {
+                               if (strcmp (search->name, ins->instance_name) == 0) {
                                        search->result = ins;
                                        return FALSE;
                                }
@@ -655,12 +741,12 @@ instance_search (SharedHeader *header, void *data)
 }
 
 static SharedInstance*
-find_custom_instance (SharedCategory* cat, MonoString *instance)
+find_custom_instance (SharedCategory* cat, char *name)
 {
        InstanceSearch search;
        search.cat_offset = (char*)cat - (char*)shared_area;
        search.cat = cat;
-       search.instance = instance;
+       search.name = name;
        search.list = NULL;
        search.result = NULL;
        foreach_shared_item (instance_search, &search);
@@ -673,7 +759,7 @@ get_custom_instances_list (SharedCategory* cat)
        InstanceSearch search;
        search.cat_offset = (char*)cat - (char*)shared_area;
        search.cat = cat;
-       search.instance = NULL;
+       search.name = NULL;
        search.list = NULL;
        search.result = NULL;
        foreach_shared_item (instance_search, &search);
@@ -712,16 +798,14 @@ fill_sample (MonoCounterSample *sample)
 }
 
 static int
-id_from_string (MonoString *instance, gboolean is_process)
+id_from_string (const gchar *id_str, gboolean is_process)
 {
        int id = -1;
-       if (mono_string_length (instance)) {
-               char *id_str = mono_string_to_utf8 (instance);
+       if (strcmp("", id_str) != 0) {
                char *end;
                id = strtol (id_str, &end, 0);
                if (end == id_str && !is_process)
                        id = -1;
-               g_free (id_str);
        }
        return id;
 }
@@ -759,7 +843,7 @@ get_cpu_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample *
 }
 
 static void*
-cpu_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBoolean *custom)
+cpu_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
 {
        int id = id_from_string (instance, FALSE) << 5;
        const CounterDesc *cdesc;
@@ -809,7 +893,7 @@ network_cleanup (ImplVtable *vtable)
        if (vtable == NULL)
                return;
 
-       narg = vtable->arg;
+       narg = (NetworkVtableArg *)vtable->arg;
        if (narg == NULL)
                return;
 
@@ -820,7 +904,7 @@ network_cleanup (ImplVtable *vtable)
 }
 
 static void*
-network_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBoolean *custom)
+network_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
 {
        const CounterDesc *cdesc;
        NetworkVtableArg *narg;
@@ -829,7 +913,7 @@ network_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBool
 
        *custom = FALSE;
        if ((cdesc = get_counter_in_category (&predef_categories [CATEGORY_NETWORK], counter))) {
-               instance_name = mono_string_to_utf8 (instance);
+               instance_name = g_strdup (instance);
                narg = g_new0 (NetworkVtableArg, 1);
                narg->id = cdesc->id;
                narg->name = instance_name;
@@ -881,7 +965,7 @@ get_process_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSamp
 }
 
 static void*
-process_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBoolean *custom)
+process_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
 {
        int id = id_from_string (instance, TRUE) << 5;
        const CounterDesc *cdesc;
@@ -906,17 +990,20 @@ mono_mem_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounterSample
        sample->counterType = predef_counters [predef_categories [CATEGORY_MONO_MEM].first_counter + id].type;
        switch (id) {
        case COUNTER_MEM_NUM_OBJECTS:
-               sample->rawValue = mono_stats.new_object_count;
+               sample->rawValue = 0;
                return TRUE;
        case COUNTER_MEM_PHYS_TOTAL:
                sample->rawValue = mono_determine_physical_ram_size ();;
                return TRUE;
+       case COUNTER_MEM_PHYS_AVAILABLE:
+               sample->rawValue = mono_determine_physical_ram_available_size ();;
+               return TRUE;
        }
        return FALSE;
 }
 
 static void*
-mono_mem_get_impl (MonoString* counter, MonoString* instance, int *type, MonoBoolean *custom)
+mono_mem_get_impl (MonoString* counter, const gchar* instance, int *type, MonoBoolean *custom)
 {
        const CounterDesc *cdesc;
        *custom = FALSE;
@@ -948,15 +1035,13 @@ predef_readonly_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounter
 }
 
 static ImplVtable*
-predef_vtable (void *arg, MonoString *instance)
+predef_vtable (void *arg, const gchar *pids)
 {
        MonoSharedArea *area;
        PredefVtable *vtable;
-       char *pids = mono_string_to_utf8 (instance);
        int pid;
 
        pid = atoi (pids);
-       g_free (pids);
        area = load_sarea_for_pid (pid);
        if (!area)
                return NULL;
@@ -989,52 +1074,52 @@ predef_writable_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounter
        case CATEGORY_EXC:
                switch (id) {
                case COUNTER_EXC_THROWN:
-                       sample->rawValue = mono_perfcounters->exceptions_thrown;
+                       sample->rawValue = InterlockedRead (&mono_perfcounters->exceptions_thrown);
                        return TRUE;
                }
                break;
        case CATEGORY_ASPNET:
                switch (id) {
                case COUNTER_ASPNET_REQ_Q:
-                       sample->rawValue = mono_perfcounters->aspnet_requests_queued;
+                       sample->rawValue = InterlockedRead (&mono_perfcounters->aspnet_requests_queued);
                        return TRUE;
                case COUNTER_ASPNET_REQ_TOTAL:
-                       sample->rawValue = mono_perfcounters->aspnet_requests;
+                       sample->rawValue = InterlockedRead (&mono_perfcounters->aspnet_requests);
                        return TRUE;
                }
                break;
        case CATEGORY_THREADPOOL:
                switch (id) {
                case COUNTER_THREADPOOL_WORKITEMS:
-                       sample->rawValue = mono_perfcounters->threadpool_workitems;
+                       sample->rawValue = InterlockedRead64 (&mono_perfcounters->threadpool_workitems);
                        return TRUE;
                case COUNTER_THREADPOOL_IOWORKITEMS:
-                       sample->rawValue = mono_perfcounters->threadpool_ioworkitems;
+                       sample->rawValue = InterlockedRead64 (&mono_perfcounters->threadpool_ioworkitems);
                        return TRUE;
                case COUNTER_THREADPOOL_THREADS:
-                       sample->rawValue = mono_perfcounters->threadpool_threads;
+                       sample->rawValue = InterlockedRead (&mono_perfcounters->threadpool_threads);
                        return TRUE;
                case COUNTER_THREADPOOL_IOTHREADS:
-                       sample->rawValue = mono_perfcounters->threadpool_iothreads;
+                       sample->rawValue = InterlockedRead (&mono_perfcounters->threadpool_iothreads);
                        return TRUE;
                }
                break;
        case CATEGORY_JIT:
                switch (id) {
                case COUNTER_JIT_BYTES:
-                       sample->rawValue = mono_perfcounters->jit_bytes;
+                       sample->rawValue = InterlockedRead (&mono_perfcounters->jit_bytes);
                        return TRUE;
                case COUNTER_JIT_METHODS:
-                       sample->rawValue = mono_perfcounters->jit_methods;
+                       sample->rawValue = InterlockedRead (&mono_perfcounters->jit_methods);
                        return TRUE;
                case COUNTER_JIT_TIME:
-                       sample->rawValue = mono_perfcounters->jit_time;
+                       sample->rawValue = InterlockedRead (&mono_perfcounters->jit_time);
                        return TRUE;
                case COUNTER_JIT_BYTES_PSEC:
-                       sample->rawValue = mono_perfcounters->jit_bytes;
+                       sample->rawValue = InterlockedRead (&mono_perfcounters->jit_bytes);
                        return TRUE;
                case COUNTER_JIT_FAILURES:
-                       sample->rawValue = mono_perfcounters->jit_failures;
+                       sample->rawValue = InterlockedRead (&mono_perfcounters->jit_failures);
                        return TRUE;
                }
                break;
@@ -1045,7 +1130,7 @@ predef_writable_counter (ImplVtable *vtable, MonoBoolean only_value, MonoCounter
 static gint64
 predef_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
 {
-       guint32 *volatile ptr = NULL;
+       gint32 *volatile ptr = NULL;
        gint64 *volatile ptr64 = NULL;
        int cat_id = GPOINTER_TO_INT (vtable->arg);
        int id = cat_id >> 16;
@@ -1059,8 +1144,8 @@ predef_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
                break;
        case CATEGORY_THREADPOOL:
                switch (id) {
-               case COUNTER_THREADPOOL_WORKITEMS: ptr64 = (gint64 *) &mono_perfcounters->threadpool_workitems; break;
-               case COUNTER_THREADPOOL_IOWORKITEMS: ptr64 = (gint64 *) &mono_perfcounters->threadpool_ioworkitems; break;
+               case COUNTER_THREADPOOL_WORKITEMS: ptr64 = &mono_perfcounters->threadpool_workitems; break;
+               case COUNTER_THREADPOOL_IOWORKITEMS: ptr64 = &mono_perfcounters->threadpool_ioworkitems; break;
                case COUNTER_THREADPOOL_THREADS: ptr = &mono_perfcounters->threadpool_threads; break;
                case COUNTER_THREADPOOL_IOTHREADS: ptr = &mono_perfcounters->threadpool_iothreads; break;
                }
@@ -1069,29 +1154,23 @@ predef_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
        if (ptr) {
                if (do_incr) {
                        if (value == 1)
-                               return InterlockedIncrement ((gint32 *) ptr); /* FIXME: sign */
+                               return InterlockedIncrement (ptr);
                        if (value == -1)
-                               return InterlockedDecrement ((gint32 *) ptr); /* FIXME: sign */
+                               return InterlockedDecrement (ptr);
 
-                       *ptr += value;
-                       return *ptr;
+                       return InterlockedAdd(ptr, value);
                }
                /* this can be non-atomic */
                *ptr = value;
                return value;
        } else if (ptr64) {
                if (do_incr) {
-                       /* FIXME: we need to do this atomically */
-                       /* No InterlockedIncrement64() yet */
-                       /*
                        if (value == 1)
-                               return InterlockedIncrement64 (ptr);
+                               return UnlockedIncrement64 (ptr64); /* FIXME: use InterlockedIncrement64 () */
                        if (value == -1)
-                               return InterlockedDecrement64 (ptr);
-                       */
+                               return UnlockedDecrement64 (ptr64); /* FIXME: use InterlockedDecrement64 () */
 
-                       *ptr64 += value;
-                       return *ptr64;
+                       return UnlockedAdd64 (ptr64, value); /* FIXME: use InterlockedAdd64 () */
                }
                /* this can be non-atomic */
                *ptr64 = value;
@@ -1101,13 +1180,13 @@ predef_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
 }
 
 static void*
-predef_writable_get_impl (int cat, MonoString* counter, MonoString* instance, int *type, MonoBoolean *custom)
+predef_writable_get_impl (int cat, MonoString* counter, const gchar *instance, int *type, MonoBoolean *custom)
 {
        const CounterDesc *cdesc;
        *custom = TRUE;
        if ((cdesc = get_counter_in_category (&predef_categories [cat], counter))) {
                *type = cdesc->type;
-               if (instance == NULL || mono_string_compare_ascii (instance, "") == 0)
+               if (instance == NULL || strcmp (instance, "") == 0)
                        return create_vtable (GINT_TO_POINTER ((cdesc->id << 16) | cat), predef_writable_counter, predef_writable_update);
                else
                        return predef_vtable (GINT_TO_POINTER ((cdesc->id << 16) | cat), instance);
@@ -1135,7 +1214,7 @@ static gint64
 custom_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
 {
        /* FIXME: check writability */
-       guint64 *ptr = vtable->arg;
+       guint64 *ptr = (guint64 *)vtable->arg;
        if (ptr) {
                if (do_incr) {
                        /* FIXME: we need to do this atomically */
@@ -1150,20 +1229,17 @@ custom_writable_update (ImplVtable *vtable, MonoBoolean do_incr, gint64 value)
 }
 
 static SharedInstance*
-custom_get_instance (SharedCategory *cat, SharedCounter *scounter, MonoString* instance)
+custom_get_instance (SharedCategory *cat, SharedCounter *scounter, char* name)
 {
        SharedInstance* inst;
        char *p;
-       int size, data_offset;
-       char *name;
-       inst = find_custom_instance (cat, instance);
+       int size;
+       inst = find_custom_instance (cat, name);
        if (inst)
                return inst;
-       name = mono_string_to_utf8 (instance);
        size = sizeof (SharedInstance) + strlen (name);
        size += 7;
        size &= ~7;
-       data_offset = size;
        size += (sizeof (guint64) * cat->num_counters);
        perfctr_lock ();
        inst = (SharedInstance*) shared_data_reserve_room (size, FTYPE_INSTANCE);
@@ -1179,7 +1255,6 @@ custom_get_instance (SharedCategory *cat, SharedCounter *scounter, MonoString* i
        strcpy (p, name);
        p += strlen (name) + 1;
        perfctr_unlock ();
-       g_free (name);
 
        return inst;
 }
@@ -1198,24 +1273,35 @@ custom_vtable (SharedCounter *scounter, SharedInstance* inst, char *data)
        return (ImplVtable*)vtable;
 }
 
+static gpointer
+custom_get_value_address (SharedCounter *scounter, SharedInstance* sinst)
+{
+       int offset = sizeof (SharedInstance) + strlen (sinst->instance_name);
+       offset += 7;
+       offset &= ~7;
+       offset += scounter->seq_num * sizeof (guint64);
+       return (char*)sinst + offset;
+}
+
 static void*
-custom_get_impl (SharedCategory *cat, MonoString* counter, MonoString* instance, int *type)
+custom_get_impl (SharedCategory *cat, MonoString *counter, MonoString* instance, int *type, MonoError *error)
 {
        SharedCounter *scounter;
        SharedInstance* inst;
-       int size;
+       char *name;
 
+       error_init (error);
        scounter = find_custom_counter (cat, counter);
        if (!scounter)
                return NULL;
+       name = mono_string_to_utf8_checked (counter, error);
+       return_val_if_nok (error, NULL);
        *type = simple_type_to_type [scounter->type];
-       inst = custom_get_instance (cat, scounter, instance);
+       inst = custom_get_instance (cat, scounter, name);
+       g_free (name);
        if (!inst)
                return NULL;
-       size = sizeof (SharedInstance) + strlen (inst->instance_name);
-       size += 7;
-       size &= ~7;
-       return custom_vtable (scounter, inst, (char*)inst + size + scounter->seq_num * sizeof (guint64));
+       return custom_vtable (scounter, inst, (char *)custom_get_value_address (scounter, inst));
 }
 
 static const CategoryDesc*
@@ -1233,7 +1319,9 @@ void*
 mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString* instance,
                MonoString* machine, int *type, MonoBoolean *custom)
 {
+       MonoError error;
        const CategoryDesc *cdesc;
+       void *result = NULL;
        /* no support for counters on other machines */
        if (mono_string_compare_ascii (machine, "."))
                return NULL;
@@ -1243,17 +1331,27 @@ mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString
                if (!scat)
                        return NULL;
                *custom = TRUE;
-               return custom_get_impl (scat, counter, instance, type);
+               result = custom_get_impl (scat, counter, instance, type, &error);
+               if (mono_error_set_pending_exception (&error))
+                       return NULL;
+               return result;
        }
+       gchar *c_instance = mono_string_to_utf8_checked (instance, &error);
+       if (mono_error_set_pending_exception (&error))
+               return NULL;
        switch (cdesc->id) {
        case CATEGORY_CPU:
-               return cpu_get_impl (counter, instance, type, custom);
+               result = cpu_get_impl (counter, c_instance, type, custom);
+               break;
        case CATEGORY_PROC:
-               return process_get_impl (counter, instance, type, custom);
+               result = process_get_impl (counter, c_instance, type, custom);
+               break;
        case CATEGORY_MONO_MEM:
-               return mono_mem_get_impl (counter, instance, type, custom);
+               result = mono_mem_get_impl (counter, c_instance, type, custom);
+               break;
        case CATEGORY_NETWORK:
-               return network_get_impl (counter, instance, type, custom);
+               result = network_get_impl (counter, c_instance, type, custom);
+               break;
        case CATEGORY_JIT:
        case CATEGORY_EXC:
        case CATEGORY_GC:
@@ -1264,15 +1362,17 @@ mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString
        case CATEGORY_SECURITY:
        case CATEGORY_ASPNET:
        case CATEGORY_THREADPOOL:
-               return predef_writable_get_impl (cdesc->id, counter, instance, type, custom);
+               result = predef_writable_get_impl (cdesc->id, counter, c_instance, type, custom);
+               break;
        }
-       return NULL;
+       g_free (c_instance);
+       return result;
 }
 
 MonoBoolean
 mono_perfcounter_get_sample (void *impl, MonoBoolean only_value, MonoCounterSample *sample)
 {
-       ImplVtable *vtable = impl;
+       ImplVtable *vtable = (ImplVtable *)impl;
        if (vtable && vtable->sample)
                return vtable->sample (vtable, only_value, sample);
        return FALSE;
@@ -1281,7 +1381,7 @@ mono_perfcounter_get_sample (void *impl, MonoBoolean only_value, MonoCounterSamp
 gint64
 mono_perfcounter_update_value (void *impl, MonoBoolean do_incr, gint64 value)
 {
-       ImplVtable *vtable = impl;
+       ImplVtable *vtable = (ImplVtable *)impl;
        if (vtable && vtable->update)
                return vtable->update (vtable, do_incr, value);
        return 0;
@@ -1290,7 +1390,7 @@ mono_perfcounter_update_value (void *impl, MonoBoolean do_incr, gint64 value)
 void
 mono_perfcounter_free_data (void *impl)
 {
-       ImplVtable *vtable = impl;
+       ImplVtable *vtable = (ImplVtable *)impl;
        if (vtable && vtable->cleanup)
                vtable->cleanup (vtable);
        g_free (impl);
@@ -1318,10 +1418,14 @@ mono_perfcounter_category_del (MonoString *name)
        return TRUE;
 }
 
+/* this is an icall */
 MonoString*
 mono_perfcounter_category_help (MonoString *category, MonoString *machine)
 {
+       MonoError error;
+       MonoString *result = NULL;
        const CategoryDesc *cdesc;
+       error_init (&error);
        /* no support for counters on other machines */
        if (mono_string_compare_ascii (machine, "."))
                return NULL;
@@ -1330,9 +1434,15 @@ mono_perfcounter_category_help (MonoString *category, MonoString *machine)
                SharedCategory *scat = find_custom_category (category);
                if (!scat)
                        return NULL;
-               return mono_string_new (mono_domain_get (), custom_category_help (scat));
+               result = mono_string_new_checked (mono_domain_get (), custom_category_help (scat), &error);
+               if (mono_error_set_pending_exception (&error))
+                       return NULL;
+               return result;
        }
-       return mono_string_new (mono_domain_get (), cdesc->help);
+       result = mono_string_new_checked (mono_domain_get (), cdesc->help, &error);
+       if (mono_error_set_pending_exception (&error))
+               return NULL;
+       return result;
 }
 
 /*
@@ -1392,7 +1502,6 @@ mono_perfcounter_create (MonoString *category, MonoString *help, int type, MonoA
        SharedCategory *cat;
 
        /* FIXME: ensure there isn't a category created already */
-       mono_error_init (&error);
        name = mono_string_to_utf8_checked (category, &error);
        if (!mono_error_ok (&error))
                goto failure;
@@ -1465,7 +1574,10 @@ failure:
 int
 mono_perfcounter_instance_exists (MonoString *instance, MonoString *category, MonoString *machine)
 {
+       MonoError error;
        const CategoryDesc *cdesc;
+       SharedInstance *sinst;
+       char *name;
        /* no support for counters on other machines */
        /*FIXME: machine appears to be wrong
        if (mono_string_compare_ascii (machine, "."))
@@ -1476,7 +1588,12 @@ mono_perfcounter_instance_exists (MonoString *instance, MonoString *category, Mo
                scat = find_custom_category (category);
                if (!scat)
                        return FALSE;
-               if (find_custom_instance (scat, instance))
+               name = mono_string_to_utf8_checked (instance, &error);
+               if (mono_error_set_pending_exception (&error))
+                       return FALSE;
+               sinst = find_custom_instance (scat, name);
+               g_free (name);
+               if (sinst)
                        return TRUE;
        } else {
                /* FIXME: search instance */
@@ -1484,50 +1601,77 @@ mono_perfcounter_instance_exists (MonoString *instance, MonoString *category, Mo
        return FALSE;
 }
 
+/* this is an icall */
 MonoArray*
 mono_perfcounter_category_names (MonoString *machine)
 {
+       MonoError error;
        int i;
        MonoArray *res;
        MonoDomain *domain = mono_domain_get ();
        GSList *custom_categories, *tmp;
        /* no support for counters on other machines */
-       if (mono_string_compare_ascii (machine, "."))
-               return mono_array_new (domain, mono_get_string_class (), 0);
+       if (mono_string_compare_ascii (machine, ".")) {
+               res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
+               mono_error_set_pending_exception (&error);
+               return res;
+       }
        perfctr_lock ();
        custom_categories = get_custom_categories ();
-       res = mono_array_new (domain, mono_get_string_class (), NUM_CATEGORIES + g_slist_length (custom_categories));
+       res = mono_array_new_checked (domain, mono_get_string_class (), NUM_CATEGORIES + g_slist_length (custom_categories), &error);
+       if (mono_error_set_pending_exception (&error)) {
+               perfctr_unlock ();
+               return NULL;
+       }
+
        for (i = 0; i < NUM_CATEGORIES; ++i) {
                const CategoryDesc *cdesc = &predef_categories [i];
-               mono_array_setref (res, i, mono_string_new (domain, cdesc->name));
+               MonoString *name = mono_string_new_checked (domain, cdesc->name, &error);
+               if (!is_ok (&error))
+                       goto leave;
+               mono_array_setref (res, i, name);
        }
        for (tmp = custom_categories; tmp; tmp = tmp->next) {
-               SharedCategory *scat = tmp->data;
-               mono_array_setref (res, i, mono_string_new (domain, scat->name));
+               SharedCategory *scat = (SharedCategory *)tmp->data;
+               MonoString *name = mono_string_new_checked (domain, scat->name, &error);
+               if (!is_ok (&error))
+                       goto leave;
+               mono_array_setref (res, i, name);
                i++;
        }
+leave:
        perfctr_unlock ();
        g_slist_free (custom_categories);
+       mono_error_set_pending_exception (&error);
        return res;
 }
 
 MonoArray*
 mono_perfcounter_counter_names (MonoString *category, MonoString *machine)
 {
+       MonoError error;
        int i;
        SharedCategory *scat;
        const CategoryDesc *cdesc;
        MonoArray *res;
        MonoDomain *domain = mono_domain_get ();
        /* no support for counters on other machines */
-       if (mono_string_compare_ascii (machine, "."))
-               return mono_array_new (domain, mono_get_string_class (), 0);
+       if (mono_string_compare_ascii (machine, ".")) {
+               res =  mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
+               mono_error_set_pending_exception (&error);
+               return res;
+       }
        cdesc = find_category (category);
        if (cdesc) {
-               res = mono_array_new (domain, mono_get_string_class (), cdesc [1].first_counter - cdesc->first_counter);
+               res = mono_array_new_checked (domain, mono_get_string_class (), cdesc [1].first_counter - cdesc->first_counter, &error);
+               if (mono_error_set_pending_exception (&error))
+                       return NULL;
                for (i = cdesc->first_counter; i < cdesc [1].first_counter; ++i) {
                        const CounterDesc *desc = &predef_counters [i];
-                       mono_array_setref (res, i - cdesc->first_counter, mono_string_new (domain, desc->name));
+                       MonoString *name = mono_string_new_checked (domain, desc->name, &error);
+                       if (mono_error_set_pending_exception (&error))
+                               return NULL;
+                       mono_array_setref (res, i - cdesc->first_counter, name);
                }
                return res;
        }
@@ -1536,26 +1680,37 @@ mono_perfcounter_counter_names (MonoString *category, MonoString *machine)
        if (scat) {
                char *p = custom_category_counters (scat);
                int i;
-               res = mono_array_new (domain, mono_get_string_class (), scat->num_counters);
+               res = mono_array_new_checked (domain, mono_get_string_class (), scat->num_counters, &error);
+               if (mono_error_set_pending_exception (&error)) {
+                       perfctr_unlock ();
+                       return NULL;
+               }
+
                for (i = 0; i < scat->num_counters; ++i) {
-                       mono_array_setref (res, i, mono_string_new (domain, p + 1));
+                       MonoString *str = mono_string_new_checked (domain, p + 1, &error);
+                       if (!is_ok (&error))
+                               goto leave;
+                       mono_array_setref (res, i, str);
                        p += 2; /* skip counter type */
                        p += strlen (p) + 1; /* skip counter name */
                        p += strlen (p) + 1; /* skip counter help */
                }
-               perfctr_unlock ();
-               return res;
-       }
+       } else
+               res = mono_array_new_checked (domain, mono_get_string_class (), 0, &error);
+leave:
        perfctr_unlock ();
-       return mono_array_new (domain, mono_get_string_class (), 0);
+       mono_error_set_pending_exception (&error);
+       return res;
 }
 
 static MonoArray*
-get_string_array (void **array, int count, gboolean is_process)
+get_string_array (void **array, int count, gboolean is_process, MonoError *error)
 {
        int i;
        MonoDomain *domain = mono_domain_get ();
-       MonoArray * res = mono_array_new (mono_domain_get (), mono_get_string_class (), count);
+       error_init (error);
+       MonoArray * res = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), count, error);
+       return_val_if_nok (error, NULL);
        for (i = 0; i < count; ++i) {
                char buf [128];
                char *p;
@@ -1566,132 +1721,226 @@ get_string_array (void **array, int count, gboolean is_process)
                        sprintf (buf, "%d", GPOINTER_TO_INT (array [i]));
                        p = buf;
                }
-               mono_array_setref (res, i, mono_string_new (domain, p));
+               MonoString *str = mono_string_new_checked (domain, p, error);
                if (p != buf)
                        g_free (p);
+               return_val_if_nok (error, NULL);
+               mono_array_setref (res, i, str);
        }
        return res;
 }
 
 static MonoArray*
-get_string_array_of_strings (void **array, int count)
+get_string_array_of_strings (void **array, int count, MonoError *error)
 {
        int i;
        MonoDomain *domain = mono_domain_get ();
-       MonoArray * res = mono_array_new (mono_domain_get (), mono_get_string_class (), count);
+       error_init (error);
+       MonoArray * res = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), count, error);
+       return_val_if_nok (error, NULL);
        for (i = 0; i < count; ++i) {
-               char* p = array[i];
-               mono_array_setref (res, i, mono_string_new (domain, p));
+               char* p = (char *)array[i];
+               MonoString *str = mono_string_new_checked (domain, p, error);
+               return_val_if_nok (error, NULL);
+               mono_array_setref (res, i, str);
        }
 
        return res;
 }
 
 static MonoArray*
-get_mono_instances (void)
+get_mono_instances (MonoError *error)
 {
        int count = 64;
        int res;
        void **buf = NULL;
        MonoArray *array;
+       error_init (error);
        do {
                count *= 2;
                g_free (buf);
                buf = g_new (void*, count);
                res = mono_shared_area_instances (buf, count);
        } while (res == count);
-       array = get_string_array (buf, res, TRUE);
+       array = get_string_array (buf, res, TRUE, error);
        g_free (buf);
        return array;
 }
 
 static MonoArray*
-get_cpu_instances (void)
+get_cpu_instances (MonoError *error)
 {
        void **buf = NULL;
        int i, count;
        MonoArray *array;
-
+       error_init (error);
        count = mono_cpu_count () + 1; /* +1 for "_Total" */
        buf = g_new (void*, count);
        for (i = 0; i < count; ++i)
                buf [i] = GINT_TO_POINTER (i - 1); /* -1 => _Total */
-       array = get_string_array (buf, count, FALSE);
+       array = get_string_array (buf, count, FALSE, error);
        g_free (buf);
-       mono_array_setref (array, 0, mono_string_new (mono_domain_get (), "_Total"));
+       MonoString *total = mono_string_new_checked (mono_domain_get (), "_Total", error);
+       return_val_if_nok (error, NULL);
+       mono_array_setref (array, 0, total);
        return array;
 }
 
 static MonoArray*
-get_processes_instances (void)
+get_processes_instances (MonoError *error)
 {
        MonoArray *array;
        int count = 0;
        void **buf = mono_process_list (&count);
+       error_init (error);
        if (!buf)
-               return get_string_array (NULL, 0, FALSE);
-       array = get_string_array (buf, count, TRUE);
+               return get_string_array (NULL, 0, FALSE, error);
+       array = get_string_array (buf, count, TRUE, error);
        g_free (buf);
        return array;
 }
 
 static MonoArray*
-get_networkinterface_instances (void)
+get_networkinterface_instances (MonoError *error)
 {
        MonoArray *array;
        int count = 0;
+       error_init (error);
        void **buf = mono_networkinterface_list (&count);
        if (!buf)
-               return get_string_array_of_strings (NULL, 0);
-       array = get_string_array_of_strings (buf, count);
+               return get_string_array_of_strings (NULL, 0, error);
+       array = get_string_array_of_strings (buf, count, error);
        g_strfreev ((char **) buf);
        return array;
 }
 
 static MonoArray*
-get_custom_instances (MonoString *category)
+get_custom_instances (MonoString *category, MonoError *error)
 {
        SharedCategory *scat;
+       error_init (error);
        scat = find_custom_category (category);
        if (scat) {
                GSList *list = get_custom_instances_list (scat);
                GSList *tmp;
                int i = 0;
-               MonoArray *array = mono_array_new (mono_domain_get (), mono_get_string_class (), g_slist_length (list));
+               MonoArray *array = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), g_slist_length (list), error);
+               if (!is_ok (error)) {
+                       g_slist_free (list);
+                       return NULL;
+               }
                for (tmp = list; tmp; tmp = tmp->next) {
-                       SharedInstance *inst = tmp->data;
-                       mono_array_setref (array, i, mono_string_new (mono_domain_get (), inst->instance_name));
+                       SharedInstance *inst = (SharedInstance *)tmp->data;
+                       MonoString *str = mono_string_new_checked (mono_domain_get (), inst->instance_name, error);
+                       if (!is_ok (error)) {
+                               g_slist_free (list);
+                               return NULL;
+                       }
+                       mono_array_setref (array, i, str);
                        i++;
                }
                g_slist_free (list);
                return array;
        }
-       return mono_array_new (mono_domain_get (), mono_get_string_class (), 0);
+       return mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, error);
 }
 
 MonoArray*
 mono_perfcounter_instance_names (MonoString *category, MonoString *machine)
 {
+       MonoError error;
        const CategoryDesc* cat;
-       if (mono_string_compare_ascii (machine, "."))
-               return mono_array_new (mono_domain_get (), mono_get_string_class (), 0);
+       MonoArray *result = NULL;
+       if (mono_string_compare_ascii (machine, ".")) {
+               result = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, &error);
+               mono_error_set_pending_exception (&error);
+               return result;
+       }
+       
        cat = find_category (category);
-       if (!cat)
-               return get_custom_instances (category);
+       if (!cat) {
+               MonoArray *result = get_custom_instances (category, &error);
+               mono_error_set_pending_exception (&error);
+               return result;
+       }
        switch (cat->instance_type) {
        case MonoInstance:
-               return get_mono_instances ();
+               result = get_mono_instances (&error);
+               break;
        case CPUInstance:
-               return get_cpu_instances ();
+               result = get_cpu_instances (&error);
+               break;
        case ProcessInstance:
-               return get_processes_instances ();
+               result = get_processes_instances (&error);
+               break;
        case NetworkInterfaceInstance:
-               return get_networkinterface_instances ();
+               result = get_networkinterface_instances (&error);
+               break;
        case ThreadInstance:
        default:
-               return mono_array_new (mono_domain_get (), mono_get_string_class (), 0);
+               result = mono_array_new_checked (mono_domain_get (), mono_get_string_class (), 0, &error);
+       }
+       mono_error_set_pending_exception (&error);
+       return result;
+}
+
+typedef struct {
+       PerfCounterEnumCallback cb;
+       void *data;
+} PerfCounterForeachData;
+
+static gboolean
+mono_perfcounter_foreach_shared_item (SharedHeader *header, gpointer data)
+{
+       int i;
+       char *p, *name;
+       unsigned char type;
+       void *addr;
+       SharedCategory *cat;
+       SharedCounter *counter;
+       SharedInstance *inst;
+       PerfCounterForeachData *foreach_data = (PerfCounterForeachData *)data;
+
+       if (header->ftype == FTYPE_CATEGORY) {
+               cat = (SharedCategory*)header;
+
+               p = cat->name;
+               p += strlen (p) + 1; /* skip category name */
+               p += strlen (p) + 1; /* skip category help */
+
+               for (i = 0; i < cat->num_counters; ++i) {
+                       counter = (SharedCounter*) p;
+                       type = (unsigned char)*p++;
+                       /* seq_num = (int)* */ p++;
+                       name = p;
+                       p += strlen (p) + 1;
+                       /* help = p; */
+                       p += strlen (p) + 1;
+
+                       inst = custom_get_instance (cat, counter, name);
+                       if (!inst)
+                               return FALSE;
+                       addr = custom_get_value_address (counter, inst);
+                       if (!foreach_data->cb (cat->name, name, type, addr ? *(gint64*)addr : 0, foreach_data->data))
+                               return FALSE;
+               }
        }
+
+       return TRUE;
 }
+
+void
+mono_perfcounter_foreach (PerfCounterEnumCallback cb, gpointer data)
+{
+       PerfCounterForeachData foreach_data = { cb, data };
+
+       perfctr_lock ();
+
+       foreach_shared_item (mono_perfcounter_foreach_shared_item, &foreach_data);
+
+       perfctr_unlock ();
+}
+
 #else
 void*
 mono_perfcounter_get_impl (MonoString* category, MonoString* counter, MonoString* instance, MonoString* machine, int *type, MonoBoolean *custom)