void qemuAgentClose(qemuAgentPtr mon) { if (!mon) return; VIR_DEBUG("mon=%p", mon); qemuAgentLock(mon); if (mon->fd >= 0) { if (mon->watch) virEventRemoveHandle(mon->watch); VIR_FORCE_CLOSE(mon->fd); } /* If there is somebody waiting for a message * wake him up. No message will arrive anyway. */ if (mon->msg && !mon->msg->finished) { mon->msg->finished = 1; virCondSignal(&mon->notify); } qemuAgentUnlock(mon); virObjectUnref(mon); }
static void qemuAgentUnwatch(void *monitor) { qemuAgentPtr mon = monitor; qemuAgentLock(mon); if (qemuAgentUnref(mon) > 0) qemuAgentUnlock(mon); }
int qemuAgentUnref(qemuAgentPtr mon) { mon->refs--; if (mon->refs == 0) { qemuAgentUnlock(mon); qemuAgentFree(mon); return 0; } return mon->refs; }
void qemuAgentClose(qemuAgentPtr mon) { if (!mon) return; VIR_DEBUG("mon=%p", mon); qemuAgentLock(mon); if (mon->fd >= 0) { if (mon->watch) virEventRemoveHandle(mon->watch); VIR_FORCE_CLOSE(mon->fd); } if (qemuAgentUnref(mon) > 0) qemuAgentUnlock(mon); }
qemuAgentPtr qemuAgentOpen(virDomainObjPtr vm, virDomainChrSourceDefPtr config, qemuAgentCallbacksPtr cb) { qemuAgentPtr mon; if (!cb || !cb->eofNotify) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("EOF notify callback must be supplied")); return NULL; } if (qemuAgentInitialize() < 0) return NULL; if (!(mon = virObjectNew(qemuAgentClass))) return NULL; if (virMutexInit(&mon->lock) < 0) { virReportSystemError(errno, "%s", _("cannot initialize monitor mutex")); VIR_FREE(mon); return NULL; } if (virCondInit(&mon->notify) < 0) { virReportSystemError(errno, "%s", _("cannot initialize monitor condition")); virMutexDestroy(&mon->lock); VIR_FREE(mon); return NULL; } mon->fd = -1; mon->vm = vm; mon->cb = cb; qemuAgentLock(mon); switch (config->type) { case VIR_DOMAIN_CHR_TYPE_UNIX: mon->fd = qemuAgentOpenUnix(config->data.nix.path, vm->pid, &mon->connectPending); break; case VIR_DOMAIN_CHR_TYPE_PTY: mon->fd = qemuAgentOpenPty(config->data.file.path); break; default: virReportError(VIR_ERR_INTERNAL_ERROR, _("unable to handle monitor type: %s"), virDomainChrTypeToString(config->type)); goto cleanup; } if (mon->fd == -1) goto cleanup; if ((mon->watch = virEventAddHandle(mon->fd, VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR | VIR_EVENT_HANDLE_READABLE | (mon->connectPending ? VIR_EVENT_HANDLE_WRITABLE : 0), qemuAgentIO, mon, virObjectFreeCallback)) < 0) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("unable to register monitor events")); goto cleanup; } virObjectRef(mon); VIR_DEBUG("New mon %p fd =%d watch=%d", mon, mon->fd, mon->watch); qemuAgentUnlock(mon); return mon; cleanup: /* We don't want the 'destroy' callback invoked during * cleanup from construction failure, because that can * give a double-unref on virDomainObjPtr in the caller, * so kill the callbacks now. */ mon->cb = NULL; qemuAgentUnlock(mon); qemuAgentClose(mon); return NULL; }
static void qemuAgentIO(int watch, int fd, int events, void *opaque) { qemuAgentPtr mon = opaque; bool error = false; bool eof = false; virObjectRef(mon); /* lock access to the monitor and protect fd */ qemuAgentLock(mon); #if DEBUG_IO VIR_DEBUG("Agent %p I/O on watch %d fd %d events %d", mon, watch, fd, events); #endif if (mon->fd != fd || mon->watch != watch) { if (events & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) eof = true; virReportError(VIR_ERR_INTERNAL_ERROR, _("event from unexpected fd %d!=%d / watch %d!=%d"), mon->fd, fd, mon->watch, watch); error = true; } else if (mon->lastError.code != VIR_ERR_OK) { if (events & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) eof = true; error = true; } else { if (events & VIR_EVENT_HANDLE_WRITABLE) { if (mon->connectPending) { if (qemuAgentIOConnect(mon) < 0) error = true; } else { if (qemuAgentIOWrite(mon) < 0) error = true; } events &= ~VIR_EVENT_HANDLE_WRITABLE; } if (!error && events & VIR_EVENT_HANDLE_READABLE) { int got = qemuAgentIORead(mon); events &= ~VIR_EVENT_HANDLE_READABLE; if (got < 0) { error = true; } else if (got == 0) { eof = true; } else { /* Ignore hangup/error events if we read some data, to * give time for that data to be consumed */ events = 0; if (qemuAgentIOProcess(mon) < 0) error = true; } } if (!error && events & VIR_EVENT_HANDLE_HANGUP) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("End of file from monitor")); eof = 1; events &= ~VIR_EVENT_HANDLE_HANGUP; } if (!error && !eof && events & VIR_EVENT_HANDLE_ERROR) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Invalid file descriptor while waiting for monitor")); eof = 1; events &= ~VIR_EVENT_HANDLE_ERROR; } if (!error && events) { virReportError(VIR_ERR_INTERNAL_ERROR, _("Unhandled event %d for monitor fd %d"), events, mon->fd); error = 1; } } if (error || eof) { if (mon->lastError.code != VIR_ERR_OK) { /* Already have an error, so clear any new error */ virResetLastError(); } else { virErrorPtr err = virGetLastError(); if (!err) virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Error while processing monitor IO")); virCopyLastError(&mon->lastError); virResetLastError(); } VIR_DEBUG("Error on monitor %s", NULLSTR(mon->lastError.message)); /* If IO process resulted in an error & we have a message, * then wakeup that waiter */ if (mon->msg && !mon->msg->finished) { mon->msg->finished = 1; virCondSignal(&mon->notify); } } qemuAgentUpdateWatch(mon); /* We have to unlock to avoid deadlock against command thread, * but is this safe ? I think it is, because the callback * will try to acquire the virDomainObjPtr mutex next */ if (eof) { void (*eofNotify)(qemuAgentPtr, virDomainObjPtr) = mon->cb->eofNotify; virDomainObjPtr vm = mon->vm; /* Make sure anyone waiting wakes up now */ virCondSignal(&mon->notify); qemuAgentUnlock(mon); virObjectUnref(mon); VIR_DEBUG("Triggering EOF callback"); (eofNotify)(mon, vm); } else if (error) { void (*errorNotify)(qemuAgentPtr, virDomainObjPtr) = mon->cb->errorNotify; virDomainObjPtr vm = mon->vm; /* Make sure anyone waiting wakes up now */ virCondSignal(&mon->notify); qemuAgentUnlock(mon); virObjectUnref(mon); VIR_DEBUG("Triggering error callback"); (errorNotify)(mon, vm); } else { qemuAgentUnlock(mon); virObjectUnref(mon); } }