pdh: Serialize access to performance counters and queries.
diff --git a/dlls/pdh/pdh_main.c b/dlls/pdh/pdh_main.c
index e49e64e..8d5c081 100644
--- a/dlls/pdh/pdh_main.c
+++ b/dlls/pdh/pdh_main.c
@@ -37,6 +37,16 @@
WINE_DEFAULT_DEBUG_CHANNEL(pdh);
+static CRITICAL_SECTION pdh_handle_cs;
+static CRITICAL_SECTION_DEBUG pdh_handle_cs_debug =
+{
+ 0, 0, &pdh_handle_cs,
+ { &pdh_handle_cs_debug.ProcessLocksList,
+ &pdh_handle_cs_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": pdh_handle_cs") }
+};
+static CRITICAL_SECTION pdh_handle_cs = { &pdh_handle_cs_debug, -1, 0, 0, 0, 0 };
+
static inline void *pdh_alloc( SIZE_T size )
{
return HeapAlloc( GetProcessHeap(), 0, size );
@@ -88,7 +98,8 @@
struct counter
{
- struct list entry;
+ DWORD magic; /* signature */
+ struct list entry; /* list entry */
WCHAR *path; /* identifier */
DWORD type; /* counter type */
DWORD status; /* update status */
@@ -113,14 +124,27 @@
} two; /* second value */
};
+#define PDH_MAGIC_COUNTER 0x50444831 /* 'PDH1' */
+
static struct counter *create_counter( void )
{
struct counter *counter;
- if ((counter = pdh_alloc_zero( sizeof(struct counter) ))) return counter;
+ if ((counter = pdh_alloc_zero( sizeof(struct counter) )))
+ {
+ counter->magic = PDH_MAGIC_COUNTER;
+ return counter;
+ }
return NULL;
}
+static void destroy_counter( struct counter *counter )
+{
+ counter->magic = 0;
+ pdh_free( counter->path );
+ pdh_free( counter );
+}
+
#define PDH_MAGIC_QUERY 0x50444830 /* 'PDH0' */
struct query
@@ -143,6 +167,12 @@
return NULL;
}
+static void destroy_query( struct query *query )
+{
+ query->magic = 0;
+ pdh_free( query );
+}
+
struct source
{
DWORD index; /* name index */
@@ -230,7 +260,13 @@
TRACE("%p %s %lx %p\n", hquery, debugstr_w(path), userdata, hcounter);
if (!path || !hcounter) return PDH_INVALID_ARGUMENT;
- if (!query || (query->magic != PDH_MAGIC_QUERY)) return PDH_INVALID_HANDLE;
+
+ EnterCriticalSection( &pdh_handle_cs );
+ if (!query || query->magic != PDH_MAGIC_QUERY)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_HANDLE;
+ }
*hcounter = NULL;
for (i = 0; i < sizeof(counter_sources) / sizeof(counter_sources[0]); i++)
@@ -248,13 +284,16 @@
counter->user = userdata;
list_add_tail( &query->counters, &counter->entry );
-
*hcounter = counter;
+
+ LeaveCriticalSection( &pdh_handle_cs );
return ERROR_SUCCESS;
}
+ LeaveCriticalSection( &pdh_handle_cs );
return PDH_MEMORY_ALLOCATION_FAILURE;
}
}
+ LeaveCriticalSection( &pdh_handle_cs );
return PDH_CSTATUS_NO_COUNTER;
}
@@ -286,36 +325,32 @@
TRACE("%p\n", handle);
- if (!query || (query->magic != PDH_MAGIC_QUERY)) return PDH_INVALID_HANDLE;
+ EnterCriticalSection( &pdh_handle_cs );
+ if (!query || query->magic != PDH_MAGIC_QUERY)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_HANDLE;
+ }
LIST_FOR_EACH_SAFE( item, next, &query->counters )
{
struct counter *counter = LIST_ENTRY( item, struct counter, entry );
list_remove( &counter->entry );
-
- pdh_free( counter->path );
- pdh_free( counter );
+ destroy_counter( counter );
}
- query->magic = 0;
- pdh_free( query );
+ destroy_query( query );
+ LeaveCriticalSection( &pdh_handle_cs );
return ERROR_SUCCESS;
}
-/***********************************************************************
- * PdhCollectQueryData (PDH.@)
- */
-PDH_STATUS WINAPI PdhCollectQueryData( PDH_HQUERY handle )
+/* caller must hold query lock */
+static void collect_query_data( struct query *query )
{
- struct query *query = handle;
struct list *item;
- TRACE("%p\n", handle);
-
- if (!query || (query->magic != PDH_MAGIC_QUERY)) return PDH_INVALID_HANDLE;
-
LIST_FOR_EACH( item, &query->counters )
{
SYSTEMTIME time;
@@ -326,6 +361,33 @@
GetLocalTime( &time );
SystemTimeToFileTime( &time, &counter->stamp );
}
+}
+
+/***********************************************************************
+ * PdhCollectQueryData (PDH.@)
+ */
+PDH_STATUS WINAPI PdhCollectQueryData( PDH_HQUERY handle )
+{
+ struct query *query = handle;
+
+ TRACE("%p\n", handle);
+
+ EnterCriticalSection( &pdh_handle_cs );
+ if (!query || query->magic != PDH_MAGIC_QUERY)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_HANDLE;
+ }
+
+ if (list_empty( &query->counters ))
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_NO_DATA;
+ }
+
+ collect_query_data( query );
+
+ LeaveCriticalSection( &pdh_handle_cs );
return ERROR_SUCCESS;
}
@@ -334,24 +396,33 @@
*/
PDH_STATUS WINAPI PdhCollectQueryDataWithTime( PDH_HQUERY handle, LONGLONG *timestamp )
{
- PDH_STATUS ret;
struct query *query = handle;
TRACE("%p %p\n", handle, timestamp);
- if (!query || (query->magic != PDH_MAGIC_QUERY)) return PDH_INVALID_HANDLE;
+ EnterCriticalSection( &pdh_handle_cs );
+ if (!query || query->magic != PDH_MAGIC_QUERY)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_HANDLE;
+ }
+ if (list_empty( &query->counters ))
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_NO_DATA;
+ }
- if (list_empty( &query->counters )) return PDH_NO_DATA;
+ collect_query_data( query );
- ret = PdhCollectQueryData( query );
- if (!ret && timestamp)
+ if (timestamp)
{
struct list *item = list_head( &query->counters );
struct counter *counter = LIST_ENTRY( item, struct counter, entry );
*timestamp = ((LONGLONG)counter->stamp.dwHighDateTime << 32) | counter->stamp.dwLowDateTime;
}
- return ret;
+ LeaveCriticalSection( &pdh_handle_cs );
+ return ERROR_SUCCESS;
}
/***********************************************************************
@@ -363,12 +434,21 @@
TRACE("%p %d %p %p\n", handle, text, size, info);
- if (!counter) return PDH_INVALID_HANDLE;
- if (!size) return PDH_INVALID_ARGUMENT;
-
+ EnterCriticalSection( &pdh_handle_cs );
+ if (!counter || counter->magic != PDH_MAGIC_COUNTER)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_HANDLE;
+ }
+ if (!size)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_ARGUMENT;
+ }
if (*size < sizeof(PDH_COUNTER_INFO_A))
{
*size = sizeof(PDH_COUNTER_INFO_A);
+ LeaveCriticalSection( &pdh_handle_cs );
return PDH_MORE_DATA;
}
@@ -382,6 +462,8 @@
info->dwQueryUserData = counter->queryuser;
*size = sizeof(PDH_COUNTER_INFO_A);
+
+ LeaveCriticalSection( &pdh_handle_cs );
return ERROR_SUCCESS;
}
@@ -394,12 +476,21 @@
TRACE("%p %d %p %p\n", handle, text, size, info);
- if (!counter) return PDH_INVALID_HANDLE;
- if (!size) return PDH_INVALID_ARGUMENT;
-
+ EnterCriticalSection( &pdh_handle_cs );
+ if (!counter || counter->magic != PDH_MAGIC_COUNTER)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_HANDLE;
+ }
+ if (!size)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_ARGUMENT;
+ }
if (*size < sizeof(PDH_COUNTER_INFO_W))
{
*size = sizeof(PDH_COUNTER_INFO_W);
+ LeaveCriticalSection( &pdh_handle_cs );
return PDH_MORE_DATA;
}
@@ -413,6 +504,8 @@
info->dwQueryUserData = counter->queryuser;
*size = sizeof(PDH_COUNTER_INFO_W);
+
+ LeaveCriticalSection( &pdh_handle_cs );
return ERROR_SUCCESS;
}
@@ -425,10 +518,18 @@
TRACE("%p %p\n", handle, base);
- if (!base) return PDH_INVALID_ARGUMENT;
- if (!counter) return PDH_INVALID_HANDLE;
+ if (!base) return PDH_INVALID_ARGUMENT;
+
+ EnterCriticalSection( &pdh_handle_cs );
+ if (!counter || counter->magic != PDH_MAGIC_COUNTER)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_HANDLE;
+ }
*base = counter->base;
+
+ LeaveCriticalSection( &pdh_handle_cs );
return ERROR_SUCCESS;
}
@@ -443,10 +544,19 @@
TRACE("%p %x %p %p\n", handle, format, type, value);
- if (!value) return PDH_INVALID_ARGUMENT;
- if (!counter) return PDH_INVALID_HANDLE;
+ if (!value) return PDH_INVALID_ARGUMENT;
- if (counter->status) return PDH_INVALID_DATA;
+ EnterCriticalSection( &pdh_handle_cs );
+ if (!counter || counter->magic != PDH_MAGIC_COUNTER)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_HANDLE;
+ }
+ if (counter->status)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_DATA;
+ }
factor = counter->scale ? counter->scale : counter->defaultscale;
if (format & PDH_FMT_LONG)
@@ -467,11 +577,13 @@
else
{
WARN("unknown format %x\n", format);
+ LeaveCriticalSection( &pdh_handle_cs );
return PDH_INVALID_ARGUMENT;
}
value->CStatus = ERROR_SUCCESS;
-
if (type) *type = counter->type;
+
+ LeaveCriticalSection( &pdh_handle_cs );
return ERROR_SUCCESS;
}
@@ -485,8 +597,14 @@
TRACE("%p %p %p\n", handle, type, value);
- if (!value) return PDH_INVALID_ARGUMENT;
- if (!counter) return PDH_INVALID_HANDLE;
+ if (!value) return PDH_INVALID_ARGUMENT;
+
+ EnterCriticalSection( &pdh_handle_cs );
+ if (!counter || counter->magic != PDH_MAGIC_COUNTER)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_HANDLE;
+ }
value->CStatus = counter->status;
value->TimeStamp.dwLowDateTime = counter->stamp.dwLowDateTime;
@@ -496,6 +614,8 @@
value->MultiCount = 1; /* FIXME */
if (type) *type = counter->type;
+
+ LeaveCriticalSection( &pdh_handle_cs );
return ERROR_SUCCESS;
}
@@ -675,13 +795,17 @@
TRACE("%p\n", handle);
- if (!counter) return PDH_INVALID_HANDLE;
+ EnterCriticalSection( &pdh_handle_cs );
+ if (!counter || counter->magic != PDH_MAGIC_COUNTER)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_HANDLE;
+ }
list_remove( &counter->entry );
+ destroy_counter( counter );
- pdh_free( counter->path );
- pdh_free( counter );
-
+ LeaveCriticalSection( &pdh_handle_cs );
return ERROR_SUCCESS;
}
@@ -694,10 +818,21 @@
TRACE("%p\n", handle);
- if (!counter) return PDH_INVALID_HANDLE;
- if (factor < PDH_MIN_SCALE || factor > PDH_MAX_SCALE) return PDH_INVALID_ARGUMENT;
+ EnterCriticalSection( &pdh_handle_cs );
+ if (!counter || counter->magic != PDH_MAGIC_COUNTER)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_HANDLE;
+ }
+ if (factor < PDH_MIN_SCALE || factor > PDH_MAX_SCALE)
+ {
+ LeaveCriticalSection( &pdh_handle_cs );
+ return PDH_INVALID_ARGUMENT;
+ }
counter->scale = factor;
+
+ LeaveCriticalSection( &pdh_handle_cs );
return ERROR_SUCCESS;
}