Commit c90fb2ea authored by Karl Heyes's avatar Karl Heyes

cleanup duplicate work, fix rare but potential deadlock, and

fix silly bug introduced ealrier

svn path=/trunk/icecast/; revision=5794
parent ef791453
...@@ -438,8 +438,6 @@ static void command_move_clients(client_t *client, source_t *source, ...@@ -438,8 +438,6 @@ static void command_move_clients(client_t *client, source_t *source,
{ {
char *dest_source; char *dest_source;
source_t *dest; source_t *dest;
avl_node *client_node;
client_t *current;
xmlDocPtr doc; xmlDocPtr doc;
xmlNodePtr node; xmlNodePtr node;
char buf[255]; char buf[255];
...@@ -459,16 +457,23 @@ static void command_move_clients(client_t *client, source_t *source, ...@@ -459,16 +457,23 @@ static void command_move_clients(client_t *client, source_t *source,
return; return;
} }
dest = source_find_mount (dest_source);
if (dest == NULL)
{
client_send_400 (client, "No such destination");
return;
}
if (strcmp (dest->mount, source->mount) == 0) if (strcmp (dest->mount, source->mount) == 0)
{ {
client_send_400 (client, "supplied mountpoints are identical"); client_send_400 (client, "supplied mountpoints are identical");
return; return;
} }
dest = source_find_mount(dest_source); if (dest->running == 0)
{
if(dest == NULL) { client_send_400 (client, "Destination not running");
client_send_400(client, "No such source");
return; return;
} }
...@@ -476,26 +481,11 @@ static void command_move_clients(client_t *client, source_t *source, ...@@ -476,26 +481,11 @@ static void command_move_clients(client_t *client, source_t *source,
node = xmlNewDocNode(doc, NULL, "iceresponse", NULL); node = xmlNewDocNode(doc, NULL, "iceresponse", NULL);
xmlDocSetRootElement(doc, node); xmlDocSetRootElement(doc, node);
avl_tree_wlock(source->client_tree); source_move_clients (source, dest);
client_node = avl_get_first(source->client_tree);
while(client_node) {
current = (client_t *)client_node->key;
avl_tree_wlock(dest->pending_tree);
avl_insert(dest->pending_tree, current);
avl_tree_unlock(dest->pending_tree);
client_node = avl_get_next(client_node);
avl_delete(source->client_tree, current, source_remove_client);
source->listeners--;
}
avl_tree_unlock(source->client_tree);
memset(buf, '\000', sizeof(buf)); memset(buf, '\000', sizeof(buf));
snprintf(buf, sizeof(buf)-1, "Clients moved from %s to %s", dest_source, snprintf (buf, sizeof(buf), "Clients moved from %s to %s",
source->mount); source->mount, dest_source);
xmlNewChild(node, NULL, "message", buf); xmlNewChild(node, NULL, "message", buf);
xmlNewChild(node, NULL, "return", "1"); xmlNewChild(node, NULL, "return", "1");
......
...@@ -95,6 +95,7 @@ void connection_initialize(void) ...@@ -95,6 +95,7 @@ void connection_initialize(void)
thread_mutex_create(&_connection_mutex); thread_mutex_create(&_connection_mutex);
thread_mutex_create(&_queue_mutex); thread_mutex_create(&_queue_mutex);
thread_mutex_create(&move_clients_mutex);
thread_rwlock_create(&_source_shutdown_rwlock); thread_rwlock_create(&_source_shutdown_rwlock);
thread_cond_create(&_pool_cond); thread_cond_create(&_pool_cond);
thread_cond_create(&global.shutdown_cond); thread_cond_create(&global.shutdown_cond);
...@@ -111,6 +112,7 @@ void connection_shutdown(void) ...@@ -111,6 +112,7 @@ void connection_shutdown(void)
thread_rwlock_destroy(&_source_shutdown_rwlock); thread_rwlock_destroy(&_source_shutdown_rwlock);
thread_mutex_destroy(&_queue_mutex); thread_mutex_destroy(&_queue_mutex);
thread_mutex_destroy(&_connection_mutex); thread_mutex_destroy(&_connection_mutex);
thread_mutex_destroy(&move_clients_mutex);
_initialized = 0; _initialized = 0;
} }
......
...@@ -56,6 +56,8 @@ ...@@ -56,6 +56,8 @@
#define MAX_FALLBACK_DEPTH 10 #define MAX_FALLBACK_DEPTH 10
mutex_t move_clients_mutex;
/* avl tree helper */ /* avl tree helper */
static int _compare_clients(void *compare_arg, void *a, void *b); static int _compare_clients(void *compare_arg, void *a, void *b);
static int _free_client(void *key); static int _free_client(void *key);
...@@ -113,11 +115,6 @@ source_t *source_create(client_t *client, connection_t *con, ...@@ -113,11 +115,6 @@ source_t *source_create(client_t *client, connection_t *con,
return src; return src;
} }
static int source_remove_source(void *key)
{
return 1;
}
/* Find a mount with this raw name - ignoring fallbacks. You should have the /* Find a mount with this raw name - ignoring fallbacks. You should have the
* global source tree locked to call this. * global source tree locked to call this.
*/ */
...@@ -250,7 +247,63 @@ client_t *source_find_client(source_t *source, int id) ...@@ -250,7 +247,63 @@ client_t *source_find_client(source_t *source, int id)
avl_tree_unlock(source->client_tree); avl_tree_unlock(source->client_tree);
return NULL; return NULL;
} }
void source_move_clients (source_t *source, source_t *dest)
{
client_t *client;
avl_node *node;
if (source->format->type != dest->format->type)
{
WARN2 ("stream %s and %s are of different types, ignored", source->mount, dest->mount);
return;
}
if (dest->running == 0)
{
WARN1 ("source %s not running, unable to move clients ", dest->mount);
return;
}
/* we don't want the two write locks to deadlock in here */
thread_mutex_lock (&move_clients_mutex);
/* we need to move the client and pending trees */
avl_tree_wlock (dest->pending_tree);
avl_tree_wlock (source->pending_tree);
while (1)
{
node = avl_get_first (source->pending_tree);
if (node == NULL)
break;
client = (client_t *)(node->key);
avl_delete (source->pending_tree, client, NULL);
/* TODO: reset client local format data? */
avl_insert (dest->pending_tree, (void *)client);
}
avl_tree_unlock (source->pending_tree);
avl_tree_wlock (source->client_tree);
while (1)
{
node = avl_get_first (source->client_tree);
if (node == NULL)
break;
client = (client_t *)(node->key);
avl_delete (source->client_tree, client, NULL);
/* TODO: reset client local format data? */
avl_insert (dest->pending_tree, (void *)client);
}
source->listeners = 0;
stats_event(source->mount, "listeners", "0");
avl_tree_unlock (source->client_tree);
avl_tree_unlock (dest->pending_tree);
thread_mutex_unlock (&move_clients_mutex);
}
void *source_main(void *arg) void *source_main(void *arg)
{ {
...@@ -450,39 +503,11 @@ void *source_main(void *arg) ...@@ -450,39 +503,11 @@ void *source_main(void *arg)
if(source->fallback_override && source->fallback_mount) { if(source->fallback_override && source->fallback_mount) {
avl_tree_rlock(global.source_tree); avl_tree_rlock(global.source_tree);
fallback_source = source_find_mount(source->fallback_mount); fallback_source = source_find_mount(source->fallback_mount);
avl_tree_unlock(global.source_tree);
if(fallback_source) { if (fallback_source)
/* we need to move the client and pending trees */ source_move_clients (fallback_source, source);
avl_tree_wlock(fallback_source->pending_tree);
while (avl_get_first(fallback_source->pending_tree)) {
client_t *client = (client_t *)avl_get_first(
fallback_source->pending_tree)->key;
avl_delete(fallback_source->pending_tree, client,
source_remove_client);
/* TODO: reset client local format data? */
avl_tree_wlock(source->pending_tree);
avl_insert(source->pending_tree, (void *)client);
avl_tree_unlock(source->pending_tree);
}
avl_tree_unlock(fallback_source->pending_tree);
avl_tree_wlock(fallback_source->client_tree);
while (avl_get_first(fallback_source->client_tree)) {
client_t *client = (client_t *)avl_get_first(
fallback_source->client_tree)->key;
avl_delete(fallback_source->client_tree, client,
source_remove_client);
/* TODO: reset client local format data? */ avl_tree_unlock(global.source_tree);
avl_tree_wlock(source->pending_tree);
avl_insert(source->pending_tree, (void *)client);
avl_tree_unlock(source->pending_tree);
}
avl_tree_unlock(fallback_source->client_tree);
}
} }
while (global.running == ICE_RUNNING && source->running) { while (global.running == ICE_RUNNING && source->running) {
...@@ -732,54 +757,18 @@ done: ...@@ -732,54 +757,18 @@ done:
} }
#endif #endif
avl_tree_rlock(global.source_tree);
fallback_source = source_find_mount(source->fallback_mount);
avl_tree_unlock(global.source_tree);
/* Now, we must remove this source from the source tree before /* Now, we must remove this source from the source tree before
* removing the clients, otherwise new clients can sneak into the pending * removing the clients, otherwise new clients can sneak into the pending
* tree after we've cleared it * tree after we've cleared it
*/ */
avl_tree_wlock(global.source_tree); avl_tree_wlock(global.source_tree);
avl_delete(global.source_tree, source, source_remove_source); fallback_source = source_find_mount (source->fallback_mount);
avl_tree_unlock(global.source_tree); avl_delete (global.source_tree, source, NULL);
/* we need to empty the client and pending trees */
avl_tree_wlock(source->pending_tree);
while (avl_get_first(source->pending_tree)) {
client_t *client = (client_t *)avl_get_first(
source->pending_tree)->key;
if(fallback_source) {
avl_delete(source->pending_tree, client, source_remove_client);
/* TODO: reset client local format data? */
avl_tree_wlock(fallback_source->pending_tree);
avl_insert(fallback_source->pending_tree, (void *)client);
avl_tree_unlock(fallback_source->pending_tree);
}
else {
avl_delete(source->pending_tree, client, _free_client);
}
}
avl_tree_unlock(source->pending_tree);
avl_tree_wlock(source->client_tree);
while (avl_get_first(source->client_tree)) {
client_t *client = (client_t *)avl_get_first(source->client_tree)->key;
if(fallback_source) { if (fallback_source != NULL)
avl_delete(source->client_tree, client, source_remove_client); source_move_clients (source, fallback_source);
/* TODO: reset client local format data? */ avl_tree_unlock (global.source_tree);
avl_tree_wlock(fallback_source->pending_tree);
avl_insert(fallback_source->pending_tree, (void *)client);
avl_tree_unlock(fallback_source->pending_tree);
}
else {
avl_delete(source->client_tree, client, _free_client);
}
}
avl_tree_unlock(source->client_tree);
/* delete this sources stats */ /* delete this sources stats */
stats_event_dec(NULL, "sources"); stats_event_dec(NULL, "sources");
......
...@@ -67,9 +67,12 @@ source_t *source_find_mount_raw(const char *mount); ...@@ -67,9 +67,12 @@ source_t *source_find_mount_raw(const char *mount);
client_t *source_find_client(source_t *source, int id); client_t *source_find_client(source_t *source, int id);
int source_compare_sources(void *arg, void *a, void *b); int source_compare_sources(void *arg, void *a, void *b);
int source_free_source(void *key); int source_free_source(void *key);
void source_move_clients (source_t *source, source_t *dest);
int source_remove_client(void *key); int source_remove_client(void *key);
void *source_main(void *arg); void *source_main(void *arg);
extern mutex_t move_clients_mutex;
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment