From a193d965b46482e697535592c969929c17192b55 Mon Sep 17 00:00:00 2001 From: Nedko Arnaudov Date: Sun, 23 Aug 2009 01:21:23 +0300 Subject: [PATCH] Move jack handling into studio object; fix race Studio is a singleton and jack server start/stop races are avoided by using a queue --- daemon/common.h | 1 - daemon/control.c | 2 +- daemon/jack.c | 124 ---------------------- daemon/jack.h | 40 ------- daemon/main.c | 18 ++-- daemon/studio.c | 316 +++++++++++++++++++++++++++++++++++++------------------ daemon/studio.h | 37 +------ wscript | 1 - 8 files changed, 226 insertions(+), 313 deletions(-) delete mode 100644 daemon/jack.c delete mode 100644 daemon/jack.h diff --git a/daemon/common.h b/daemon/common.h index e7911525..2e4aadb3 100644 --- a/daemon/common.h +++ b/daemon/common.h @@ -107,6 +107,5 @@ struct room #include "studio.h" extern bool g_quit; -extern studio_handle g_studio; #endif /* #ifndef COMMON_H__CFDC869A_31AE_4FA3_B2D3_DACA8488CA55__INCLUDED */ diff --git a/daemon/control.c b/daemon/control.c index 28aa51d4..99d889eb 100644 --- a/daemon/control.c +++ b/daemon/control.c @@ -39,7 +39,7 @@ static void ladish_is_studio_loaded(method_call_t * call_ptr) DBusMessageIter iter; dbus_bool_t is_loaded; - is_loaded = g_studio != NULL; + is_loaded = studio_is_loaded(); call_ptr->reply = dbus_message_new_method_return(call_ptr->message); if (call_ptr->reply == NULL) diff --git a/daemon/jack.c b/daemon/jack.c deleted file mode 100644 index fc8c36a6..00000000 --- a/daemon/jack.c +++ /dev/null @@ -1,124 +0,0 @@ -/* -*- Mode: C ; c-basic-offset: 2 -*- */ -/* - * LADI Session Handler (ladish) - * - * Copyright (C) 2009 Nedko Arnaudov - * - ************************************************************************** - * This file contains code for JACK server monitor and control - ************************************************************************** - * - * LADI Session Handler is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * LADI Session Handler 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LADI Session Handler. If not, see - * or write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "jack.h" -#include "../jack_proxy.h" -#include "studio.h" -#include "control.h" - -void -on_jack_server_started( - void) -{ - lash_info("JACK server start detected."); - - if (g_studio == NULL) - { - if (!studio_create(&g_studio)) - { - lash_error("failed to create studio object"); - return; - } - } - - if (!studio_fetch_jack_settings(g_studio)) - { - lash_error("studio_fetch_jack_settings() failed."); - - if (!studio_is_persisted(g_studio)) - { - emit_studio_disappeared(); - studio_destroy(g_studio); - g_studio = NULL; - return; - } - } - - lash_info("jack conf successfully retrieved"); - studio_activate(g_studio); - emit_studio_appeared(); - studio_save(g_studio, NULL); /* XXX - to test save functionality, we should not save unless requested by user */ - return; -} - -void -on_jack_server_stopped( - void) -{ - lash_info("JACK server stop detected."); - - if (g_studio == NULL) - { - return; - } - - if (!studio_is_persisted(g_studio)) - { - emit_studio_disappeared(); - studio_destroy(g_studio); - g_studio = NULL; - return; - } - - /* TODO: if user wants, restart jack server and reconnect all jack apps to it */ -} - -void -on_jack_server_appeared( - void) -{ - lash_info("JACK controller appeared."); -} - -void -on_jack_server_disappeared( - void) -{ - lash_info("JACK controller disappeared."); -} - -bool -jack_init( - void) -{ - if (!jack_proxy_init( - on_jack_server_started, - on_jack_server_stopped, - on_jack_server_appeared, - on_jack_server_disappeared)) - { - return false; - } - - return true; -} - -void -jack_uninit( - void) -{ - jack_proxy_uninit(); -} diff --git a/daemon/jack.h b/daemon/jack.h deleted file mode 100644 index 56eecdcb..00000000 --- a/daemon/jack.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- Mode: C ; c-basic-offset: 2 -*- */ -/* - * LADI Session Handler (ladish) - * - * Copyright (C) 2009 Nedko Arnaudov - * - ************************************************************************** - * This file contains interface to JACK server monitor and control code - ************************************************************************** - * - * LADI Session Handler is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * LADI Session Handler 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with LADI Session Handler. If not, see - * or write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef JACK_H__1C44BAEA_280C_4235_94AB_839499BDE47F__INCLUDED -#define JACK_H__1C44BAEA_280C_4235_94AB_839499BDE47F__INCLUDED - -#include "common.h" - -bool -jack_init( - void); - -void -jack_uninit( - void); - -#endif /* #ifndef JACK_H__1C44BAEA_280C_4235_94AB_839499BDE47F__INCLUDED */ diff --git a/daemon/main.c b/daemon/main.c index b907ef21..74403d52 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -37,14 +37,12 @@ #include "loader.h" #include "sigsegv.h" #include "control.h" -#include "jack.h" #include "studio.h" #include "../dbus_constants.h" bool g_quit; const char * g_dbus_unique_name; object_path_t * g_control_object; -studio_handle g_studio; #if 0 static DBusHandlerResult lashd_client_disconnect_handler(DBusConnection * connection, DBusMessage * message, void * data) @@ -57,7 +55,6 @@ static DBusHandlerResult lashd_client_disconnect_handler(DBusConnection * connec const char *member, *name, *old_name; struct lash_client *client; - DBusError err; if (!(member = dbus_message_get_member(message))) { @@ -138,6 +135,8 @@ static bool connect_dbus(void) goto unref_connection; } + lash_info("Connected to local session bus, unique name is \"%s\"", g_dbus_unique_name); + ret = dbus_bus_request_name(g_dbus_connection, SERVICE_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE, &g_dbus_error); if (ret == -1) { @@ -250,7 +249,7 @@ int main(int argc, char ** argv, char ** envp) /* setup our SIGSEGV magic that prints nice stack in our logfile */ setup_sigsegv(); - if (!jack_init()) + if (!studio_init()) { goto uninit_dbus; } @@ -259,21 +258,16 @@ int main(int argc, char ** argv, char ** envp) { dbus_connection_read_write_dispatch(g_dbus_connection, 50); loader_run(); - } - - if (g_studio != NULL) - { - studio_destroy(g_studio); - emit_studio_disappeared(); + studio_run(); } ret = EXIT_SUCCESS; lash_debug("Finished, cleaning up"); -uninit_dbus: - jack_uninit(); + studio_uninit(); +uninit_dbus: disconnect_dbus(); uninit_loader: diff --git a/daemon/studio.c b/daemon/studio.c index 00a7f4c8..ce36dde9 100644 --- a/daemon/studio.c +++ b/daemon/studio.c @@ -5,7 +5,7 @@ * Copyright (C) 2009 Nedko Arnaudov * ************************************************************************** - * This file contains studio object helpers + * This file contains implementation of the studio singleton object ************************************************************************** * * LADI Session Handler is free software; you can redistribute it and/or modify @@ -28,6 +28,7 @@ #include "../jack_proxy.h" #include "patchbay.h" #include "../dbus_constants.h" +#include "control.h" extern const interface_t g_interface_studio; @@ -48,14 +49,23 @@ struct studio bool persisted:1; /* Studio has on-disk representation, i.e. can be reloaded from disk */ bool modified:1; /* Studio needs saving */ - bool jack_conf_stable:1; /* JACK server configuration obtained successfully */ + bool jack_conf_valid:1; /* JACK server configuration obtained successfully */ struct list_head jack_conf; /* root of the conf tree */ struct list_head jack_params; /* list of conf tree leaves */ object_path_t * dbus_object; - struct patchbay_implementator patchbay_implementator; + struct list_head event_queue; +} g_studio; + +#define EVENT_JACK_START 0 +#define EVENT_JACK_STOP 1 + +struct event +{ + struct list_head siblings; + unsigned int type; }; #define JACK_CONF_MAX_ADDRESS_SIZE 1024 @@ -83,7 +93,6 @@ struct conf_callback_context { char address[JACK_CONF_MAX_ADDRESS_SIZE]; struct list_head * container_ptr; - struct studio * studio_ptr; struct jack_conf_container * parent_ptr; }; @@ -241,8 +250,6 @@ conf_callback( struct jack_conf_container * container_ptr; struct jack_conf_parameter * parameter_ptr; - assert(context_ptr->studio_ptr); - parent_ptr = context_ptr->parent_ptr; dst = path; @@ -327,7 +334,7 @@ conf_callback( parameter_ptr->parent_ptr = parent_ptr; memcpy(parameter_ptr->address, context_ptr->address, JACK_CONF_MAX_ADDRESS_SIZE); list_add_tail(¶meter_ptr->siblings, &parent_ptr->children); - list_add_tail(¶meter_ptr->leaves, &context_ptr->studio_ptr->jack_params); + list_add_tail(¶meter_ptr->leaves, &g_studio.jack_params); } else { @@ -354,7 +361,7 @@ conf_callback( if (parent_ptr == NULL) { - list_add_tail(&container_ptr->siblings, &context_ptr->studio_ptr->jack_conf); + list_add_tail(&container_ptr->siblings, &g_studio.jack_conf); } else { @@ -379,122 +386,243 @@ conf_callback( #undef context_ptr -#define studio_ptr ((struct studio *)this) - -uint64_t -studio_get_graph_version( - void * this) +bool studio_fetch_jack_settings() { - //lash_info("studio_get_graph_version() called"); - return 1; -} + struct conf_callback_context context; -#undef studio_ptr + context.address[0] = 0; + context.container_ptr = &g_studio.jack_conf; + context.parent_ptr = NULL; + + if (!jack_proxy_read_conf_container(context.address, &context, conf_callback)) + { + lash_error("jack_proxy_read_conf_container() failed."); + return false; + } + + return true; +} bool -studio_create( - studio_handle * studio_handle_ptr) +studio_activate(void) { - struct studio * studio_ptr; + object_path_t * object; - lash_info("studio object construct"); + object = object_path_new(STUDIO_OBJECT_PATH, &g_studio, 2, &g_interface_studio, &g_interface_patchbay); + if (object == NULL) + { + lash_error("object_path_new() failed"); + return false; + } - studio_ptr = malloc(sizeof(struct studio)); - if (studio_ptr == NULL) + if (!object_path_register(g_dbus_connection, object)) { - lash_error("malloc() failed to allocate struct studio"); + lash_error("object_path_register() failed"); + object_path_destroy(g_dbus_connection, object); return false; } - studio_ptr->patchbay_impl.this = studio_ptr; - studio_ptr->patchbay_impl.get_graph_version = studio_get_graph_version; + lash_info("Studio D-Bus object created."); + + g_studio.dbus_object = object; - INIT_LIST_HEAD(&studio_ptr->all_connections); - INIT_LIST_HEAD(&studio_ptr->all_ports); - INIT_LIST_HEAD(&studio_ptr->all_clients); - INIT_LIST_HEAD(&studio_ptr->jack_connections); - INIT_LIST_HEAD(&studio_ptr->jack_ports); - INIT_LIST_HEAD(&studio_ptr->jack_clients); - INIT_LIST_HEAD(&studio_ptr->rooms); - INIT_LIST_HEAD(&studio_ptr->clients); - INIT_LIST_HEAD(&studio_ptr->ports); + emit_studio_appeared(); - studio_ptr->modified = false; - studio_ptr->persisted = false; - studio_ptr->jack_conf_stable = false; + return true; +} - INIT_LIST_HEAD(&studio_ptr->jack_conf); - INIT_LIST_HEAD(&studio_ptr->jack_params); +void +studio_clear(void) +{ + struct list_head * node_ptr; - studio_ptr->dbus_object = NULL; + g_studio.modified = false; + g_studio.persisted = false; - *studio_handle_ptr = (studio_handle)studio_ptr; + while (!list_empty(&g_studio.jack_conf)) + { + node_ptr = g_studio.jack_conf.next; + list_del(node_ptr); + jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings)); + } - return true; -} + g_studio.jack_conf_valid = false; -#define studio_ptr ((struct studio *)studio) + if (g_studio.dbus_object != NULL) + { + object_path_destroy(g_dbus_connection, g_studio.dbus_object); + g_studio.dbus_object = NULL; + emit_studio_disappeared(); + } +} void -studio_destroy( - studio_handle studio) +studio_clear_if_not_persisted(void) { - struct list_head * node_ptr; + if (!g_studio.persisted) + { + studio_clear(); + return; + } +} - if (studio_ptr->dbus_object != NULL) +void on_event_jack_started(void) +{ + if (g_studio.dbus_object == NULL) { - object_path_destroy(g_dbus_connection, studio_ptr->dbus_object); + studio_activate(); } - while (!list_empty(&studio_ptr->jack_conf)) + if (!studio_fetch_jack_settings(g_studio)) { - node_ptr = studio_ptr->jack_conf.next; - list_del(node_ptr); - jack_conf_container_destroy(list_entry(node_ptr, struct jack_conf_container, siblings)); + lash_error("studio_fetch_jack_settings() failed."); + + studio_clear_if_not_persisted(); + return; } - free(studio_ptr); - lash_info("studio object destroy"); + lash_info("jack conf successfully retrieved"); + g_studio.jack_conf_valid = true; } -bool -studio_activate( - studio_handle studio) +void on_event_jack_stopped(void) { - object_path_t * object; + studio_clear_if_not_persisted(); - object = object_path_new(STUDIO_OBJECT_PATH, studio, 2, &g_interface_studio, &g_interface_patchbay); - if (object == NULL) + /* TODO: if user wants, restart jack server and reconnect all jack apps to it */ +} + +void studio_run(void) +{ + struct event * event_ptr; + + while (!list_empty(&g_studio.event_queue)) { - lash_error("object_path_new() failed"); - return false; + event_ptr = list_entry(g_studio.event_queue.next, struct event, siblings); + list_del(g_studio.event_queue.next); + + switch (event_ptr->type) + { + case EVENT_JACK_START: + on_event_jack_started(); + break; + case EVENT_JACK_STOP: + on_event_jack_stopped(); + break; + } + + free(event_ptr); } +} - if (!object_path_register(g_dbus_connection, object)) +static void on_jack_server_started(void) +{ + struct event * event_ptr; + + lash_info("JACK server start detected."); + + event_ptr = malloc(sizeof(struct event)); + if (event_ptr == NULL) { - lash_error("object_path_register() failed"); - object_path_destroy(g_dbus_connection, object); - return false; + lash_error("malloc() failed to allocate struct event. Ignoring JACK start."); + return; } - lash_info("Studio D-Bus object created."); + event_ptr->type = EVENT_JACK_START; + list_add_tail(&event_ptr->siblings, &g_studio.event_queue); +} + +static void on_jack_server_stopped(void) +{ + struct event * event_ptr; + + lash_info("JACK server stop detected."); + + event_ptr = malloc(sizeof(struct event)); + if (event_ptr == NULL) + { + lash_error("malloc() failed to allocate struct event. Ignoring JACK stop."); + return; + } + + event_ptr->type = EVENT_JACK_STOP; + list_add_tail(&event_ptr->siblings, &g_studio.event_queue); +} + +static void on_jack_server_appeared(void) +{ + lash_info("JACK controller appeared."); +} + +static void on_jack_server_disappeared(void) +{ + lash_info("JACK controller disappeared."); +} + +#define studio_ptr ((struct studio *)this) + +uint64_t +studio_get_graph_version( + void * this) +{ + //lash_info("studio_get_graph_version() called"); + return 1; +} + +#undef studio_ptr + +bool studio_init(void) +{ + lash_info("studio object construct"); + + g_studio.patchbay_impl.this = &g_studio; + g_studio.patchbay_impl.get_graph_version = studio_get_graph_version; - studio_ptr->dbus_object = object; + INIT_LIST_HEAD(&g_studio.all_connections); + INIT_LIST_HEAD(&g_studio.all_ports); + INIT_LIST_HEAD(&g_studio.all_clients); + INIT_LIST_HEAD(&g_studio.jack_connections); + INIT_LIST_HEAD(&g_studio.jack_ports); + INIT_LIST_HEAD(&g_studio.jack_clients); + INIT_LIST_HEAD(&g_studio.rooms); + INIT_LIST_HEAD(&g_studio.clients); + INIT_LIST_HEAD(&g_studio.ports); + + INIT_LIST_HEAD(&g_studio.jack_conf); + INIT_LIST_HEAD(&g_studio.jack_params); + + INIT_LIST_HEAD(&g_studio.event_queue); + + g_studio.dbus_object = NULL; + studio_clear(); + + if (!jack_proxy_init( + on_jack_server_started, + on_jack_server_stopped, + on_jack_server_appeared, + on_jack_server_disappeared)) + { + return false; + } return true; } -bool -studio_is_persisted( - studio_handle studio) +void studio_uninit(void) { - return studio_ptr->persisted; + jack_proxy_uninit(); + + studio_clear(); + + lash_info("studio object destroy"); } -bool -studio_save( - studio_handle studio, - const char * file_path) +bool studio_is_loaded(void) +{ + return g_studio.dbus_object != NULL; +} + +bool studio_save(const char * file_path) { struct list_head * node_ptr; struct jack_conf_parameter * parameter_ptr; @@ -505,7 +633,7 @@ studio_save( lash_info("saving studio..."); - list_for_each(node_ptr, &studio_ptr->jack_params) + list_for_each(node_ptr, &g_studio.jack_params) { parameter_ptr = list_entry(node_ptr, struct jack_conf_parameter, leaves); @@ -565,37 +693,21 @@ studio_save( return false; /* not implemented yet */ } -bool -studio_load( - studio_handle studio, - const char * file_path) +bool studio_load(const char * file_path) { return false; /* not implemented yet */ } -#undef studio_ptr - -bool -studio_fetch_jack_settings( - studio_handle studio) +static void ladish_save_studio(method_call_t * call_ptr) { - struct conf_callback_context context; - - context.address[0] = 0; - context.studio_ptr = (struct studio *)studio; - context.container_ptr = &context.studio_ptr->jack_conf; - context.parent_ptr = NULL; - - if (!jack_proxy_read_conf_container(context.address, &context, conf_callback)) - { - lash_error("jack_proxy_read_conf_container() failed."); - return false; - } - - return true; + //studio_save(g_studio, NULL) } +METHOD_ARGS_BEGIN(Save, "Save studio") +METHOD_ARGS_END + METHODS_BEGIN + METHOD_DESCRIBE(Save, ladish_save_studio) METHODS_END SIGNAL_ARGS_BEGIN(RoomAppeared, "Room D-Bus object appeared") diff --git a/daemon/studio.h b/daemon/studio.h index 52f35327..5d3e6ca6 100644 --- a/daemon/studio.h +++ b/daemon/studio.h @@ -5,7 +5,7 @@ * Copyright (C) 2009 Nedko Arnaudov * ************************************************************************** - * This file contains interface to studio object helpers + * This file contains interface of the studio singleton object ************************************************************************** * * LADI Session Handler is free software; you can redistribute it and/or modify @@ -27,36 +27,9 @@ #ifndef STUDIO_H__0BEDE85E_4FB3_4D74_BC08_C373A22409C0__INCLUDED #define STUDIO_H__0BEDE85E_4FB3_4D74_BC08_C373A22409C0__INCLUDED -typedef struct { int unused; } * studio_handle; - -bool -studio_create( - studio_handle * studio_ptr); - -void -studio_destroy( - studio_handle studio); - -bool -studio_activate( - studio_handle studio); - -bool -studio_fetch_jack_settings( - studio_handle studio); - -bool -studio_is_persisted( - studio_handle studio); - -bool -studio_save( - studio_handle studio, - const char * file_path); - -bool -studio_load( - studio_handle studio, - const char * file_path); +bool studio_init(void); +void studio_uninit(void); +void studio_run(void); +bool studio_is_loaded(void); #endif /* #ifndef STUDIO_H__0BEDE85E_4FB3_4D74_BC08_C373A22409C0__INCLUDED */ diff --git a/wscript b/wscript index 63f9db45..2df58bad 100644 --- a/wscript +++ b/wscript @@ -177,7 +177,6 @@ def build(bld): 'appdb.c', 'procfs.c', 'control.c', - 'jack.c', 'studio.c', 'patchbay.c', ]: -- 2.11.4.GIT