mirror of
https://gitlab.xiph.org/xiph/icecast-server.git
synced 2024-09-22 04:15:54 -04:00
cleanup duplicate work, fix rare but potential deadlock, and
fix silly bug introduced ealrier svn path=/trunk/icecast/; revision=5794
This commit is contained in:
parent
ef79145396
commit
c90fb2ea55
38
src/admin.c
38
src/admin.c
@ -438,8 +438,6 @@ static void command_move_clients(client_t *client, source_t *source,
|
||||
{
|
||||
char *dest_source;
|
||||
source_t *dest;
|
||||
avl_node *client_node;
|
||||
client_t *current;
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr node;
|
||||
char buf[255];
|
||||
@ -459,16 +457,23 @@ static void command_move_clients(client_t *client, source_t *source,
|
||||
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)
|
||||
{
|
||||
client_send_400 (client, "supplied mountpoints are identical");
|
||||
return;
|
||||
}
|
||||
|
||||
dest = source_find_mount(dest_source);
|
||||
|
||||
if(dest == NULL) {
|
||||
client_send_400(client, "No such source");
|
||||
if (dest->running == 0)
|
||||
{
|
||||
client_send_400 (client, "Destination not running");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -476,26 +481,11 @@ static void command_move_clients(client_t *client, source_t *source,
|
||||
node = xmlNewDocNode(doc, NULL, "iceresponse", NULL);
|
||||
xmlDocSetRootElement(doc, node);
|
||||
|
||||
avl_tree_wlock(source->client_tree);
|
||||
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);
|
||||
source_move_clients (source, dest);
|
||||
|
||||
memset(buf, '\000', sizeof(buf));
|
||||
snprintf(buf, sizeof(buf)-1, "Clients moved from %s to %s", dest_source,
|
||||
source->mount);
|
||||
snprintf (buf, sizeof(buf), "Clients moved from %s to %s",
|
||||
source->mount, dest_source);
|
||||
xmlNewChild(node, NULL, "message", buf);
|
||||
xmlNewChild(node, NULL, "return", "1");
|
||||
|
||||
|
@ -95,6 +95,7 @@ void connection_initialize(void)
|
||||
|
||||
thread_mutex_create(&_connection_mutex);
|
||||
thread_mutex_create(&_queue_mutex);
|
||||
thread_mutex_create(&move_clients_mutex);
|
||||
thread_rwlock_create(&_source_shutdown_rwlock);
|
||||
thread_cond_create(&_pool_cond);
|
||||
thread_cond_create(&global.shutdown_cond);
|
||||
@ -111,6 +112,7 @@ void connection_shutdown(void)
|
||||
thread_rwlock_destroy(&_source_shutdown_rwlock);
|
||||
thread_mutex_destroy(&_queue_mutex);
|
||||
thread_mutex_destroy(&_connection_mutex);
|
||||
thread_mutex_destroy(&move_clients_mutex);
|
||||
|
||||
_initialized = 0;
|
||||
}
|
||||
|
147
src/source.c
147
src/source.c
@ -56,6 +56,8 @@
|
||||
|
||||
#define MAX_FALLBACK_DEPTH 10
|
||||
|
||||
mutex_t move_clients_mutex;
|
||||
|
||||
/* avl tree helper */
|
||||
static int _compare_clients(void *compare_arg, void *a, void *b);
|
||||
static int _free_client(void *key);
|
||||
@ -113,11 +115,6 @@ source_t *source_create(client_t *client, connection_t *con,
|
||||
return src;
|
||||
}
|
||||
|
||||
static int source_remove_source(void *key)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Find a mount with this raw name - ignoring fallbacks. You should have the
|
||||
* global source tree locked to call this.
|
||||
*/
|
||||
@ -251,6 +248,62 @@ client_t *source_find_client(source_t *source, int id)
|
||||
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)
|
||||
{
|
||||
@ -450,39 +503,11 @@ void *source_main(void *arg)
|
||||
if(source->fallback_override && source->fallback_mount) {
|
||||
avl_tree_rlock(global.source_tree);
|
||||
fallback_source = source_find_mount(source->fallback_mount);
|
||||
|
||||
if (fallback_source)
|
||||
source_move_clients (fallback_source, source);
|
||||
|
||||
avl_tree_unlock(global.source_tree);
|
||||
|
||||
if(fallback_source) {
|
||||
/* we need to move the client and pending trees */
|
||||
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_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) {
|
||||
@ -732,55 +757,19 @@ done:
|
||||
}
|
||||
#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
|
||||
* removing the clients, otherwise new clients can sneak into the pending
|
||||
* tree after we've cleared it
|
||||
*/
|
||||
avl_tree_wlock(global.source_tree);
|
||||
avl_delete(global.source_tree, source, source_remove_source);
|
||||
fallback_source = source_find_mount (source->fallback_mount);
|
||||
avl_delete (global.source_tree, source, NULL);
|
||||
|
||||
if (fallback_source != NULL)
|
||||
source_move_clients (source, fallback_source);
|
||||
|
||||
avl_tree_unlock (global.source_tree);
|
||||
|
||||
/* 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) {
|
||||
avl_delete(source->client_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->client_tree, client, _free_client);
|
||||
}
|
||||
}
|
||||
avl_tree_unlock(source->client_tree);
|
||||
|
||||
/* delete this sources stats */
|
||||
stats_event_dec(NULL, "sources");
|
||||
stats_event(source->mount, "listeners", NULL);
|
||||
|
@ -67,9 +67,12 @@ source_t *source_find_mount_raw(const char *mount);
|
||||
client_t *source_find_client(source_t *source, int id);
|
||||
int source_compare_sources(void *arg, void *a, void *b);
|
||||
int source_free_source(void *key);
|
||||
void source_move_clients (source_t *source, source_t *dest);
|
||||
int source_remove_client(void *key);
|
||||
void *source_main(void *arg);
|
||||
|
||||
extern mutex_t move_clients_mutex;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user