Separate code to manage statistic file

Code is quite independent so move in separate file.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Acked-by: Christophe Fergeau <cfergeau@redhat.com>
This commit is contained in:
Frediano Ziglio 2016-11-15 13:51:07 +00:00
parent 99eff8500b
commit f9ccabfaea
6 changed files with 233 additions and 127 deletions

View File

@ -143,6 +143,8 @@ libserver_la_SOURCES = \
sound.c \
sound.h \
stat.h \
stat-file.c \
stat-file.h \
spicevmc.c \
video-encoder.h \
zlib-encoder.c \

View File

@ -24,6 +24,7 @@
#include "main-dispatcher.h"
#include "main-channel.h"
#include "inputs-channel.h"
#include "stat-file.h"
#define MIGRATE_TIMEOUT (MSEC_PER_SEC * 10)
#define MM_TIME_DELTA 400 /*ms*/
@ -45,13 +46,6 @@ typedef struct MonitorMode {
uint32_t y_res;
} MonitorMode;
#ifdef RED_STATISTICS
#define REDS_MAX_STAT_NODES 100
#define REDS_STAT_SHM_SIZE (sizeof(SpiceStat) + REDS_MAX_STAT_NODES * sizeof(SpiceStatNode))
#endif
typedef struct RedsMigPendingLink {
SpiceLinkMess *link_msg;
RedsStream *stream;
@ -127,9 +121,7 @@ struct RedsState {
SSL_CTX *ctx;
#ifdef RED_STATISTICS
char *stat_shm_name;
SpiceStat *stat;
pthread_mutex_t stat_lock;
RedStatFile stat_file;
#endif
int allow_multiple_clients;

View File

@ -76,6 +76,8 @@
#include "main-channel-client.h"
#include "red-client.h"
#define REDS_MAX_STAT_NODES 100
static void reds_client_monitors_config(RedsState *reds, VDAgentMonitorsConfig *monitors_config);
static gboolean reds_use_client_monitors_config(RedsState *reds);
@ -348,105 +350,24 @@ static void reds_link_free(RedLinkInfo *link)
#ifdef RED_STATISTICS
static void reds_insert_stat_node(RedsState *reds, StatNodeRef parent, StatNodeRef ref)
{
SpiceStatNode *node = &reds->stat->nodes[ref];
uint32_t pos = INVALID_STAT_REF;
uint32_t node_index;
uint32_t *head;
SpiceStatNode *n;
node->first_child_index = INVALID_STAT_REF;
head = (parent == INVALID_STAT_REF ? &reds->stat->root_index :
&reds->stat->nodes[parent].first_child_index);
node_index = *head;
while (node_index != INVALID_STAT_REF && (n = &reds->stat->nodes[node_index]) &&
strcmp(node->name, n->name) > 0) {
pos = node_index;
node_index = n->next_sibling_index;
}
if (pos == INVALID_STAT_REF) {
node->next_sibling_index = *head;
*head = ref;
} else {
n = &reds->stat->nodes[pos];
node->next_sibling_index = n->next_sibling_index;
n->next_sibling_index = ref;
}
}
StatNodeRef stat_add_node(RedsState *reds, StatNodeRef parent, const char *name, int visible)
{
StatNodeRef ref;
SpiceStatNode *node;
spice_assert(name && strlen(name) > 0);
if (strlen(name) >= sizeof(node->name)) {
return INVALID_STAT_REF;
}
pthread_mutex_lock(&reds->stat_lock);
ref = (parent == INVALID_STAT_REF ? reds->stat->root_index :
reds->stat->nodes[parent].first_child_index);
while (ref != INVALID_STAT_REF) {
node = &reds->stat->nodes[ref];
if (strcmp(name, node->name)) {
ref = node->next_sibling_index;
} else {
pthread_mutex_unlock(&reds->stat_lock);
return ref;
}
}
if (reds->stat->num_of_nodes >= REDS_MAX_STAT_NODES || reds->stat == NULL) {
pthread_mutex_unlock(&reds->stat_lock);
return INVALID_STAT_REF;
}
reds->stat->generation++;
reds->stat->num_of_nodes++;
for (ref = 0; ref <= REDS_MAX_STAT_NODES; ref++) {
node = &reds->stat->nodes[ref];
if (!(node->flags & SPICE_STAT_NODE_FLAG_ENABLED)) {
break;
}
}
spice_assert(!(node->flags & SPICE_STAT_NODE_FLAG_ENABLED));
node->value = 0;
node->flags = SPICE_STAT_NODE_FLAG_ENABLED | (visible ? SPICE_STAT_NODE_FLAG_VISIBLE : 0);
g_strlcpy(node->name, name, sizeof(node->name));
reds_insert_stat_node(reds, parent, ref);
pthread_mutex_unlock(&reds->stat_lock);
return ref;
}
static void reds_stat_remove(RedsState *reds, SpiceStatNode *node)
{
pthread_mutex_lock(&reds->stat_lock);
node->flags &= ~SPICE_STAT_NODE_FLAG_ENABLED;
reds->stat->generation++;
reds->stat->num_of_nodes--;
pthread_mutex_unlock(&reds->stat_lock);
return stat_file_add_node(&reds->stat_file, parent, name, visible);
}
void stat_remove_node(RedsState *reds, StatNodeRef ref)
{
reds_stat_remove(reds, &reds->stat->nodes[ref]);
stat_file_remove_node(&reds->stat_file, ref);
}
uint64_t *stat_add_counter(RedsState *reds, StatNodeRef parent, const char *name, int visible)
{
StatNodeRef ref = stat_add_node(reds, parent, name, visible);
SpiceStatNode *node;
if (ref == INVALID_STAT_REF) {
return NULL;
}
node = &reds->stat->nodes[ref];
node->flags |= SPICE_STAT_NODE_FLAG_VALUE;
return &node->value;
return stat_file_add_counter(&reds->stat_file, parent, name, visible);
}
void stat_remove_counter(RedsState *reds, uint64_t *counter)
{
reds_stat_remove(reds, (SpiceStatNode *)(counter - SPICE_OFFSETOF(SpiceStatNode, value)));
stat_file_remove_counter(&reds->stat_file, counter);
}
#endif
@ -2906,11 +2827,7 @@ static int reds_init_ssl(RedsState *reds)
static void reds_cleanup(RedsState *reds)
{
#ifdef RED_STATISTICS
if (reds->stat_shm_name) {
shm_unlink(reds->stat_shm_name);
free(reds->stat_shm_name);
reds->stat_shm_name = NULL;
}
stat_file_unlink(&reds->stat_file);
#endif
}
@ -3442,30 +3359,7 @@ static int do_spice_init(RedsState *reds, SpiceCoreInterface *core_interface)
}
#ifdef RED_STATISTICS
int shm_name_len;
int fd;
shm_name_len = strlen(SPICE_STAT_SHM_NAME) + 20;
reds->stat_shm_name = (char *)spice_malloc(shm_name_len);
snprintf(reds->stat_shm_name, shm_name_len, SPICE_STAT_SHM_NAME, getpid());
shm_unlink(reds->stat_shm_name);
if ((fd = shm_open(reds->stat_shm_name, O_CREAT | O_RDWR, 0444)) == -1) {
spice_error("statistics shm_open failed, %s", strerror(errno));
}
if (ftruncate(fd, REDS_STAT_SHM_SIZE) == -1) {
spice_error("statistics ftruncate failed, %s", strerror(errno));
}
reds->stat = (SpiceStat *)mmap(NULL, REDS_STAT_SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (reds->stat == (SpiceStat *)MAP_FAILED) {
spice_error("statistics mmap failed, %s", strerror(errno));
}
memset(reds->stat, 0, REDS_STAT_SHM_SIZE);
reds->stat->magic = SPICE_STAT_MAGIC;
reds->stat->version = SPICE_STAT_VERSION;
reds->stat->root_index = INVALID_STAT_REF;
if (pthread_mutex_init(&reds->stat_lock, NULL)) {
spice_error("mutex init failed");
}
stat_file_init(&reds->stat_file, REDS_MAX_STAT_NODES);
#endif
if (reds_init_net(reds) < 0) {

177
server/stat-file.c Normal file
View File

@ -0,0 +1,177 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2009-2016 Red Hat, Inc.
This library 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 library 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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <common/log.h>
#include <common/mem.h>
#include "stat-file.h"
#define STAT_SHM_SIZE(max_nodes) \
(sizeof(SpiceStat) + (max_nodes) * sizeof(SpiceStatNode))
void stat_file_init(RedStatFile *stat_file, unsigned int max_nodes)
{
int shm_name_len;
int fd;
size_t shm_size = STAT_SHM_SIZE(max_nodes);
stat_file->max_nodes = max_nodes;
shm_name_len = strlen(SPICE_STAT_SHM_NAME) + 20;
stat_file->shm_name = (char *)spice_malloc(shm_name_len);
snprintf(stat_file->shm_name, shm_name_len, SPICE_STAT_SHM_NAME, getpid());
shm_unlink(stat_file->shm_name);
if ((fd = shm_open(stat_file->shm_name, O_CREAT | O_RDWR, 0444)) == -1) {
spice_error("statistics shm_open failed, %s", strerror(errno));
}
if (ftruncate(fd, shm_size) == -1) {
spice_error("statistics ftruncate failed, %s", strerror(errno));
}
stat_file->stat = (SpiceStat *)mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (stat_file->stat == (SpiceStat *)MAP_FAILED) {
spice_error("statistics mmap failed, %s", strerror(errno));
}
memset(stat_file->stat, 0, shm_size);
stat_file->stat->magic = SPICE_STAT_MAGIC;
stat_file->stat->version = SPICE_STAT_VERSION;
stat_file->stat->root_index = INVALID_STAT_REF;
if (pthread_mutex_init(&stat_file->lock, NULL)) {
spice_error("mutex init failed");
}
}
void stat_file_unlink(RedStatFile *stat_file)
{
if (stat_file->shm_name) {
shm_unlink(stat_file->shm_name);
free(stat_file->shm_name);
stat_file->shm_name = NULL;
}
}
static void reds_insert_stat_node(RedStatFile *stat_file, StatNodeRef parent, StatNodeRef ref)
{
SpiceStatNode *node = &stat_file->stat->nodes[ref];
uint32_t pos = INVALID_STAT_REF;
uint32_t node_index;
uint32_t *head;
SpiceStatNode *n;
node->first_child_index = INVALID_STAT_REF;
head = (parent == INVALID_STAT_REF ? &stat_file->stat->root_index :
&stat_file->stat->nodes[parent].first_child_index);
node_index = *head;
while (node_index != INVALID_STAT_REF && (n = &stat_file->stat->nodes[node_index]) &&
strcmp(node->name, n->name) > 0) {
pos = node_index;
node_index = n->next_sibling_index;
}
if (pos == INVALID_STAT_REF) {
node->next_sibling_index = *head;
*head = ref;
} else {
n = &stat_file->stat->nodes[pos];
node->next_sibling_index = n->next_sibling_index;
n->next_sibling_index = ref;
}
}
StatNodeRef
stat_file_add_node(RedStatFile *stat_file, StatNodeRef parent, const char *name, int visible)
{
StatNodeRef ref;
SpiceStatNode *node;
spice_assert(name && strlen(name) > 0);
if (strlen(name) >= sizeof(node->name)) {
return INVALID_STAT_REF;
}
pthread_mutex_lock(&stat_file->lock);
ref = (parent == INVALID_STAT_REF ? stat_file->stat->root_index :
stat_file->stat->nodes[parent].first_child_index);
while (ref != INVALID_STAT_REF) {
node = &stat_file->stat->nodes[ref];
if (strcmp(name, node->name)) {
ref = node->next_sibling_index;
} else {
pthread_mutex_unlock(&stat_file->lock);
return ref;
}
}
if (stat_file->stat->num_of_nodes >= stat_file->max_nodes || stat_file->stat == NULL) {
pthread_mutex_unlock(&stat_file->lock);
return INVALID_STAT_REF;
}
stat_file->stat->generation++;
stat_file->stat->num_of_nodes++;
for (ref = 0; ref <= stat_file->max_nodes; ref++) {
node = &stat_file->stat->nodes[ref];
if (!(node->flags & SPICE_STAT_NODE_FLAG_ENABLED)) {
break;
}
}
spice_assert(!(node->flags & SPICE_STAT_NODE_FLAG_ENABLED));
node->value = 0;
node->flags = SPICE_STAT_NODE_FLAG_ENABLED | (visible ? SPICE_STAT_NODE_FLAG_VISIBLE : 0);
g_strlcpy(node->name, name, sizeof(node->name));
reds_insert_stat_node(stat_file, parent, ref);
pthread_mutex_unlock(&stat_file->lock);
return ref;
}
uint64_t *
stat_file_add_counter(RedStatFile *stat_file, StatNodeRef parent, const char *name, int visible)
{
StatNodeRef ref = stat_file_add_node(stat_file, parent, name, visible);
SpiceStatNode *node;
if (ref == INVALID_STAT_REF) {
return NULL;
}
node = &stat_file->stat->nodes[ref];
node->flags |= SPICE_STAT_NODE_FLAG_VALUE;
return &node->value;
}
static void stat_file_remove(RedStatFile *stat_file, SpiceStatNode *node)
{
pthread_mutex_lock(&stat_file->lock);
node->flags &= ~SPICE_STAT_NODE_FLAG_ENABLED;
stat_file->stat->generation++;
stat_file->stat->num_of_nodes--;
pthread_mutex_unlock(&stat_file->lock);
}
void stat_file_remove_node(RedStatFile *stat_file, StatNodeRef ref)
{
stat_file_remove(stat_file, &stat_file->stat->nodes[ref]);
}
void stat_file_remove_counter(RedStatFile *stat_file, uint64_t *counter)
{
stat_file_remove(stat_file, (SpiceStatNode *)(counter - SPICE_OFFSETOF(SpiceStatNode, value)));
}

43
server/stat-file.h Normal file
View File

@ -0,0 +1,43 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2016 Red Hat, Inc.
This library 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 library 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.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef STAT_FILE_H_
#define STAT_FILE_H_
#include <pthread.h>
#include <spice/stats.h>
typedef uint32_t StatNodeRef;
#define INVALID_STAT_REF (~(StatNodeRef)0)
typedef struct {
char *shm_name;
SpiceStat *stat;
pthread_mutex_t lock;
unsigned int max_nodes;
} RedStatFile;
void stat_file_init(RedStatFile *stat_file, unsigned int max_nodes);
void stat_file_unlink(RedStatFile *file_stat);
StatNodeRef stat_file_add_node(RedStatFile *stat_file, StatNodeRef parent,
const char *name, int visible);
uint64_t *stat_file_add_counter(RedStatFile *stat_file, StatNodeRef parent,
const char *name, int visible);
void stat_file_remove_node(RedStatFile *stat_file, StatNodeRef ref);
void stat_file_remove_counter(RedStatFile *stat_file, uint64_t *counter);
#endif /* STAT_FILE_H_ */

View File

@ -22,9 +22,7 @@
#include <glib.h>
#include "spice.h"
typedef uint32_t StatNodeRef;
#define INVALID_STAT_REF (~(StatNodeRef)0)
#include "stat-file.h"
#ifdef RED_STATISTICS
StatNodeRef stat_add_node(SpiceServer *reds, StatNodeRef parent, const char *name, int visible);