uvtd: add new Virtual Terminal daemon

This introduces uvtd which replaces kmscon sessions as an external helper
program. It's still a dummy program but it will get extended soon. After
that, kmscon sessions will get removed and limited to a single seat. This
will simplify kmscon itself heavily and move rarely used features out of
kmscon into helpers.

Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
This commit is contained in:
David Herrmann 2013-03-04 15:11:30 +01:00
parent 9c2375b6d4
commit 176a0e8be5
6 changed files with 1006 additions and 2 deletions

1
.gitignore vendored
View File

@ -40,6 +40,7 @@ docs/reference/kmscon.????*
docs/reference/*.stamp
docs/reference/version.xml
docs/reference/*/
uvtd
wlterm
docs/man/*.1
docs/man/*.3

View File

@ -1,6 +1,6 @@
#
# Kmscon - Global Makefile
# Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
# Copyright (c) 2012-2013 David Herrmann <dh.herrmann@googlemail.com>
#
#
@ -30,7 +30,7 @@ LIBUTERM_AGE = 0
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
AM_MAKEFLAGS = --no-print-directory
AUTOMAKE_OPTIONS = color-tests
AM_DISTCHECK_CONFIGURE_FLAGS = --enable-wlterm
AM_DISTCHECK_CONFIGURE_FLAGS = --enable-wlterm --enable-uvtd
SUBDIRS = .
@ -687,6 +687,27 @@ wlterm_LDADD = \
libshl.la \
-lpthread
#
# uvtd
#
if BUILD_ENABLE_UVTD
bin_PROGRAMS += uvtd
endif
uvtd_SOURCES = \
src/uvtd_main.c \
src/uvtd_seat.h \
src/uvtd_seat.c
uvtd_CPPFLAGS = \
$(AM_CPPFLAGS) \
$(XKBCOMMON_CFLAGS)
uvtd_LDADD = \
$(XKBCOMMON_LIBS) \
libeloop.la \
libshl.la \
libuterm.la
#
# Tests
#

View File

@ -188,6 +188,16 @@ if test "x$enable_wlterm" = "x" ; then
fi
AC_MSG_RESULT([$enable_wlterm])
# uvtd
AC_MSG_CHECKING([whether user wants uvtd])
AC_ARG_ENABLE([uvtd],
[AS_HELP_STRING([--enable-uvtd],
[build uvtd])])
if test "x$enable_uvtd" = "x" ; then
enable_uvtd="no (default)"
fi
AC_MSG_RESULT([$enable_uvtd])
# debug
AC_MSG_CHECKING([whether to build with debugging on])
AC_ARG_ENABLE([debug],
@ -803,6 +813,30 @@ else
wlterm_missing="enable-wlterm"
fi
# uvtd
uvtd_avail=no
uvtd_missing=""
if test ! "x$enable_uvtd" = "xno" ; then
uvtd_avail=yes
if test "x$uvt_avail" = "xno" ; then
uvtd_avail=no
uvtd_missing="$uvt_missing,$uvtd_missing"
fi
if test "x$eloop_avail" = "xno" ; then
uvtd_avail=no
uvtd_missing="$eloop_missing,$uvtd_missing"
fi
if test "x$uvtd_avail" = "xno" ; then
if test "x$enable_uvtd" = "xyes" ; then
AC_ERROR([missing for uvtd: $uvtd_missing])
fi
fi
else
uvtd_missing="enable-uvtd"
fi
#
# Enable all required modules
# We now know which modules can be built by checking the *_avail variables set
@ -811,6 +845,16 @@ fi
# needs them. This is done top-down of course.
#
# uvtd
uvtd_enabled=no
if test "x$uvtd_avail" = "xyes" ; then
if test "x${enable_uvtd% *}" = "xyes" ; then
uvtd_enabled=yes
enable_eloop=yes
enable_uvt=yes
fi
fi
# wlterm
wlterm_enabled=no
if test "x$wlterm_avail" = "xyes" ; then
@ -1194,6 +1238,10 @@ AM_CONDITIONAL([BUILD_ENABLE_KMSCON],
AM_CONDITIONAL([BUILD_ENABLE_WLTERM],
[test "x$wlterm_enabled" = "xyes"])
# uvtd
AM_CONDITIONAL([BUILD_ENABLE_UVTD],
[test "x$uvtd_enabled" = "xyes"])
#
# Miscellaneous Checks
# All checks below are independent of module checking or depend on the results
@ -1278,6 +1326,7 @@ AC_MSG_NOTICE([Build configuration:
Applications and Libraries:
kmscon: $kmscon_enabled ($kmscon_avail: $kmscon_missing)
wlterm: $wlterm_enabled ($wlterm_avail: $wlterm_missing)
uvtd: $uvtd_enabled ($uvtd_avail: $uvtd_missing)
uterm: $uterm_enabled ($uterm_avail: $uterm_missing)
tsm: $tsm_enabled ($tsm_avail: $tsm_missing)
uvt: $uvt_enabled ($uvt_avail: $uvt_missing)

243
src/uvtd_main.c Normal file
View File

@ -0,0 +1,243 @@
/*
* uvtd - User-space VT daemon
*
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@googlemail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/signalfd.h>
#include "eloop.h"
#include "shl_dlist.h"
#include "shl_log.h"
#include "uterm_input.h"
#include "uterm_monitor.h"
#include "uvtd_seat.h"
struct app_seat {
struct shl_dlist list;
struct uvtd_app *app;
struct uterm_monitor_seat *useat;
struct uvtd_seat *seat;
};
struct uvtd_app {
struct ev_eloop *eloop;
struct uterm_monitor *mon;
struct shl_dlist seats;
};
static void app_seat_event(struct uvtd_seat *seat, unsigned int ev, void *data)
{
}
static int app_seat_new(struct uvtd_app *app, const char *sname,
struct uterm_monitor_seat *useat)
{
struct app_seat *seat;
int ret;
seat = malloc(sizeof(*seat));
if (!seat)
return -ENOMEM;
log_debug("new seat %p on %s", seat, sname);
memset(seat, 0, sizeof(*seat));
seat->app = app;
seat->useat = useat;
ret = uvtd_seat_new(&seat->seat, sname, app->eloop, app_seat_event,
seat);
if (ret)
goto err_free;
uterm_monitor_set_seat_data(seat->useat, seat);
shl_dlist_link(&app->seats, &seat->list);
return 0;
err_free:
free(seat);
return ret;
}
static void app_seat_free(struct app_seat *seat)
{
log_debug("free seat %p", seat);
shl_dlist_unlink(&seat->list);
uterm_monitor_set_seat_data(seat->useat, NULL);
uvtd_seat_free(seat->seat);
free(seat);
}
static void app_monitor_event(struct uterm_monitor *mon,
struct uterm_monitor_event *ev,
void *data)
{
struct uvtd_app *app = data;
struct app_seat *seat;
int ret;
switch (ev->type) {
case UTERM_MONITOR_NEW_SEAT:
ret = app_seat_new(app, ev->seat_name, ev->seat);
if (ret)
return;
break;
case UTERM_MONITOR_FREE_SEAT:
if (ev->seat_data)
app_seat_free(ev->seat_data);
break;
case UTERM_MONITOR_NEW_DEV:
seat = ev->seat_data;
if (!seat)
return;
switch (ev->dev_type) {
case UTERM_MONITOR_INPUT:
log_debug("new input device %s on seat %p",
ev->dev_node, seat);
break;
}
break;
case UTERM_MONITOR_FREE_DEV:
seat = ev->seat_data;
if (!seat)
return;
switch (ev->dev_type) {
case UTERM_MONITOR_INPUT:
log_debug("free input device %s on seat %p",
ev->dev_node, seat);
break;
}
break;
}
}
static void app_sig_generic(struct ev_eloop *eloop,
struct signalfd_siginfo *info,
void *data)
{
struct uvtd_app *app = data;
log_info("terminating due to caught signal %d", info->ssi_signo);
ev_eloop_exit(app->eloop);
}
static void app_sig_ignore(struct ev_eloop *eloop,
struct signalfd_siginfo *info,
void *data)
{
}
static void destroy_app(struct uvtd_app *app)
{
uterm_monitor_unref(app->mon);
ev_eloop_unregister_signal_cb(app->eloop, SIGPIPE, app_sig_ignore,
app);
ev_eloop_unregister_signal_cb(app->eloop, SIGINT, app_sig_generic,
app);
ev_eloop_unregister_signal_cb(app->eloop, SIGTERM, app_sig_generic,
app);
ev_eloop_unref(app->eloop);
}
static int setup_app(struct uvtd_app *app)
{
int ret;
shl_dlist_init(&app->seats);
ret = ev_eloop_new(&app->eloop, log_llog, NULL);
if (ret) {
log_error("cannot create eloop object: %d", ret);
goto err_app;
}
ret = ev_eloop_register_signal_cb(app->eloop, SIGTERM,
app_sig_generic, app);
if (ret) {
log_error("cannot register SIGTERM signal handler: %d", ret);
goto err_app;
}
ret = ev_eloop_register_signal_cb(app->eloop, SIGINT,
app_sig_generic, app);
if (ret) {
log_error("cannot register SIGINT signal handler: %d", ret);
goto err_app;
}
ret = ev_eloop_register_signal_cb(app->eloop, SIGPIPE,
app_sig_ignore, app);
if (ret) {
log_error("cannot register SIGPIPE signal handler: %d", ret);
goto err_app;
}
ret = uterm_monitor_new(&app->mon, app->eloop, app_monitor_event, app);
if (ret) {
log_error("cannot create device monitor: %d", ret);
goto err_app;
}
log_debug("scanning for devices...");
uterm_monitor_scan(app->mon);
return 0;
err_app:
destroy_app(app);
return ret;
}
int main(int argc, char **argv)
{
int ret;
struct uvtd_app app;
log_set_config(&LOG_CONFIG_INFO(1, 1));
log_print_init("uvtd");
memset(&app, 0, sizeof(app));
ret = setup_app(&app);
if (ret)
goto err_out;
ev_eloop_run(app.eloop, -1);
ret = 0;
destroy_app(&app);
err_out:
if (ret)
log_err("cannot initialize uvtd, errno %d: %s",
ret, strerror(-ret));
log_info("exiting");
return -ret;
}

594
src/uvtd_seat.c Normal file
View File

@ -0,0 +1,594 @@
/*
* uvtd - User-space VT daemon
*
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* Seats
* Each set of input+output devices form a single seat. Each seat is independent
* of each other and there can be exactly one user per seat interacting with the
* system.
* Per seat, we have multiple sessions. But only one session can be active at a
* time per seat. We allow external sessions, so session activation/deactivation
* may be asynchronous.
*
* A seat object manages all the sessions for a single seat. As long as a seat
* is asleep, no session is active. If you wake it up, the seat manager
* automatically schedules a session. You can then request other sessions to be
* scheduled and the seat manager will try to deactivate the current session and
* reactivate the new session.
*
* Note that session deactivation may be asynchronous (unless forced). So some
* calls might return -EINPROGRESS if the session-deactivation is pending. This
* shouldn't bother the user as the session will notify back soon that the
* deactivation was successfull. However, if it doesn't the user can chose to
* perform any other action and we will retry the operation. As a last resort,
* you can always kill the session by unregistering it or forcing a
* deactivation.
* "async_schedule" tracks the task that requested the deactivation of a
* session. So when the session notifies us that it got deactivated, we know
* what the user wanted and can perform the requested task now.
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "eloop.h"
#include "shl_dlist.h"
#include "shl_log.h"
#include "uvtd_seat.h"
#define LOG_SUBSYSTEM "seat"
struct uvtd_session {
struct shl_dlist list;
unsigned long ref;
struct uvtd_seat *seat;
bool enabled;
bool deactivating;
uvtd_session_cb_t cb;
void *data;
};
/* task that requested the pending session-deactivation */
enum uvtd_async_schedule {
SCHEDULE_NONE, /* default, causes a reschedule */
SCHEDULE_SWITCH, /* causes a reschedule */
SCHEDULE_SLEEP, /* puts the seat asleep */
SCHEDULE_UNREGISTER, /* unregisters the session */
};
struct uvtd_seat {
struct ev_eloop *eloop;
char *name;
size_t session_count;
struct shl_dlist sessions;
bool awake;
struct uvtd_session *current_sess;
struct uvtd_session *scheduled_sess;
struct uvtd_session *dummy_sess;
unsigned int async_schedule;
uvtd_seat_cb_t cb;
void *data;
};
static int session_call(struct uvtd_session *sess, unsigned int event)
{
if (!sess->cb)
return 0;
return sess->cb(sess, event, sess->data);
}
static int session_call_activate(struct uvtd_session *sess)
{
log_debug("activate session %p", sess);
return session_call(sess, UVTD_SESSION_ACTIVATE);
}
static int session_call_deactivate(struct uvtd_session *sess)
{
log_debug("deactivate session %p", sess);
return session_call(sess, UVTD_SESSION_DEACTIVATE);
}
/* drop the current session as if it was successfully deactivated */
static void seat_yield(struct uvtd_seat *seat)
{
if (!seat->current_sess)
return;
seat->current_sess->deactivating = false;
seat->current_sess = NULL;
seat->async_schedule = SCHEDULE_NONE;
}
static int seat_go_asleep(struct uvtd_seat *seat, bool force)
{
int ret = 0;
if (!seat->awake)
return 0;
if (seat->current_sess) {
ret = -EBUSY;
if (!force)
return ret;
seat_yield(seat);
}
seat->awake = false;
if (seat->cb)
seat->cb(seat, UVTD_SEAT_SLEEP, seat->data);
return ret;
}
static void seat_go_awake(struct uvtd_seat *seat)
{
if (seat->awake)
return;
seat->awake = true;
}
static int seat_run(struct uvtd_seat *seat)
{
int ret;
struct uvtd_session *session;
if (!seat->awake)
return -EBUSY;
if (seat->current_sess)
return 0;
if (!seat->scheduled_sess) {
log_debug("no session scheduled to run (num: %zu)",
seat->session_count);
return -ENOENT;
}
session = seat->scheduled_sess;
/* TODO: unregister session and try next on failure */
ret = session_call_activate(session);
if (ret) {
log_warning("cannot activate session %p: %d", session, ret);
return ret;
}
seat->current_sess = session;
return 0;
}
static int seat_pause(struct uvtd_seat *seat, bool force, unsigned int async)
{
int ret;
if (!seat->current_sess)
return 0;
/* TODO: pass \force to the session */
seat->current_sess->deactivating = true;
ret = session_call_deactivate(seat->current_sess);
if (ret) {
if (!force && ret == -EINPROGRESS) {
seat->async_schedule = async;
log_debug("pending deactivation for session %p",
seat->current_sess);
} else {
log_warning("cannot deactivate session %p (%d): %d",
seat->current_sess, force, ret);
}
if (!force)
return ret;
}
seat_yield(seat);
return ret;
}
static void seat_reschedule(struct uvtd_seat *seat)
{
struct shl_dlist *iter, *start;
struct uvtd_session *sess;
if (seat->scheduled_sess && seat->scheduled_sess->enabled)
return;
if (seat->current_sess && seat->current_sess->enabled) {
seat->scheduled_sess = seat->current_sess;
return;
}
if (seat->current_sess)
start = &seat->current_sess->list;
else
start = &seat->sessions;
shl_dlist_for_each_but_one(iter, start, &seat->sessions) {
sess = shl_dlist_entry(iter, struct uvtd_session, list);
if (sess != seat->dummy_sess && sess->enabled) {
seat->scheduled_sess = sess;
return;
}
}
if (seat->dummy_sess && seat->dummy_sess->enabled)
seat->scheduled_sess = seat->dummy_sess;
else
seat->scheduled_sess = NULL;
}
static bool seat_has_schedule(struct uvtd_seat *seat)
{
return seat->scheduled_sess &&
seat->scheduled_sess != seat->current_sess;
}
static int seat_switch(struct uvtd_seat *seat)
{
int ret;
ret = seat_pause(seat, false, SCHEDULE_SWITCH);
if (ret)
return ret;
return seat_run(seat);
}
static void seat_schedule(struct uvtd_seat *seat, struct uvtd_session *sess)
{
seat->scheduled_sess = sess;
seat_reschedule(seat);
if (seat_has_schedule(seat))
seat_switch(seat);
}
static void seat_next(struct uvtd_seat *seat, bool reverse)
{
struct shl_dlist *cur, *iter;
struct uvtd_session *s, *next;
if (seat->current_sess)
cur = &seat->current_sess->list;
else if (seat->session_count)
cur = &seat->sessions;
else
return;
next = NULL;
if (!seat->current_sess && seat->dummy_sess &&
seat->dummy_sess->enabled)
next = seat->dummy_sess;
if (reverse) {
shl_dlist_for_each_reverse_but_one(iter, cur,
&seat->sessions) {
s = shl_dlist_entry(iter, struct uvtd_session, list);
if (s->enabled && seat->dummy_sess != s) {
next = s;
break;
}
}
} else {
shl_dlist_for_each_but_one(iter, cur, &seat->sessions) {
s = shl_dlist_entry(iter, struct uvtd_session, list);
if (s->enabled && seat->dummy_sess != s) {
next = s;
break;
}
}
}
if (!next)
return;
seat_schedule(seat, next);
}
int uvtd_seat_new(struct uvtd_seat **out, const char *seatname,
struct ev_eloop *eloop, uvtd_seat_cb_t cb, void *data)
{
struct uvtd_seat *seat;
int ret;
if (!out || !eloop || !seatname)
return -EINVAL;
seat = malloc(sizeof(*seat));
if (!seat)
return -ENOMEM;
memset(seat, 0, sizeof(*seat));
seat->eloop = eloop;
seat->cb = cb;
seat->data = data;
shl_dlist_init(&seat->sessions);
seat->name = strdup(seatname);
if (!seat->name) {
ret = -ENOMEM;
goto err_free;
}
ev_eloop_ref(seat->eloop);
*out = seat;
return 0;
err_free:
free(seat);
return ret;
}
void uvtd_seat_free(struct uvtd_seat *seat)
{
struct uvtd_session *s;
int ret;
if (!seat)
return;
ret = seat_pause(seat, true, SCHEDULE_NONE);
if (ret)
log_warning("destroying seat %s while session %p is active",
seat->name, seat->current_sess);
ret = seat_go_asleep(seat, true);
if (ret)
log_warning("destroying seat %s while still awake: %d",
seat->name, ret);
while (!shl_dlist_empty(&seat->sessions)) {
s = shl_dlist_entry(seat->sessions.next, struct uvtd_session,
list);
uvtd_session_unregister(s);
}
free(seat->name);
ev_eloop_unref(seat->eloop);
free(seat);
}
const char *uvtd_seat_get_name(struct uvtd_seat *seat)
{
return seat ? seat->name : NULL;
}
struct ev_eloop *uvtd_seat_get_eloop(struct uvtd_seat *seat)
{
return seat ? seat->eloop : NULL;
}
int uvtd_seat_sleep(struct uvtd_seat *seat, bool force)
{
int ret, err = 0;
if (!seat)
return -EINVAL;
ret = seat_pause(seat, force, SCHEDULE_SLEEP);
if (ret) {
if (force)
err = ret;
else
return ret;
}
ret = seat_go_asleep(seat, force);
if (ret) {
if (force)
err = ret;
else
return ret;
}
return err;
}
void uvtd_seat_wake_up(struct uvtd_seat *seat)
{
if (!seat)
return;
seat_go_awake(seat);
seat_run(seat);
}
int uvtd_seat_register_session(struct uvtd_seat *seat,
struct uvtd_session **out,
unsigned int id, uvtd_session_cb_t cb,
void *data)
{
struct uvtd_session *sess;
if (!seat || !out)
return -EINVAL;
sess = malloc(sizeof(*sess));
if (!sess)
return -ENOMEM;
log_debug("register session %p", sess);
memset(sess, 0, sizeof(*sess));
sess->ref = 1;
sess->seat = seat;
sess->cb = cb;
sess->data = data;
/* TODO: add support for \ids */
/* register new sessions next to the current one */
if (seat->current_sess)
shl_dlist_link(&seat->current_sess->list, &sess->list);
else
shl_dlist_link_tail(&seat->sessions, &sess->list);
++seat->session_count;
*out = sess;
return 0;
}
void uvtd_session_ref(struct uvtd_session *sess)
{
if (!sess || !sess->ref)
return;
++sess->ref;
}
void uvtd_session_unref(struct uvtd_session *sess)
{
if (!sess || !sess->ref || --sess->ref)
return;
uvtd_session_unregister(sess);
free(sess);
}
void uvtd_session_unregister(struct uvtd_session *sess)
{
struct uvtd_seat *seat;
int ret;
bool forced = false;
if (!sess || !sess->seat)
return;
log_debug("unregister session %p", sess);
seat = sess->seat;
sess->enabled = false;
if (seat->dummy_sess == sess)
seat->dummy_sess = NULL;
seat_reschedule(seat);
if (seat->current_sess == sess) {
ret = seat_pause(seat, true, SCHEDULE_NONE);
if (ret) {
forced = true;
log_warning("unregistering active session %p; skipping automatic session-switch",
sess);
}
}
shl_dlist_unlink(&sess->list);
--seat->session_count;
sess->seat = NULL;
session_call(sess, UVTD_SESSION_UNREGISTER);
uvtd_session_unref(sess);
/* If this session was active and we couldn't deactivate it, then it
* might still have resources allocated that couldn't get freed. In this
* case we should not automatically switch to the next session as it is
* very likely that it will not be able to start.
* Instead, we stay inactive and wait for user/external input to switch
* to another session. This delay will then hopefully be long enough so
* all resources got freed. */
if (!forced)
seat_run(seat);
}
bool uvtd_session_is_registered(struct uvtd_session *sess)
{
return sess && sess->seat;
}
bool uvtd_session_is_active(struct uvtd_session *sess)
{
return sess && sess->seat && sess->seat->current_sess == sess;
}
void uvtd_session_schedule(struct uvtd_session *sess)
{
if (!sess || !sess->seat)
return;
seat_schedule(sess->seat, sess);
}
void uvtd_session_enable(struct uvtd_session *sess)
{
if (!sess || sess->enabled)
return;
log_debug("enable session %p", sess);
sess->enabled = true;
if (sess->seat &&
(!sess->seat->current_sess ||
sess->seat->current_sess == sess->seat->dummy_sess))
seat_schedule(sess->seat, sess);
}
void uvtd_session_disable(struct uvtd_session *sess)
{
if (!sess || !sess->enabled)
return;
log_debug("disable session %p", sess);
sess->enabled = false;
}
bool uvtd_session_is_enabled(struct uvtd_session *sess)
{
return sess && sess->enabled;
}
void uvtd_session_notify_deactivated(struct uvtd_session *sess)
{
struct uvtd_seat *seat;
unsigned int sched;
if (!sess || !sess->seat)
return;
seat = sess->seat;
if (seat->current_sess != sess)
return;
sched = seat->async_schedule;
log_debug("session %p notified core about deactivation (schedule: %u)",
sess, sched);
seat_yield(seat);
seat_reschedule(seat);
if (sched == SCHEDULE_SLEEP)
seat_go_asleep(seat, false);
else if (sched == SCHEDULE_UNREGISTER)
uvtd_session_unregister(sess);
else
seat_run(seat);
}

96
src/uvtd_seat.h Normal file
View File

@ -0,0 +1,96 @@
/*
* uvtd - User-space VT daemon
*
* Copyright (c) 2012-2013 David Herrmann <dh.herrmann@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* Seats
* Each set of input+output devices form a single seat. Each seat is independent
* of each other and there can be exactly one user per seat interacting with the
* system.
* Per seat, we have multiple sessions. But only one session can be active at a
* time per seat. We allow external sessions, so session activation/deactivation
* may be asynchronous.
*/
#ifndef UVTD_SEAT_H
#define UVTD_SEAT_H
#include <stdlib.h>
#include "eloop.h"
/* sessions */
struct uvtd_session;
enum uvtd_session_event_type {
UVTD_SESSION_ACTIVATE,
UVTD_SESSION_DEACTIVATE,
UVTD_SESSION_UNREGISTER,
};
typedef int (*uvtd_session_cb_t) (struct uvtd_session *session,
unsigned int event,
void *data);
void uvtd_session_ref(struct uvtd_session *sess);
void uvtd_session_unref(struct uvtd_session *sess);
void uvtd_session_unregister(struct uvtd_session *sess);
bool uvtd_session_is_registered(struct uvtd_session *sess);
bool uvtd_session_is_active(struct uvtd_session *sess);
void uvtd_session_schedule(struct uvtd_session *sess);
void uvtd_session_enable(struct uvtd_session *sess);
void uvtd_session_disable(struct uvtd_session *sess);
bool uvtd_session_is_enabled(struct uvtd_session *sess);
void uvtd_session_notify_deactivated(struct uvtd_session *sess);
/* seats */
struct uvtd_seat;
enum uvtd_seat_event {
UVTD_SEAT_SLEEP,
};
typedef void (*uvtd_seat_cb_t) (struct uvtd_seat *seat, unsigned int event,
void *data);
int uvtd_seat_new(struct uvtd_seat **out, const char *seatname,
struct ev_eloop *eloop, uvtd_seat_cb_t cb, void *data);
void uvtd_seat_free(struct uvtd_seat *seat);
const char *uvtd_seat_get_name(struct uvtd_seat *seat);
struct ev_eloop *uvtd_seat_get_eloop(struct uvtd_seat *seat);
int uvtd_seat_sleep(struct uvtd_seat *seat, bool force);
void uvtd_seat_wake_up(struct uvtd_seat *seat);
void uvtd_seat_schedule(struct uvtd_seat *seat, unsigned int id);
int uvtd_seat_register_session(struct uvtd_seat *seat,
struct uvtd_session **out,
unsigned int id, uvtd_session_cb_t cb,
void *data);
#endif /* UVTD_SEAT_H */