void Process::finish(int returnCode) { { std::lock_guard<std::mutex> lock(mMutex); mReturn = returnCode; mStdInBuffer.clear(); closeStdIn(CloseForce); mWantStdInClosed = false; if (mMode == Async) { // try to read all remaining data on stdout and stderr handleOutput(mStdOut[0], mStdOutBuffer, mStdOutIndex, mReadyReadStdOut); handleOutput(mStdErr[0], mStdErrBuffer, mStdErrIndex, mReadyReadStdErr); closeStdOut(); closeStdErr(); } else { int w; char q = 'q'; eintrwrap(w, ::write(mSync[1], &q, 1)); eintrwrap(w, ::close(mSync[1])); mSync[1] = -1; } } if (mMode == Async) mFinished(this); }
void Process::event(const Event* event) { if (event->type() == ProcessFinishedEvent::Type) { const ProcessFinishedEvent* pevent = static_cast<const ProcessFinishedEvent*>(event); if (mPid == -1) { error() << "process already finished, pid " << pevent->pid; return; } assert(mPid == pevent->pid); mPid = -1; mReturn = pevent->returnCode; mStdInBuffer.clear(); closeStdIn(); // try to read all remaining data on stdout and stderr handleOutput(mStdOut[0], mStdOutBuffer, mStdOutIndex, mReadyReadStdOut); handleOutput(mStdErr[0], mStdErrBuffer, mStdErrIndex, mReadyReadStdErr); closeStdOut(); closeStdErr(); mFinished(); } else { EventReceiver::event(event); } }
void MPlayer::mStarted() { if (play_list.size()) { play(play_list.at(0)); play_list.removeAt(0); QTimer::singleShot(1000, this, SLOT(setDuration())); } else { emit mFinished(); } }
void Connection::onDataAvailable(const SocketClient::SharedPtr&, Buffer&& buf) { while (true) { if (!buf.isEmpty()) mBuffers.push_back(std::move(buf)); unsigned int available = bufferSize(mBuffers); if (!available) break; if (!mPendingRead) { if (available < static_cast<int>(sizeof(uint32_t))) break; char buf[sizeof(uint32_t)]; const int read = bufferRead(mBuffers, buf, 4); assert(read == 4); Deserializer strm(buf, read); strm >> mPendingRead; assert(mPendingRead > 0); available -= 4; } assert(mPendingRead >= 0); if (available < static_cast<unsigned int>(mPendingRead)) break; char buf[1024]; char *buffer = buf; if (mPendingRead > static_cast<int>(sizeof(buf))) { buffer = new char[mPendingRead]; } const int read = bufferRead(mBuffers, buffer, mPendingRead); assert(read == mPendingRead); mPendingRead = 0; std::shared_ptr<Message> message = Message::create(mVersion, buffer, read); if (message) { auto that = shared_from_this(); if (message->messageId() == FinishMessage::MessageId) { mFinishStatus = std::static_pointer_cast<FinishMessage>(message)->status(); mFinished(that, mFinishStatus); } else if (message->messageId() == ConnectMessage::MessageId) { mIsConnected = true; } else { newMessage()(message, that); } } if (buffer != buf) delete[] buffer; if (!message) mSocketClient->close(); // mClient->dataAvailable().disconnect(this, &Connection::dataAvailable); } }
void Connection::onDataAvailable(const SocketClient::SharedPtr &client, Buffer&& buf) { auto that = shared_from_this(); while (true) { if (!buf.isEmpty()) mBuffers.push(std::forward<Buffer>(buf)); unsigned int available = mBuffers.size(); if (!available) break; if (!mPendingRead) { if (available < static_cast<int>(sizeof(uint32_t))) break; union { unsigned char b[sizeof(uint32_t)]; int pending; }; const int read = mBuffers.read(b, 4); assert(read == 4); mPendingRead = pending; assert(mPendingRead > 0); available -= read; } assert(mPendingRead >= 0); if (available < static_cast<unsigned int>(mPendingRead)) break; StackBuffer<1024 * 16> buffer(mPendingRead); const int read = mBuffers.read(buffer.buffer(), mPendingRead); assert(read == mPendingRead); mPendingRead = 0; Message::MessageError error; std::shared_ptr<Message> message = Message::create(mVersion, buffer, read, &error); if (message) { if (message->messageId() == FinishMessage::MessageId) { mFinishStatus = std::static_pointer_cast<FinishMessage>(message)->status(); mFinished(that, mFinishStatus); } else { newMessage()(message, that); } } else if (mErrorHandler) { mErrorHandler(client, std::move(error)); } else { ::error() << "Unable to create message from data" << error.type << error.text << read; } if (!message) client->close(); } }
void Connection::onDataAvailable(const SocketClient::SharedPtr&, Buffer&& buf) { while (true) { if (!buf.isEmpty()) mBuffers.push_back(std::move(buf)); unsigned int available = bufferSize(mBuffers); if (!available) break; if (!mPendingRead) { if (available < static_cast<int>(sizeof(uint32_t))) break; union { char buf[sizeof(uint32_t)]; int pending; }; const int read = bufferRead(mBuffers, buf, 4); assert(read == 4); mPendingRead = pending; assert(mPendingRead > 0); available -= read; } assert(mPendingRead >= 0); if (available < static_cast<unsigned int>(mPendingRead)) break; StackBuffer<1024 * 16> buffer(mPendingRead); const int read = bufferRead(mBuffers, buffer, mPendingRead); assert(read == mPendingRead); mPendingRead = 0; std::shared_ptr<Message> message = Message::create(mVersion, buffer, read); if (message) { auto that = shared_from_this(); if (message->messageId() == FinishMessage::MessageId) { mFinishStatus = std::static_pointer_cast<FinishMessage>(message)->status(); mFinished(that, mFinishStatus); } else { newMessage()(message, that); } } else { ::error() << "Unable to create message from data" << read; } if (!message) mSocketClient->close(); // mClient->dataAvailable().disconnect(this, &Connection::dataAvailable); } }
void ScanThread::run() { mFinished(paths(mPath, mFilters)); }
void ScanJob::run() { mPath.visit(&ScanJob::visit, this); if (shared_ptr<Project> project = mProject.lock()) mFinished(mPaths); }
void CompletionJob::execute() { StopWatch timer; CXUnsavedFile unsavedFile = { mUnsaved.isEmpty() ? 0 : mPath.constData(), mUnsaved.isEmpty() ? 0 : mUnsaved.constData(), static_cast<unsigned long>(mUnsaved.size()) }; if (!mUnit) { String clangLine; RTags::parseTranslationUnit(mPath, mArgs, mUnit, Server::instance()->clangIndex(), clangLine, 0, 0, &unsavedFile, 1); mParseCount = 1; if (!mUnit) { error() << "Failed to parse" << mPath << "Can't complete"; return; } } // error() << "Completing" << mPath << mParseCount; assert(mParseCount >= 1 && mParseCount <= 2); if (mParseCount == 1) { RTags::reparseTranslationUnit(mUnit, &unsavedFile, 1); if (!mUnit) { mFinished(mPath, id()); return; } else { ++mParseCount; } } CXCodeCompleteResults *results = clang_codeCompleteAt(mUnit, mPath.constData(), mLine, mColumn, &unsavedFile, mUnsaved.isEmpty() ? 0 : 1, CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeCodePatterns); if (results) { CompletionNode *nodes = new CompletionNode[results->NumResults]; int nodeCount = 0; Map<Token, int> tokens; if (!mUnsaved.isEmpty()) { tokenize(mUnsaved.constData(), mUnsaved.size(), tokens); // for (Map<Token, int>::const_iterator it = tokens.begin(); it != tokens.end(); ++it) { // error() << String(it->first.data, it->first.length) << it->second; // } } for (unsigned i = 0; i < results->NumResults; ++i) { const CXCursorKind kind = results->Results[i].CursorKind; if (kind == CXCursor_Destructor) continue; const CXCompletionString &string = results->Results[i].CompletionString; const CXAvailabilityKind availabilityKind = clang_getCompletionAvailability(string); if (availabilityKind != CXAvailability_Available) continue; const int priority = clang_getCompletionPriority(string); if (priority >= 75) continue; CompletionNode &node = nodes[nodeCount]; node.priority = priority; node.signature.reserve(256); const int chunkCount = clang_getNumCompletionChunks(string); bool ok = true; for (int j=0; j<chunkCount; ++j) { const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(string, j); if (chunkKind == CXCompletionChunk_TypedText) { node.completion = RTags::eatString(clang_getCompletionChunkText(string, j)); if (node.completion.size() > 8 && node.completion.startsWith("operator") && !isPartOfSymbol(node.completion.at(8))) { ok = false; break; } node.signature.append(node.completion); } else { node.signature.append(RTags::eatString(clang_getCompletionChunkText(string, j))); if (chunkKind == CXCompletionChunk_ResultType) node.signature.append(' '); } } if (ok) { int ws = node.completion.size() - 1; while (ws >= 0 && isspace(node.completion.at(ws))) --ws; if (ws >= 0) { node.completion.truncate(ws + 1); node.signature.replace("\n", ""); node.distance = tokens.value(Token(node.completion.constData(), node.completion.size()), -1); ++nodeCount; continue; } } node.completion.clear(); node.signature.clear(); } if (nodeCount) { if (nodeCount > SendThreshold) { write("`"); } else { qsort(nodes, nodeCount, sizeof(CompletionNode), compareCompletionNode); if (mType == Stream) { write<128>("`%s %s", nodes[0].completion.constData(), nodes[0].signature.constData()); } else { write<128>("%s %s", nodes[0].completion.constData(), nodes[0].signature.constData()); } for (int i=1; i<nodeCount; ++i) { write<128>("%s %s", nodes[i].completion.constData(), nodes[i].signature.constData()); } } } warning() << "Wrote" << ((nodeCount > SendThreshold) ? -1 : nodeCount) << "completions for" << String::format<128>("%s:%d:%d", mPath.constData(), mLine, mColumn) << "in" << timer.elapsed() << "ms" << mArgs; // const unsigned diagnosticCount = clang_getNumDiagnostics(mUnit); // for (unsigned i=0; i<diagnosticCount; ++i) { // CXDiagnostic diagnostic = clang_getDiagnostic(mUnit, i); // const CXDiagnosticSeverity severity = clang_getDiagnosticSeverity(diagnostic); // const String msg = RTags::eatString(clang_getDiagnosticSpelling(diagnostic)); // CXFile file; // unsigned line, col; // clang_getSpellingLocation(clang_getDiagnosticLocation(diagnostic), &file, &line, &col, 0); // error() << i << diagnosticCount << severity << msg // << String::format<128>("%s:%d:%d", RTags::eatString(clang_getFileName(file)).constData(), // line, col); // clang_disposeDiagnostic(diagnostic); // } delete[] nodes; //processDiagnostics(results); clang_disposeCodeCompleteResults(results); std::shared_ptr<Project> proj = project(); if (proj) { // error() << "Adding to cache" << mParseCount << mPath; proj->addToCache(mPath, mArgs, mUnit, mParseCount); } } mFinished(mPath, id()); }
void CompletionJob::execute() { CXUnsavedFile unsavedFile = { mUnsaved.isEmpty() ? 0 : mPath.constData(), mUnsaved.isEmpty() ? 0 : mUnsaved.constData(), static_cast<unsigned long>(mUnsaved.size()) }; CXCodeCompleteResults *results = clang_codeCompleteAt(mUnit, mPath.constData(), mLine, mColumn, &unsavedFile, mUnsaved.isEmpty() ? 0 : 1, CXCodeComplete_IncludeMacros | CXCodeComplete_IncludeCodePatterns); if (results) { CompletionNode *nodes = new CompletionNode[results->NumResults]; int nodeCount = 0; Map<Token, int> tokens; if (!mUnsaved.isEmpty()) { tokenize(mUnsaved.constData(), mUnsaved.size(), tokens); // for (Map<Token, int>::const_iterator it = tokens.begin(); it != tokens.end(); ++it) { // error() << ByteArray(it->first.data, it->first.length) << it->second; // } } for (unsigned i = 0; i < results->NumResults; ++i) { const CXCursorKind kind = results->Results[i].CursorKind; if (kind == CXCursor_Destructor) continue; const CXCompletionString &string = results->Results[i].CompletionString; const CXAvailabilityKind availabilityKind = clang_getCompletionAvailability(string); if (availabilityKind != CXAvailability_Available) continue; const int priority = clang_getCompletionPriority(string); if (priority >= 75) continue; CompletionNode &node = nodes[nodeCount]; node.priority = priority; node.signature.reserve(256); const int chunkCount = clang_getNumCompletionChunks(string); bool ok = true; for (int j=0; j<chunkCount; ++j) { const CXCompletionChunkKind chunkKind = clang_getCompletionChunkKind(string, j); if (chunkKind == CXCompletionChunk_TypedText) { node.completion = RTags::eatString(clang_getCompletionChunkText(string, j)); if (node.completion.size() > 8 && node.completion.startsWith("operator") && !isPartOfSymbol(node.completion.at(8))) { ok = false; break; } node.signature.append(node.completion); } else { node.signature.append(RTags::eatString(clang_getCompletionChunkText(string, j))); if (chunkKind == CXCompletionChunk_ResultType) node.signature.append(' '); } } if (ok) { int ws = node.completion.size() - 1; while (ws >= 0 && isspace(node.completion.at(ws))) --ws; if (ws >= 0) { node.completion.truncate(ws + 1); node.signature.replace("\n", ""); node.distance = tokens.value(Token(node.completion.constData(), node.completion.size()), -1); ++nodeCount; continue; } } node.completion.clear(); node.signature.clear(); } if (nodeCount) { qsort(nodes, nodeCount, sizeof(CompletionNode), compareCompletionNode); write<128>("`%s %s", nodes[0].completion.constData(), nodes[0].signature.constData()); for (int i=1; i<nodeCount; ++i) { write<128>("%s %s", nodes[i].completion.constData(), nodes[i].signature.constData()); } } delete[] nodes; //processDiagnostics(results); clang_disposeCodeCompleteResults(results); shared_ptr<Project> proj = project(); if (proj) proj->addToCache(mPath, mArgs, mIndex, mUnit); } mFinished(mPath); }
Process::ExecState Process::startInternal(const Path &command, const List<String> &a, const List<String> &environ, int timeout, unsigned execFlags) { mErrorString.clear(); Path cmd = findCommand(command); if (cmd.isEmpty()) { mErrorString = "Command not found"; return Error; } List<String> arguments = a; int err; int closePipe[2]; eintrwrap(err, ::pipe(closePipe)); #ifdef HAVE_CLOEXEC if (!SocketClient::setFlags(closePipe[1], FD_CLOEXEC, F_GETFD, F_SETFD)) { mErrorString = "Unable to set FD_CLOEXEC"; eintrwrap(err, ::close(closePipe[0])); eintrwrap(err, ::close(closePipe[1])); return Error; } #else #warning No CLOEXEC, Process might have problematic behavior #endif eintrwrap(err, ::pipe(mStdIn)); eintrwrap(err, ::pipe(mStdOut)); eintrwrap(err, ::pipe(mStdErr)); if (mMode == Sync) eintrwrap(err, ::pipe(mSync)); const char **args = new const char*[arguments.size() + 2]; // const char* args[arguments.size() + 2]; args[arguments.size() + 1] = 0; args[0] = cmd.nullTerminated(); int pos = 1; for (List<String>::const_iterator it = arguments.begin(); it != arguments.end(); ++it) { args[pos] = it->nullTerminated(); //printf("arg: '%s'\n", args[pos]); ++pos; } const bool hasEnviron = !environ.empty(); const char **env = new const char*[environ.size() + 1]; env[environ.size()] = 0; if (hasEnviron) { pos = 0; //printf("fork, about to exec '%s'\n", cmd.nullTerminated()); for (List<String>::const_iterator it = environ.begin(); it != environ.end(); ++it) { env[pos] = it->nullTerminated(); //printf("env: '%s'\n", env[pos]); ++pos; } } mPid = ::fork(); if (mPid == -1) { //printf("fork, something horrible has happened %d\n", errno); // bail out eintrwrap(err, ::close(mStdIn[1])); eintrwrap(err, ::close(mStdIn[0])); eintrwrap(err, ::close(mStdOut[1])); eintrwrap(err, ::close(mStdOut[0])); eintrwrap(err, ::close(mStdErr[1])); eintrwrap(err, ::close(mStdErr[0])); eintrwrap(err, ::close(closePipe[1])); eintrwrap(err, ::close(closePipe[0])); mErrorString = "Fork failed"; delete[] env; delete[] args; return Error; } else if (mPid == 0) { //printf("fork, in child\n"); // child, should do some error checking here really eintrwrap(err, ::close(closePipe[0])); eintrwrap(err, ::close(mStdIn[1])); eintrwrap(err, ::close(mStdOut[0])); eintrwrap(err, ::close(mStdErr[0])); eintrwrap(err, ::close(STDIN_FILENO)); eintrwrap(err, ::close(STDOUT_FILENO)); eintrwrap(err, ::close(STDERR_FILENO)); eintrwrap(err, ::dup2(mStdIn[0], STDIN_FILENO)); eintrwrap(err, ::close(mStdIn[0])); eintrwrap(err, ::dup2(mStdOut[1], STDOUT_FILENO)); eintrwrap(err, ::close(mStdOut[1])); eintrwrap(err, ::dup2(mStdErr[1], STDERR_FILENO)); eintrwrap(err, ::close(mStdErr[1])); int ret; if (!mChRoot.isEmpty() && ::chroot(mChRoot.constData())) { goto error; } if (!mCwd.isEmpty() && ::chdir(mCwd.constData())) { goto error; } if (hasEnviron) { ret = ::execve(cmd.nullTerminated(), const_cast<char* const*>(args), const_cast<char* const*>(env)); } else { ret = ::execv(cmd.nullTerminated(), const_cast<char* const*>(args)); } // notify the parent process error: const char c = 'c'; eintrwrap(err, ::write(closePipe[1], &c, 1)); eintrwrap(err, ::close(closePipe[1])); ::_exit(1); (void)ret; //printf("fork, exec seemingly failed %d, %d %s\n", ret, errno, strerror(errno)); } else { delete[] env; delete[] args; // parent eintrwrap(err, ::close(closePipe[1])); eintrwrap(err, ::close(mStdIn[0])); eintrwrap(err, ::close(mStdOut[1])); eintrwrap(err, ::close(mStdErr[1])); //printf("fork, in parent\n"); int flags; eintrwrap(flags, fcntl(mStdIn[1], F_GETFL, 0)); eintrwrap(flags, fcntl(mStdIn[1], F_SETFL, flags | O_NONBLOCK)); eintrwrap(flags, fcntl(mStdOut[0], F_GETFL, 0)); eintrwrap(flags, fcntl(mStdOut[0], F_SETFL, flags | O_NONBLOCK)); eintrwrap(flags, fcntl(mStdErr[0], F_GETFL, 0)); eintrwrap(flags, fcntl(mStdErr[0], F_SETFL, flags | O_NONBLOCK)); // block until exec is called in the child or until exec fails { char c; eintrwrap(err, ::read(closePipe[0], &c, 1)); (void)c; if (err == -1) { // bad eintrwrap(err, ::close(closePipe[0])); mErrorString = "Failed to read from closePipe during process start"; mPid = -1; return Error; } else if (err == 0) { // process has started successfully eintrwrap(err, ::close(closePipe[0])); } else if (err == 1) { // process start failed eintrwrap(err, ::close(closePipe[0])); mErrorString = "Process failed to start"; mPid = -1; return Error; } } ProcessThread::addPid(mPid, this, (mMode == Async)); //printf("fork, about to add fds: stdin=%d, stdout=%d, stderr=%d\n", mStdIn[1], mStdOut[0], mStdErr[0]); if (mMode == Async) { if (EventLoop::SharedPtr loop = EventLoop::eventLoop()) { loop->registerSocket(mStdOut[0], EventLoop::SocketRead, std::bind(&Process::processCallback, this, std::placeholders::_1, std::placeholders::_2)); loop->registerSocket(mStdErr[0], EventLoop::SocketRead, std::bind(&Process::processCallback, this, std::placeholders::_1, std::placeholders::_2)); } } else { // select and stuff timeval started, now, *selecttime = 0; if (timeout > 0) { Rct::gettime(&started); now = started; selecttime = &now; Rct::timevalAdd(selecttime, timeout); } if (!(execFlags & NoCloseStdIn)) { closeStdIn(CloseForce); mWantStdInClosed = false; } for (;;) { // set up all the select crap fd_set rfds, wfds; FD_ZERO(&rfds); FD_ZERO(&wfds); int max = 0; FD_SET(mStdOut[0], &rfds); max = std::max(max, mStdOut[0]); FD_SET(mStdErr[0], &rfds); max = std::max(max, mStdErr[0]); FD_SET(mSync[0], &rfds); max = std::max(max, mSync[0]); if (mStdIn[1] != -1) { FD_SET(mStdIn[1], &wfds); max = std::max(max, mStdIn[1]); } int ret; eintrwrap(ret, ::select(max + 1, &rfds, &wfds, 0, selecttime)); if (ret == -1) { // ow mErrorString = "Sync select failed: "; mErrorString += strerror(errno); return Error; } // check fds and stuff if (FD_ISSET(mStdOut[0], &rfds)) handleOutput(mStdOut[0], mStdOutBuffer, mStdOutIndex, mReadyReadStdOut); if (FD_ISSET(mStdErr[0], &rfds)) handleOutput(mStdErr[0], mStdErrBuffer, mStdErrIndex, mReadyReadStdErr); if (mStdIn[1] != -1 && FD_ISSET(mStdIn[1], &wfds)) handleInput(mStdIn[1]); if (FD_ISSET(mSync[0], &rfds)) { // we're done { std::lock_guard<std::mutex> lock(mMutex); assert(mSync[1] == -1); // try to read all remaining data on stdout and stderr handleOutput(mStdOut[0], mStdOutBuffer, mStdOutIndex, mReadyReadStdOut); handleOutput(mStdErr[0], mStdErrBuffer, mStdErrIndex, mReadyReadStdErr); closeStdOut(); closeStdErr(); int w; eintrwrap(w, ::close(mSync[0])); mSync[0] = -1; } mFinished(this); return Done; } if (timeout) { assert(selecttime); Rct::gettime(selecttime); const int lasted = Rct::timevalDiff(selecttime, &started); if (lasted >= timeout) { // timeout, we're done kill(); // attempt to kill mErrorString = "Timed out"; return TimedOut; } *selecttime = started; Rct::timevalAdd(selecttime, timeout); } } } } return Done; }