tools: console: make console virLockableObject

We need to turn console into virObject object because stream/fd callbacks
can be called from the event loop thread after freeing console
in main thread. It is convinient to turn into virLockableObject as
we have mutex in console object.

Reviewed-by: Cole Robinson <crobinso@redhat.com>
Signed-off-by: Nikolay Shirokovskiy <nshirokovskiy@virtuozzo.com>
This commit is contained in:
Nikolay Shirokovskiy 2019-03-18 11:53:06 +03:00
parent e3389d830c
commit 98361cc3b9

View File

@ -60,9 +60,10 @@ struct virConsoleBuffer {
typedef struct virConsole virConsole;
typedef virConsole *virConsolePtr;
struct virConsole {
virObjectLockable parent;
virStreamPtr st;
bool quit;
virMutex lock;
virCond cond;
int stdinWatch;
@ -74,6 +75,19 @@ struct virConsole {
char escapeChar;
};
static virClassPtr virConsoleClass;
static void virConsoleDispose(void *obj);
static int
virConsoleOnceInit(void)
{
if (!VIR_CLASS_NEW(virConsole, virClassForObjectLockable()))
return -1;
return 0;
}
VIR_ONCE_GLOBAL_INIT(virConsole);
static void
virConsoleHandleSignal(int sig ATTRIBUTE_UNUSED)
@ -104,16 +118,14 @@ virConsoleShutdown(virConsolePtr con)
static void
virConsoleFree(virConsolePtr con)
virConsoleDispose(void *obj)
{
if (!con)
return;
virConsolePtr con = obj;
if (con->st)
virStreamFree(con->st);
virMutexDestroy(&con->lock);
virCondDestroy(&con->cond);
VIR_FREE(con);
}
@ -288,6 +300,35 @@ virConsoleEventOnStdout(int watch ATTRIBUTE_UNUSED,
}
static virConsolePtr
virConsoleNew(void)
{
virConsolePtr con;
if (virConsoleInitialize() < 0)
return NULL;
if (!(con = virObjectNew(virConsoleClass)))
return NULL;
if (virCondInit(&con->cond) < 0) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("cannot initialize console condition"));
goto error;
}
con->stdinWatch = -1;
con->stdoutWatch = -1;
return con;
error:
virObjectUnref(con);
return NULL;
}
static char
virshGetEscapeChar(const char *s)
{
@ -324,6 +365,11 @@ virshRunConsole(vshControl *ctl,
if (vshTTYMakeRaw(ctl, true) < 0)
goto resettty;
if (!(con = virConsoleNew()))
goto resettty;
virObjectLock(con);
/* Trap all common signals so that we can safely restore the original
* terminal settings on STDIN before the process exits - people don't like
* being left with a messed up terminal ! */
@ -333,9 +379,6 @@ virshRunConsole(vshControl *ctl,
sigaction(SIGHUP, &sighandler, &old_sighup);
sigaction(SIGPIPE, &sighandler, &old_sigpipe);
if (VIR_ALLOC(con) < 0)
goto cleanup;
con->escapeChar = virshGetEscapeChar(priv->escapeChar);
con->st = virStreamNew(virDomainGetConnect(dom),
VIR_STREAM_NONBLOCK);
@ -345,11 +388,6 @@ virshRunConsole(vshControl *ctl,
if (virDomainOpenConsole(dom, dev_name, con->st, flags) < 0)
goto cleanup;
if (virCondInit(&con->cond) < 0 || virMutexInit(&con->lock) < 0)
goto cleanup;
virMutexLock(&con->lock);
con->stdinWatch = virEventAddHandle(STDIN_FILENO,
VIR_EVENT_HANDLE_READABLE,
virConsoleEventOnStdin,
@ -368,19 +406,17 @@ virshRunConsole(vshControl *ctl,
NULL);
while (!con->quit) {
if (virCondWait(&con->cond, &con->lock) < 0) {
virMutexUnlock(&con->lock);
if (virCondWait(&con->cond, &con->parent.lock) < 0) {
VIR_ERROR(_("unable to wait on console condition"));
goto cleanup;
}
}
virMutexUnlock(&con->lock);
ret = 0;
cleanup:
virConsoleFree(con);
virObjectUnlock(con);
virObjectUnref(con);
/* Restore original signal handlers */
sigaction(SIGQUIT, &old_sigquit, NULL);