#include "child-process.h"
enum {
+ STARTED,
GOT_DATA,
GOT_SIGNAL,
EXITED,
TERMINATED,
+ STOPPED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
GIOChannel *to_child_channel;
GIOChannel *from_child_channel;
+ /* Timeout waiting for process to quit */
+ guint quit_timeout;
+
/* Process ID */
GPid pid;
};
static ChildProcess *parent_process = NULL;
static GHashTable *processes = NULL;
static int signal_pipe[2];
-static gboolean stopping = FALSE;
ChildProcess *
child_process_get_parent (void)
g_signal_emit (process, signals[TERMINATED], 0, WTERMSIG (status));
}
+ if (process->priv->quit_timeout)
+ g_source_remove (process->priv->quit_timeout);
+ process->priv->quit_timeout = 0;
process->priv->pid = 0;
g_hash_table_remove (processes, GINT_TO_POINTER (pid));
- /* Stop when all processes quit */
- if (stopping && g_hash_table_size (processes) == 0)
- exit (EXIT_SUCCESS);
+ g_signal_emit (process, signals[STOPPED], 0);
}
static void
g_hash_table_insert (processes, GINT_TO_POINTER (process->priv->pid), g_object_ref (process));
g_child_watch_add (process->priv->pid, child_process_watch_cb, process);
+ g_signal_emit (process, signals[STARTED], 0);
+
return TRUE;
}
return process->priv->from_child_channel;
}
-void
-child_process_stop_all (void)
+static gboolean
+quit_timeout_cb (ChildProcess *process)
{
- GHashTableIter iter;
- gpointer key, value;
-
- stopping = TRUE;
-
- /* If no processes, then just quit */
- if (g_hash_table_size (processes) == 0)
- exit (EXIT_SUCCESS);
+ process->priv->quit_timeout = 0;
+ child_process_signal (process, SIGKILL);
+ return FALSE;
+}
- g_hash_table_iter_init (&iter, processes);
- while (g_hash_table_iter_next (&iter, &key, &value))
- {
- ChildProcess *process = (ChildProcess *)value;
- child_process_signal (process, SIGTERM);
- }
+void
+child_process_stop (ChildProcess *process)
+{
+ /* Send SIGTERM, and then SIGKILL if no response */
+ process->priv->quit_timeout = g_timeout_add (5000, (GSourceFunc) quit_timeout_cb, process);
+ child_process_signal (process, SIGTERM);
}
static void
g_type_class_add_private (klass, sizeof (ChildProcessPrivate));
+ signals[STARTED] =
+ g_signal_new ("started",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ChildProcessClass, started),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
signals[GOT_DATA] =
g_signal_new ("got-data",
G_TYPE_FROM_CLASS (klass),
NULL, NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE, 1, G_TYPE_INT);
+ signals[STOPPED] =
+ g_signal_new ("stopped",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (ChildProcessClass, stopped),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
/* Catch signals and feed them to the main loop via a pipe */
processes = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
typedef struct
{
GObjectClass parent_class;
+ void (*started)(ChildProcess *process);
void (*got_data)(ChildProcess *process);
void (*got_signal)(ChildProcess *process, int signum);
void (*exited)(ChildProcess *process, int status);
- void (*terminated) (ChildProcess *process, int signum);
+ void (*terminated)(ChildProcess *process, int signum);
+ void (*stopped)(ChildProcess *process);
} ChildProcessClass;
GType child_process_get_type (void);
GIOChannel *child_process_get_from_child_channel (ChildProcess *process);
-void child_process_stop_all (void);
+void child_process_stop (ChildProcess *process);
+
+//void child_process_stop_all (void);
G_END_DECLS
#include "theme.h"
enum {
+ STARTED,
DISPLAY_ADDED,
+ STOPPED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
/* XDMCP server */
XDMCPServer *xdmcp_server;
+
+ /* TRUE if stopping the display manager (waiting for displays to stop) */
+ gboolean stopping;
};
G_DEFINE_TYPE (DisplayManager, display_manager, G_TYPE_OBJECT);
}
}
+static gboolean
+check_stopped (DisplayManager *manager)
+{
+ if (g_list_length (manager->priv->displays) == 0)
+ {
+ g_debug ("Display manager stopped");
+ g_signal_emit (manager, signals[STOPPED], 0);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+stopped_cb (Display *display, DisplayManager *manager)
+{
+ manager->priv->displays = g_list_remove (manager->priv->displays, display);
+ if (manager->priv->stopping)
+ check_stopped (manager);
+}
+
static guchar
atox (char c)
{
g_signal_connect (display, "start-greeter", G_CALLBACK (start_greeter_cb), manager);
g_signal_connect (display, "start-session", G_CALLBACK (start_session_cb), manager);
g_signal_connect (display, "end-session", G_CALLBACK (end_session_cb), manager);
+ g_signal_connect (display, "stopped", G_CALLBACK (stopped_cb), manager);
value = config_get_string (config_get_instance (), "LightDM", "session-wrapper");
if (value)
g_debug ("Starting XDMCP server on UDP/IP port %d", xdmcp_server_get_port (manager->priv->xdmcp_server));
xdmcp_server_start (manager->priv->xdmcp_server);
}
+
+ g_signal_emit (manager, signals[STARTED], 0);
}
+void
+display_manager_stop (DisplayManager *manager)
+{
+ GList *link;
+
+ g_debug ("Stopping display manager");
+
+ manager->priv->stopping = TRUE;
+
+ if (check_stopped (manager))
+ return;
+
+ for (link = manager->priv->displays; link; link = link->next)
+ {
+ Display *display = link->data;
+ display_stop (display);
+ }
+}
+
static void
display_manager_init (DisplayManager *manager)
{
g_type_class_add_private (klass, sizeof (DisplayManagerPrivate));
+ signals[STARTED] =
+ g_signal_new ("started",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DisplayManagerClass, started),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
signals[DISPLAY_ADDED] =
g_signal_new ("display-added",
G_TYPE_FROM_CLASS (klass),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, DISPLAY_TYPE);
+ signals[STOPPED] =
+ g_signal_new ("stopped",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DisplayManagerClass, stopped),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
}
{
GObjectClass parent_class;
+ void (*started)(DisplayManager *manager);
void (*display_added)(DisplayManager *manager, Display *display);
+ void (*stopped)(DisplayManager *manager);
} DisplayManagerClass;
GType display_manager_get_type (void);
void display_manager_start (DisplayManager *manager);
+void display_manager_stop (DisplayManager *manager);
+
G_END_DECLS
#endif /* _DISPLAY_MANAGER_H_ */
#define USER_SESSION_TIMEOUT 5000
enum {
+ STARTED,
START_GREETER,
END_GREETER,
START_SESSION,
END_SESSION,
- EXITED,
+ STOPPED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
/* Default session */
gchar *default_session;
+
+ /* TRUE if stopping the display (waiting for xserver, greeter and session to stop) */
+ gboolean stopping;
};
G_DEFINE_TYPE (Display, display, G_TYPE_OBJECT);
display->priv->user_session_timer = 0;
}
- g_object_unref (display->priv->user_session);
- display->priv->user_session = NULL;
-
pam_session_end (display->priv->user_pam_session);
g_object_unref (display->priv->user_pam_session);
display->priv->user_pam_session = NULL;
static void
user_session_exited_cb (Session *session, gint status, Display *display)
{
- end_user_session (display, status == 0);
+ if (!display->priv->stopping)
+ end_user_session (display, status == 0);
}
static void
user_session_terminated_cb (Session *session, gint signum, Display *display)
{
- end_user_session (display, FALSE);
+ if (!display->priv->stopping)
+ end_user_session (display, FALSE);
+}
+
+static void
+check_stopped (Display *display)
+{
+ if (display->priv->stopping &&
+ display->priv->xserver == NULL &&
+ display->priv->greeter_session == NULL &&
+ display->priv->user_session == NULL)
+ {
+ g_debug ("Display stopped");
+ g_signal_emit (display, signals[STOPPED], 0);
+ }
+}
+
+static void
+user_session_stopped_cb (Session *session, Display *display)
+{
+ g_signal_handlers_disconnect_matched (display->priv->user_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
+
+ g_object_unref (display->priv->user_session);
+ display->priv->user_session = NULL;
+ check_stopped (display);
}
static void
display->priv->user_session = session_new ();
g_signal_connect (G_OBJECT (display->priv->user_session), "exited", G_CALLBACK (user_session_exited_cb), display);
g_signal_connect (G_OBJECT (display->priv->user_session), "terminated", G_CALLBACK (user_session_terminated_cb), display);
+ g_signal_connect (G_OBJECT (display->priv->user_session), "stopped", G_CALLBACK (user_session_stopped_cb), display);
session_set_user (display->priv->user_session, user);
session_set_command (display->priv->user_session, session_command);
}
static void
-greeter_quit_cb (Greeter *greeter, Display *display)
+greeter_stopped_cb (Greeter *greeter, Display *display)
{
g_debug ("Greeter quit");
g_object_unref (display->priv->greeter_pam_session);
display->priv->greeter_pam_session = NULL;
- g_object_unref (display->priv->greeter_session);
- display->priv->greeter_session = NULL;
-
end_ck_session (display->priv->greeter_ck_cookie);
g_free (display->priv->greeter_ck_cookie);
display->priv->greeter_ck_cookie = NULL;
- /* Start session if waiting for greeter to quit */
- if (display->priv->user_session && child_process_get_pid (CHILD_PROCESS (display->priv->user_session)) == 0)
- really_start_user_session (display);
+ g_signal_handlers_disconnect_matched (display->priv->greeter_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
+ g_object_unref (display->priv->greeter_session);
+ display->priv->greeter_session = NULL;
+
+ if (display->priv->stopping)
+ {
+ check_stopped (display);
+ }
+ else
+ {
+ /* Start session if waiting for greeter to quit */
+ if (display->priv->user_session && child_process_get_pid (CHILD_PROCESS (display->priv->user_session)) == 0)
+ really_start_user_session (display);
+ }
}
static gboolean
greeter_set_default_user (display->priv->greeter_session, display->priv->default_user, display->priv->timeout);
greeter_set_default_session (display->priv->greeter_session, display->priv->default_session);
g_signal_connect (G_OBJECT (display->priv->greeter_session), "start-session", G_CALLBACK (greeter_start_session_cb), display);
- g_signal_connect (G_OBJECT (display->priv->greeter_session), "quit", G_CALLBACK (greeter_quit_cb), display);
+ g_signal_connect (G_OBJECT (display->priv->greeter_session), "stopped", G_CALLBACK (greeter_stopped_cb), display);
session_set_user (SESSION (display->priv->greeter_session), user);
command = theme_get_command (theme);
session_set_command (SESSION (display->priv->greeter_session), command);
return result;
}
-static void
-end_display (Display *display)
-{
- g_object_unref (display->priv->xserver);
- display->priv->xserver = NULL;
- g_signal_emit (display, signals[EXITED], 0);
-}
-
static void
xserver_exit_cb (XServer *server, int status, Display *display)
{
if (status != 0)
g_debug ("X server exited with value %d", status);
- end_display (display);
}
static void
xserver_terminate_cb (XServer *server, int signum, Display *display)
{
g_debug ("X server terminated with signal %d", signum);
- end_display (display);
+}
+
+static void
+xserver_stopped_cb (XServer *server, Display *display)
+{
+ g_signal_handlers_disconnect_matched (display->priv->xserver, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, display);
+ g_object_unref (display->priv->xserver);
+ display->priv->xserver = NULL;
+
+ // FIXME: Should restart xserver
+
+ check_stopped (display);
}
static void
gboolean
display_start (Display *display)
{
+ gboolean result;
+
g_return_val_if_fail (display != NULL, FALSE);
g_return_val_if_fail (display->priv->xserver != NULL, FALSE);
g_signal_connect (G_OBJECT (display->priv->xserver), "ready", G_CALLBACK (xserver_ready_cb), display);
g_signal_connect (G_OBJECT (display->priv->xserver), "exited", G_CALLBACK (xserver_exit_cb), display);
+ g_signal_connect (G_OBJECT (display->priv->xserver), "stopped", G_CALLBACK (xserver_stopped_cb), display);
g_signal_connect (G_OBJECT (display->priv->xserver), "terminated", G_CALLBACK (xserver_terminate_cb), display);
- return xserver_start (display->priv->xserver);
+ result = xserver_start (display->priv->xserver);
+
+ g_signal_emit (display, signals[STARTED], 0);
+
+ return result;
+}
+
+void
+display_stop (Display *display)
+{
+ g_debug ("Stopping display");
+
+ display->priv->stopping = TRUE;
+
+ if (display->priv->xserver)
+ child_process_stop (CHILD_PROCESS (display->priv->xserver));
+ if (display->priv->greeter_session)
+ child_process_stop (CHILD_PROCESS (display->priv->greeter_session));
+ if (display->priv->user_session)
+ child_process_stop (CHILD_PROCESS (display->priv->user_session));
}
static void
g_type_class_add_private (klass, sizeof (DisplayPrivate));
+ signals[STARTED] =
+ g_signal_new ("started",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (DisplayClass, started),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
signals[START_GREETER] =
g_signal_new ("start-greeter",
G_TYPE_FROM_CLASS (klass),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, SESSION_TYPE);
-
signals[END_GREETER] =
g_signal_new ("end-greeter",
G_TYPE_FROM_CLASS (klass),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, SESSION_TYPE);
-
signals[START_SESSION] =
g_signal_new ("start-session",
G_TYPE_FROM_CLASS (klass),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, SESSION_TYPE);
-
signals[END_SESSION] =
g_signal_new ("end-session",
G_TYPE_FROM_CLASS (klass),
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, SESSION_TYPE);
-
- signals[EXITED] =
- g_signal_new ("exited",
+ signals[STOPPED] =
+ g_signal_new ("stopped",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (DisplayClass, exited),
+ G_STRUCT_OFFSET (DisplayClass, stopped),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
{
GObjectClass parent_class;
+ void (*started)(Display *display);
void (*start_greeter)(Display *display, Session *session);
void (*end_greeter)(Display *display, Session *session);
void (*start_session)(Display *display, Session *session);
void (*end_session)(Display *display, Session *session);
- void (*exited)(Display *display);
+ void (*stopped)(Display *display);
} DisplayClass;
GType display_get_type (void);
gboolean display_start (Display *display);
+void display_stop (Display *display);
+
G_END_DECLS
#endif /* _DISPLAY_H_ */
enum {
START_SESSION,
- QUIT,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
return;*/
// FIXME: Issue with greeter, don't want to start a new one, report error to user
-
- g_signal_emit (greeter, signals[QUIT], 0);
}
static void
NULL, NULL,
ldm_marshal_VOID__STRING_STRING,
G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
- signals[QUIT] =
- g_signal_new ("quit",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GreeterClass, quit),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
g_type_class_add_private (klass, sizeof (GreeterPrivate));
}
{
SessionClass parent_class;
void (*start_session)(Greeter *greeter, const gchar *session, const gchar *language);
- void (*quit)(Greeter *greeter);
} GreeterClass;
GType greeter_get_type (void);
signal_cb (ChildProcess *process, int signum)
{
/* Quit when all child processes have ended */
- g_debug ("Caught %s signal, exiting", g_strsignal (signum));
- child_process_stop_all ();
+ g_debug ("Caught %s signal, shutting down", g_strsignal (signum));
+ display_manager_stop (display_manager);
+}
+
+static void
+display_manager_stopped_cb (DisplayManager *display_manager)
+{
+ g_debug ("All processes complete, exiting");
+ exit (EXIT_SUCCESS);
}
static void
g_debug ("Loaded configuration from %s", config_path);
display_manager = display_manager_new ();
+ g_signal_connect (display_manager, "stopped", G_CALLBACK (display_manager_stopped_cb), NULL);
display_manager_start (display_manager);