static void virConsoleShutdown(virConsolePtr con) { virErrorPtr err = virGetLastError(); if (con->error.code == VIR_ERR_OK && err) virCopyLastError(&con->error); if (con->st) { virStreamEventRemoveCallback(con->st); virStreamAbort(con->st); virStreamFree(con->st); con->st = NULL; } VIR_FREE(con->streamToTerminal.data); VIR_FREE(con->terminalToStream.data); if (con->stdinWatch != -1) virEventRemoveHandle(con->stdinWatch); if (con->stdoutWatch != -1) virEventRemoveHandle(con->stdoutWatch); con->stdinWatch = -1; con->stdoutWatch = -1; if (!con->quit) { con->quit = true; virCondSignal(&con->cond); } }
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); }
/* * @priority - job priority * Return: 0 on success, -1 otherwise */ int virThreadPoolSendJob(virThreadPoolPtr pool, unsigned int priority, void *jobData) { virThreadPoolJobPtr job; virMutexLock(&pool->mutex); if (pool->quit) goto error; if (pool->freeWorkers - pool->jobQueueDepth <= 0 && pool->nWorkers < pool->maxWorkers && virThreadPoolExpand(pool, 1, false) < 0) goto error; if (VIR_ALLOC(job) < 0) goto error; job->data = jobData; job->priority = priority; job->prev = pool->jobList.tail; if (pool->jobList.tail) pool->jobList.tail->next = job; pool->jobList.tail = job; if (!pool->jobList.head) pool->jobList.head = job; if (priority && !pool->jobList.firstPrio) pool->jobList.firstPrio = job; pool->jobQueueDepth++; virCondSignal(&pool->cond); if (priority) virCondSignal(&pool->prioCond); virMutexUnlock(&pool->mutex); return 0; error: virMutexUnlock(&pool->mutex); return -1; }
/* * obj must be locked before calling * * To be called after completing the work associated with the * earlier libxlDomainBeginJob() call * * Returns true if the remaining reference count on obj is * non-zero, false if the reference count has dropped to zero * and obj is disposed. */ void libxlDomainObjEndJob(libxlDriverPrivatePtr driver ATTRIBUTE_UNUSED, virDomainObjPtr obj) { libxlDomainObjPrivatePtr priv = obj->privateData; enum libxlDomainJob job = priv->job.active; VIR_DEBUG("Stopping job: %s", libxlDomainJobTypeToString(job)); libxlDomainObjResetJob(priv); virCondSignal(&priv->job.cond); }
void qemuAgentNotifyEvent(qemuAgentPtr mon, qemuAgentEvent event) { VIR_DEBUG("mon=%p event=%d", mon, event); if (mon->await_event == event) { VIR_DEBUG("Waking up a tragedian"); mon->await_event = QEMU_AGENT_EVENT_NONE; /* somebody waiting for this event, wake him up. */ if (mon->msg && !mon->msg->finished) { mon->msg->finished = 1; virCondSignal(&mon->notify); } } else { /* shouldn't happen but one never knows */ VIR_WARN("Received unexpected event %d", event); } }
static void virConsoleShutdown(virConsolePtr con) { if (con->st) { virStreamEventRemoveCallback(con->st); virStreamAbort(con->st); virStreamFree(con->st); } VIR_FREE(con->streamToTerminal.data); VIR_FREE(con->terminalToStream.data); if (con->stdinWatch != -1) virEventRemoveHandle(con->stdinWatch); if (con->stdoutWatch != -1) virEventRemoveHandle(con->stdoutWatch); con->stdinWatch = -1; con->stdoutWatch = -1; con->quit = true; virCondSignal(&con->cond); }
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); } }
/* * Process all calls pending dispatch/receive until we * get a reply to our own call. Then quit and pass the buck * to someone else. */ static int virNetClientIOEventLoop(virNetClientPtr client, virNetClientCallPtr thiscall) { struct pollfd fds[2]; int ret; fds[0].fd = virNetSocketGetFD(client->sock); fds[1].fd = client->wakeupReadFD; for (;;) { virNetClientCallPtr tmp = client->waitDispatch; virNetClientCallPtr prev; char ignore; sigset_t oldmask, blockedsigs; int timeout = -1; /* If we have existing SASL decoded data we * don't want to sleep in the poll(), just * check if any other FDs are also ready */ if (virNetSocketHasCachedData(client->sock)) timeout = 0; fds[0].events = fds[0].revents = 0; fds[1].events = fds[1].revents = 0; fds[1].events = POLLIN; while (tmp) { if (tmp->mode == VIR_NET_CLIENT_MODE_WAIT_RX) fds[0].events |= POLLIN; if (tmp->mode == VIR_NET_CLIENT_MODE_WAIT_TX) fds[0].events |= POLLOUT; tmp = tmp->next; } /* We have to be prepared to receive stream data * regardless of whether any of the calls waiting * for dispatch are for streams. */ if (client->nstreams) fds[0].events |= POLLIN; /* Release lock while poll'ing so other threads * can stuff themselves on the queue */ virNetClientUnlock(client); /* Block SIGWINCH from interrupting poll in curses programs, * then restore the original signal mask again immediately * after the call (RHBZ#567931). Same for SIGCHLD and SIGPIPE * at the suggestion of Paolo Bonzini and Daniel Berrange. */ sigemptyset (&blockedsigs); #ifdef SIGWINCH sigaddset (&blockedsigs, SIGWINCH); #endif #ifdef SIGCHLD sigaddset (&blockedsigs, SIGCHLD); #endif sigaddset (&blockedsigs, SIGPIPE); ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask)); repoll: ret = poll(fds, ARRAY_CARDINALITY(fds), timeout); if (ret < 0 && errno == EAGAIN) goto repoll; ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL)); virNetClientLock(client); /* If we have existing SASL decoded data, pretend * the socket became readable so we consume it */ if (virNetSocketHasCachedData(client->sock)) fds[0].revents |= POLLIN; if (fds[1].revents) { VIR_DEBUG("Woken up from poll by other thread"); if (saferead(client->wakeupReadFD, &ignore, sizeof(ignore)) != sizeof(ignore)) { virReportSystemError(errno, "%s", _("read on wakeup fd failed")); goto error; } } if (ret < 0) { if (errno == EWOULDBLOCK) continue; virReportSystemError(errno, "%s", _("poll on socket failed")); goto error; } if (fds[0].revents & POLLOUT) { if (virNetClientIOHandleOutput(client) < 0) goto error; } if (fds[0].revents & POLLIN) { if (virNetClientIOHandleInput(client) < 0) goto error; } /* Iterate through waiting threads and if * any are complete then tell 'em to wakeup */ tmp = client->waitDispatch; prev = NULL; while (tmp) { if (tmp != thiscall && tmp->mode == VIR_NET_CLIENT_MODE_COMPLETE) { /* Take them out of the list */ if (prev) prev->next = tmp->next; else client->waitDispatch = tmp->next; /* And wake them up.... * ...they won't actually wakeup until * we release our mutex a short while * later... */ VIR_DEBUG("Waking up sleep %p %p", tmp, client->waitDispatch); virCondSignal(&tmp->cond); } else { prev = tmp; } tmp = tmp->next; } /* Now see if *we* are done */ if (thiscall->mode == VIR_NET_CLIENT_MODE_COMPLETE) { /* We're at head of the list already, so * remove us */ client->waitDispatch = thiscall->next; VIR_DEBUG("Giving up the buck %p %p", thiscall, client->waitDispatch); /* See if someone else is still waiting * and if so, then pass the buck ! */ if (client->waitDispatch) { VIR_DEBUG("Passing the buck to %p", client->waitDispatch); virCondSignal(&client->waitDispatch->cond); } return 0; } if (fds[0].revents & (POLLHUP | POLLERR)) { virNetError(VIR_ERR_INTERNAL_ERROR, "%s", _("received hangup / error event on socket")); goto error; } } error: client->waitDispatch = thiscall->next; VIR_DEBUG("Giving up the buck due to I/O error %p %p", thiscall, client->waitDispatch); /* See if someone else is still waiting * and if so, then pass the buck ! */ if (client->waitDispatch) { VIR_DEBUG("Passing the buck to %p", client->waitDispatch); virCondSignal(&client->waitDispatch->cond); } return -1; }
static void virThreadPoolWorker(void *opaque) { struct virThreadPoolWorkerData *data = opaque; virThreadPoolPtr pool = data->pool; virCondPtr cond = data->cond; bool priority = data->priority; size_t *curWorkers = priority ? &pool->nPrioWorkers : &pool->nWorkers; size_t *maxLimit = priority ? &pool->maxPrioWorkers : &pool->maxWorkers; virThreadPoolJobPtr job = NULL; VIR_FREE(data); virMutexLock(&pool->mutex); while (1) { /* In order to support async worker termination, we need ensure that * both busy and free workers know if they need to terminated. Thus, * busy workers need to check for this fact before they start waiting for * another job (and before taking another one from the queue); and * free workers need to check for this right after waking up. */ if (virThreadPoolWorkerQuitHelper(*curWorkers, *maxLimit)) goto out; while (!pool->quit && ((!priority && !pool->jobList.head) || (priority && !pool->jobList.firstPrio))) { if (!priority) pool->freeWorkers++; if (virCondWait(cond, &pool->mutex) < 0) { if (!priority) pool->freeWorkers--; goto out; } if (!priority) pool->freeWorkers--; if (virThreadPoolWorkerQuitHelper(*curWorkers, *maxLimit)) goto out; } if (pool->quit) break; if (priority) { job = pool->jobList.firstPrio; } else { job = pool->jobList.head; } if (job == pool->jobList.firstPrio) { virThreadPoolJobPtr tmp = job->next; while (tmp) { if (tmp->priority) break; tmp = tmp->next; } pool->jobList.firstPrio = tmp; } if (job->prev) job->prev->next = job->next; else pool->jobList.head = job->next; if (job->next) job->next->prev = job->prev; else pool->jobList.tail = job->prev; pool->jobQueueDepth--; virMutexUnlock(&pool->mutex); (pool->jobFunc)(job->data, pool->jobOpaque); VIR_FREE(job); virMutexLock(&pool->mutex); } out: if (priority) pool->nPrioWorkers--; else pool->nWorkers--; if (pool->nWorkers == 0 && pool->nPrioWorkers == 0) virCondSignal(&pool->quit_cond); virMutexUnlock(&pool->mutex); }