Esempio n. 1
0
	void Program::ThreadMonitor::theProcessHasStopped(bool killed, int exitstatus)
	{
		// prevent against invalid code
		if (YUNI_UNLIKELY(pEndTime == 0))
		{
			assert(false and "endTime is invalid");
			pEndTime = currentTime();
		}

		// execution time for the sub-process
		sint64 duration = (pEndTime >= pStartTime) ? (pEndTime - pStartTime) : 0;

		// Making sure that the process ID is invalid
		{
			MutexLocker locker(procinfo.mutex);
			if (YUNI_UNLIKELY(not procinfo.running)) // already stopped - should never happen
				return;

			procinfo.running      = false;
			procinfo.processInput = -1;
			procinfo.exitstatus   = exitstatus;
			procinfo.duration     = duration;
		}

		if (!(!stream))
		{
			stream->onStop(killed, exitstatus, duration);
			// remove the reference to the stream as soon as possible
			stream = nullptr;
		}
	}
Esempio n. 2
0
	bool QueueThread::onExecute()
	{
		// Notify the scheduler that this thread has begun its work
		pQueueService.registerWorker(this);

		// Asking for the next job
		while (pQueueService.pWaitingRoom.pop(pJob))
		{
			// Execute the job, via a wrapper for symbol visibility issues
			Yuni::Private::QueueService::JobAccessor<Yuni::Job::IJob>::Execute(*pJob, this);

			// We must release our pointer to the job here to avoid its destruction
			// in `pQueueService.nextJob()` (when `pJob` is re-assigned).
			// This method uses a lock and the destruction of the job may take some time.
			// Obviously, there is absolutely no guarantee that the job will be destroyed
			// at this point but we don't really care
			pJob = nullptr;

			// Cancellation point
			if (YUNI_UNLIKELY(shouldAbort())) // We have to stop as soon as possible, no need for hibernation
				return false;

		} // loop for retrieving jobs to execute

		// Returning true, for hibernation
		return true;
	}
Esempio n. 3
0
DBI::Error Transaction::truncate(const AnyString& tablename)
{
    if (YUNI_UNLIKELY(not IsValidIdentifier(tablename)))
        return errInvalidIdentifier;

    assert(!(!pChannel));

    // the adapter
    ::yn_dbi_adapter& adapter = pChannel->adapter;

    // The DBI interface should provide the most appropriate way for
    // truncating a table (autoincrement / cascade...)
    if (YUNI_LIKELY(adapter.truncate))
    {
        return (DBI::Error) adapter.truncate(adapter.dbh, tablename.c_str(), tablename.size());
    }
    else
    {
        // Fallback to a failsafe method
        // -- stmt << "TRUNCATE " << tablename << ';';
        // The SQL command Truncate is not supported by all databases. `DELETE FROM`
        // is not  the most efficient way for truncating a table
        // but it should work almost everywhere
        String stmt;
        stmt << "DELETE FROM " << tablename << ';';
        return perform(stmt);
    }
}
Esempio n. 4
0
Cursor Transaction::prepare(const AnyString& stmt)
{
    assert(!(!pChannel));

    // the adapter
    ::yn_dbi_adapter& adapter = pChannel->adapter;

    if (YUNI_UNLIKELY(nullHandle == pTxHandle))
    {
        if (errNone != pChannel->begin(pTxHandle))
            return Cursor(adapter, nullptr);
    }

    // query handle
    void* handle = nullptr;

    if (YUNI_LIKELY(not stmt.empty() and adapter.dbh))
    {
        assert(adapter.query_new != NULL  and "invalid adapter query_new");
        assert(adapter.query_ref_acquire != NULL and "invalid adapter query_ref_acquire");
        assert(adapter.query_ref_release != NULL and "invalid adapter query_ref_release");

        adapter.query_new(&handle, adapter.dbh, stmt.c_str(), stmt.size());
    }

    return Cursor(adapter, handle);
}
Esempio n. 5
0
	Program::ProcessSharedInfo::~ProcessSharedInfo()
	{
		if (YUNI_UNLIKELY(timeoutThread.get()))
		{
			// should never go in this section
			assert(false and "the thread for handling the timeout has not been properly stopped");
			timeoutThread->stop();
		}

		if (thread and thread->release())
			delete thread;
	}
Esempio n. 6
0
	int Program::wait(sint64* duration)
	{
		auto envptr = pEnv;
		if (YUNI_UNLIKELY(!envptr))
		{
			if (duration)
				*duration = 0;
			return 0;
		}
		ProcessSharedInfo& env = *envptr;

		ThreadMonitor* thread = nullptr;
		// checking environment
		{
			MutexLocker locker(env.mutex);
			if (not env.running or (nullptr == env.thread))
			{
				if (duration)
					*duration = env.duration;
				return env.exitstatus;
			}
			// capture the thread
			thread = env.thread;
			thread->addRef();
		}

		// wait for the end of the thread
		assert(thread != nullptr);
		thread->wait();


		MutexLocker locker(env.mutex);

		// since the thread has finished, we can safely destroy it
		if (env.thread)
			env.thread->release();
		env.thread = nullptr;

		if (thread->release())
			delete thread;

		if (duration)
			*duration = env.duration;
		return env.exitstatus;
	}
Esempio n. 7
0
	void Program::commandLine(AnyString cmd)
	{
		// remove all whitespaces
		cmd.trim();

		auto envptr = pEnv; // keeping a reference to the current env
		if (!envptr)
		{
			envptr = std::make_shared<ProcessSharedInfo>();
			pEnv = envptr;
		}
		ProcessSharedInfo& env = *envptr;

		MutexLocker locker(env.mutex);
		env.executable.clear();
		env.arguments.clear();

		if (cmd.empty())
			return;


		String* str = &env.executable;
		char instring = '\0';
		const AnyString::null_iterator end = cmd.utf8end();
		for (AnyString::const_utf8iterator i = cmd.utf8begin(); i != end; ++i)
		{
			char c = *i;
			switch (c)
			{
				default:
				{
					*str += i.value();
					break;
				}
				case '"':
					[[fallthrough]];
				case '\'':
				{
					if (instring == '\0')
					{
						instring = c;
					}
					else
					{
						if (instring == c)
							instring = '\0';
						else
							*str += c;
					}
					break;
				}
				case '\\':
				{
					++i;
					if (YUNI_UNLIKELY(i == end))
						return;
					c = *i;
					switch (c)
					{
						case 'n':  (*str) += '\n'; break;
						case 't':  (*str) += '\t'; break;
						case 'r':  (*str) += '\r'; break;
						case 'b':  (*str) += '\b'; break;
						case 'f':  (*str) += '\f'; break;
						case 'v':  (*str) += '\v'; break;
						case '0':  (*str) += '\0'; break;
						case 'e': [[fallthrough]];
						case 'a': [[fallthrough]];
						case 'E':  break;
						default:   (*str) << '\\' << c; break;
					}
					break;
				}
				case ' ':
					[[fallthrough]];
				case '\t':
				{
					if (instring == '\0')
					{
						if (not str->empty())
						{
							env.arguments.push_back(nullptr);
							str = &(env.arguments.back());
						}
					}
					else
						*str += c;
					break;
				}
			}
		}
	}