daemon: on studio stop, wait apps to finish before stopping jack server. Fix for #24
[ladish.git] / daemon / cmd_stop_studio.c
blob9037f24a05150e234a1aeb6773a78232468c89d6
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of the "stop studio" command
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <unistd.h>
29 #include "cmd.h"
30 #include "studio_internal.h"
31 #include "loader.h"
33 #define STOP_STATE_WAITING_FOR_JACK_CLIENTS_DISAPPEAR 1
34 #define STOP_STATE_WAITING_FOR_CHILDS_TERMINATION 2
35 #define STOP_STATE_WAITING_FOR_JACK_SERVER_STOP 3
37 struct ladish_command_stop_studio
39 struct ladish_command command;
40 int stop_waits;
41 unsigned int stop_state;
44 #define cmd_ptr ((struct ladish_command_stop_studio *)context)
46 static bool run(void * context)
48 bool jack_server_started;
49 unsigned int clients_count;
51 switch (cmd_ptr->command.state)
53 case LADISH_COMMAND_STATE_PENDING:
54 if (!studio_is_started())
56 log_info("Ignoring stop request because studio is already stopped.");
57 /* nothing to do, studio is not running */
58 cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE;
59 return true;
62 ladish_graph_dump(g_studio.jack_graph);
63 ladish_graph_dump(g_studio.studio_graph);
65 ladish_app_supervisor_stop(g_studio.app_supervisor);
67 cmd_ptr->command.state = LADISH_COMMAND_STATE_WAITING;
68 cmd_ptr->stop_state = STOP_STATE_WAITING_FOR_JACK_CLIENTS_DISAPPEAR;
69 /* fall through */
70 case LADISH_COMMAND_STATE_WAITING:
71 if (cmd_ptr->stop_state == STOP_STATE_WAITING_FOR_JACK_CLIENTS_DISAPPEAR)
73 clients_count = ladish_virtualizer_get_our_clients_count(g_studio.virtualizer);
74 log_info("%u JACK clients started by ladish are visible", clients_count);
75 if (clients_count != 0)
77 return true;
80 cmd_ptr->stop_state = STOP_STATE_WAITING_FOR_CHILDS_TERMINATION;
83 if (cmd_ptr->stop_state == STOP_STATE_WAITING_FOR_CHILDS_TERMINATION)
85 clients_count = loader_get_app_count();
86 log_info("%u child processes are running", clients_count);
87 if (clients_count != 0)
89 return true;
92 log_info("Stopping JACK server...");
94 ladish_graph_dump(g_studio.studio_graph);
96 cmd_ptr->stop_state = STOP_STATE_WAITING_FOR_JACK_SERVER_STOP;
98 if (!jack_proxy_stop_server())
100 log_error("Stopping JACK server failed. Waiting stop for 5 seconds anyway...");
102 /* JACK server stop sometimes fail, even if it actually succeeds after some time */
103 /* Reproducable with yoshimi-0.0.45 */
105 cmd_ptr->stop_waits = 5000;
106 return true;
110 ASSERT(cmd_ptr->stop_state == STOP_STATE_WAITING_FOR_JACK_SERVER_STOP);
112 if (cmd_ptr->stop_waits > 0)
114 if (!jack_proxy_is_started(&jack_server_started))
116 log_error("jack_proxy_is_started() failed.");
117 return false;
120 if (!jack_server_started)
122 ladish_environment_reset_stealth(&g_studio.env_store, ladish_environment_jack_server_started);
123 goto done;
126 if (cmd_ptr->stop_waits == 1)
128 log_error("JACK server stop wait after stop request expired.");
129 return false;
132 cmd_ptr->stop_waits--;
133 usleep(1000);
134 return true;
137 if (!ladish_environment_consume_change(&g_studio.env_store, ladish_environment_jack_server_started, &jack_server_started))
139 /* we are still waiting for the JACK server stop */
140 ASSERT(ladish_environment_get(&g_studio.env_store, ladish_environment_jack_server_started)); /* someone else consumed the state change? */
141 return true;
144 done:
145 log_info("Wait for JACK server stop complete.");
147 ladish_graph_hide_all(g_studio.jack_graph);
148 ladish_graph_hide_all(g_studio.studio_graph);
149 ASSERT(!jack_server_started);
151 ladish_graph_dump(g_studio.studio_graph);
153 on_event_jack_stopped();
155 cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE;
156 return true;
159 ASSERT_NO_PASS;
160 return false;
163 #undef cmd_ptr
165 bool ladish_command_stop_studio(void * call_ptr, struct ladish_cqueue * queue_ptr)
167 struct ladish_command_stop_studio * cmd_ptr;
169 cmd_ptr = ladish_command_new(sizeof(struct ladish_command_stop_studio));
170 if (cmd_ptr == NULL)
172 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "ladish_command_new() failed.");
173 goto fail;
176 cmd_ptr->command.run = run;
177 cmd_ptr->stop_waits = -1;
179 if (!ladish_cqueue_add_command(queue_ptr, &cmd_ptr->command))
181 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "ladish_cqueue_add_command() failed.");
182 goto fail_destroy_command;
185 return true;
187 fail_destroy_command:
188 free(cmd_ptr);
190 fail:
191 return false;