1 /* ovirt viewer console application
2 * Copyright (C) 2008 Red Hat Inc.
3 * Written by Richard W.M. Jones <rjones@redhat.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 /* Private functions. */
31 static gpointer wui_thread (gpointer data);
32 static void wui_thread_send_quit (void);
33 static gboolean do_connect (void);
34 static gboolean do_login (void);
35 static void refresh_vm_list (void);
37 /* Messages (main thread -> WUI thread only).
39 * These are passed by reference. They are allocated by the sender
40 * (ie. the main thread) and freed by the receiver (ie. the WUI thread).
43 QUIT, /* Tell the WUI thread to quit cleanly. */
44 CONNECT, /* Tell to connect (just fetch the URI). */
45 DISCONNECT, /* Tell to disconnect, forget state. */
46 LOGIN, /* Tell to login, and pass credentials. */
47 REFRESH_VM_LIST, /* Tell to refresh the VM list right away. */
51 enum message_type type;
56 /* Start the WUI thread. See main() for explanation of the threading model. */
57 static GThread *wui_gthread = NULL;
58 static GAsyncQueue *wui_thread_queue = NULL;
61 start_wui_thread (void)
65 DEBUG ("starting the WUI thread");
67 /* Create the message queue for main -> WUI thread communications. */
68 wui_thread_queue = g_async_queue_new ();
70 wui_gthread = g_thread_create (wui_thread, wui_thread_queue, TRUE, &error);
72 g_print ("%s\n", error->message);
79 stop_wui_thread (void)
81 DEBUG ("stopping the WUI thread");
84 /* Send a quit message then wait for the WUI thread to join.
86 * This "nice" shutdown could cause the UI to hang for an
87 * indefinite period (eg. if the WUI thread is engaged in some
88 * long connection or download from the remote server). But
89 * I want to keep it this way for the moment so that we can
90 * diagnose problems with the WUI thread.
92 * (This could be solved with some sort of interruptible
93 * join, but glib doesn't support that AFAICT).
95 wui_thread_send_quit ();
96 (void) g_thread_join (wui_gthread);
97 g_async_queue_unref (wui_thread_queue);
101 /* Send the quit message to the WUI thread. */
103 wui_thread_send_quit (void)
107 msg = g_new (struct message, 1);
109 g_async_queue_push (wui_thread_queue, msg);
112 /* Send the connect message to the WUI thread. */
114 wui_thread_send_connect (const char *uri)
118 msg = g_new (struct message, 1);
120 msg->str1 = g_strdup (uri);
121 g_async_queue_push (wui_thread_queue, msg);
124 /* Send the disconnect message to the WUI thread. */
126 wui_thread_send_disconnect (void)
130 msg = g_new (struct message, 1);
131 msg->type = DISCONNECT;
132 g_async_queue_push (wui_thread_queue, msg);
135 /* Send the login message to the WUI thread. */
137 wui_thread_send_login (const char *username, const char *password)
141 msg = g_new (struct message, 1);
143 msg->str1 = g_strdup (username);
144 msg->str2 = g_strdup (password);
145 g_async_queue_push (wui_thread_queue, msg);
148 /* Send the refresh VM list message to the WUI thread. */
150 wui_thread_send_refresh_vm_list (void)
154 msg = g_new (struct message, 1);
155 msg->type = REFRESH_VM_LIST;
156 g_async_queue_push (wui_thread_queue, msg);
159 /* The current state.
161 * For safety, the main thread must lock this before reading, and the
162 * WUI thread must lock this before writing. However the WUI thread
163 * does not need to lock before reading, because no other thread
166 static gboolean connected = FALSE;
167 static gboolean logged_in = FALSE;
168 static gboolean busy = FALSE;
169 static GStaticMutex state_mutex;
171 static void set_connected (gboolean);
172 static void set_logged_in (gboolean);
173 static void set_busy (gboolean);
175 /* The private state of the WUI thread. */
176 static int secs_between_refresh = 60;
177 static char *uri = NULL;
178 static char *username = NULL;
179 static char *password = NULL;
181 static gboolean process_message (struct message *);
183 /* The WUI thread. See main() above for explanation of
184 * the threading model.
187 wui_thread (gpointer _queue)
189 GAsyncQueue *queue = (GAsyncQueue *) _queue;
190 gboolean quit = FALSE;
195 DEBUG ("WUI thread starting up");
197 g_async_queue_ref (queue);
199 /* In the thread's loop we check for new instructions from the main
200 * thread and carry them out. Also, if we are connected and logged
201 * in then we periodically recheck the list of VMs.
207 g_get_current_time (&tv);
208 g_time_val_add (&tv, secs_between_refresh * 1000000);
209 _msg = g_async_queue_timed_pop (queue, &tv);
211 _msg = g_async_queue_pop (queue);
215 msg = (struct message *) _msg;
218 DEBUG ("received message %d", msg->type);
219 quit = process_message (msg);
220 /* Don't free any strings in the message - we've saved them. */
223 /* No message, must have got a timeout instead, which means
224 * we are logged in and we should refresh the list of VMs.
225 * Note it's not an error if we temporarily lose contact
232 DEBUG ("WUI thread shutting down cleanly");
234 g_async_queue_unref (queue);
235 g_thread_exit (NULL);
236 return NULL; /* not reached? */
239 /* The WUI thread calls this to safely update the state variables.
240 * This also updates elements in the UI by setting idle callbacks
241 * which are executed in the context of the main thread.
244 set_connected (gboolean new_connected)
246 g_static_mutex_lock (&state_mutex);
247 connected = new_connected;
248 g_static_mutex_unlock (&state_mutex);
252 set_logged_in (gboolean new_logged_in)
254 g_static_mutex_lock (&state_mutex);
255 logged_in = new_logged_in;
256 g_static_mutex_unlock (&state_mutex);
260 set_busy (gboolean new_busy)
262 g_static_mutex_lock (&state_mutex);
264 g_static_mutex_unlock (&state_mutex);
267 /* The main thread should call these functions to get the WUI thread's
271 wui_thread_is_connected (void)
275 g_static_mutex_lock (&state_mutex);
277 g_static_mutex_unlock (&state_mutex);
282 wui_thread_is_logged_in (void)
286 g_static_mutex_lock (&state_mutex);
288 g_static_mutex_unlock (&state_mutex);
293 wui_thread_is_busy (void)
297 g_static_mutex_lock (&state_mutex);
299 g_static_mutex_unlock (&state_mutex);
303 /* Process a message from the main thread. */
305 process_message (struct message *msg)
309 if (uri) g_free (uri);
310 if (username) g_free (username);
311 if (password) g_free (password);
312 set_connected (FALSE);
313 set_logged_in (FALSE);
317 if (uri) g_free (uri);
321 set_connected (TRUE);
323 set_connected (FALSE);
324 set_logged_in (FALSE);
329 /* This just forgets the state. REST is connectionless. */
330 if (uri) g_free (uri);
331 if (username) g_free (username);
332 if (password) g_free (password);
333 set_connected (FALSE);
334 set_logged_in (FALSE);
338 if (username) g_free (username);
339 username = msg->str1;
340 if (password) g_free (password);
341 password = msg->str2;
345 set_logged_in (TRUE);
348 set_logged_in (FALSE);
353 case REFRESH_VM_LIST:
355 secs_between_refresh = 60;
359 DEBUG ("unknown message type %d", msg->type);
366 /* Try to connect to the current URI. Returns true on success. */
370 DEBUG ("connecting to uri %s", uri);
374 /* Try to login to URI/login with the username and password given.
375 * Returns true on success.
380 DEBUG ("logging in with username %s, password *****", username);
384 /* Refresh the list of VMs. */
386 refresh_vm_list (void)
388 DEBUG ("refreshing list of VMs");