OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-cogserver / opencog / network / ConsoleSocket.cc

99 lines · cc ref:
/*
 * opencog/network/ConsoleSocket.cc
 *
 * Copyright (C) 2002-2007 Novamente LLC
 * Written by Andre Senna <senna@vettalabs.com>
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

#include <string>

#include <opencog/util/Logger.h>
#include <opencog/util/misc.h>

#include <opencog/network/ConsoleSocket.h>

using namespace opencog;

ConsoleSocket::ConsoleSocket(SocketManager* mgr) :
    ServerSocket(mgr)
{
    _shell = nullptr;
    _use_count = 0;
}

ConsoleSocket::~ConsoleSocket()
{
    logger().debug("[ConsoleSocket] enter destructor");

    // We need the use-count and the condition variables because
    // the design of asio is broken. Basically, the asio
    // code calls this destructor for ConsoleSocket while there are
    // still requests outstanding in another thread.  We have to stall
    // the destructor until all the in-flight requests are complete;
    // we use the condition variable to do this.
    //
    // Some details: basically, the remote end of the socket "fires and
    // forgets" a bunch of commands, and then closes the socket before
    // these requests have completed.  asio notices that the
    // remote socket has closed, and so decides its a good day to call
    // destructors. But of course, its not ... because the requests
    // still have to be handled.
    std::unique_lock<std::mutex> lck(_in_use_mtx);
    while (_use_count) _in_use_cv.wait(lck);
    lck.unlock();

    // If there's a shell, kill it.
    if (_shell) delete _shell;

    logger().debug("[ConsoleSocket] destructor finished");
}

void ConsoleSocket::SetShell(GenericShell* g)
{
    std::unique_lock<std::mutex> lck(_in_use_mtx);
    _shell = g;
}

/// Return true, if we have a shell, and it's busy. We have
/// to do this under a lock, because the shell could disapear
/// out from under us, destroyed in a differrent thread.
/// Before it is destroyed, though, the SetShell() above will
/// be called with a nullptr. So we are sae, under a lock.
bool ConsoleSocket::busyShell(void)
{
    std::unique_lock<std::mutex> lck(_in_use_mtx);
    if (nullptr == _shell) return false;
    return (_shell->queued() > 0 or not _shell->eval_done());
}

// ==================================================================

std::string ConsoleSocket::connection_header(void)
{
    return ServerSocket::connection_header() + " U SHEL QZ E PENDG";
}

std::string ConsoleSocket::connection_stats(void)
{
    std::string rc = ServerSocket::connection_stats();

    char buf[40];
    snprintf(buf, 40, " %1d ", get_use_count());
    rc += buf;

    if (_shell)
    {
        rc += _shell->_name;
        snprintf(buf, 40, " %2zd %c %5zd",
            _shell->queued(), _shell->eval_done()?'F':'T',
            _shell->pending());
        rc += buf;
    }
    else rc += "cogs           ";

    return rc;
}

// ==================================================================