Example #1
0
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
void MsgMgr::threadPurgeMessages()
{
    MsgChannel * channel = mChannelList->getHeadChannelList();
    while(channel)
    {
        bool signalNewMessages = false;

        u64 minMsgId = 0xffffffffffffffff;

        ChannelListener * listener = channel->getHeadListenerChannel();
        while(listener)
        {
            if(listener->mCurrentMsg)
            {
                if(minMsgId > listener->mCurrentMsg->mMsgRefId)
                    minMsgId = listener->mCurrentMsg->mMsgRefId;
            }
            listener = listener->getNext();
        }

        int numMsgs = 0;
        while(channel->mHeadMsgList && channel->mHeadMsgList->mMsgRefId < minMsgId)
        {
            channel->unlinkAndDestroyStoredMsgHead();

            //numMsgs++;
            //if(numMsgs > PURGE_MAX_MSGS_PER_CHANNEL)
            //{
            //    break;
            //}
        }

        channel = channel->getNext();
    }
}
Example #2
0
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
bool MsgMgr::addCommNodeListenerToChannel(ChannelId _channelId, CommNode * _commNode)
{
    ASSERT(_commNode);

    bool bRet = false;

    ASSERT(_channelId != InvalidChannelId);
    if(_channelId != InvalidChannelId)
    {
        {
            NWAutoCritSec critSec(mCritSecAddRemoveCommNodes);

            MsgChannel * channel = mChannelList->getChannel(_channelId);
            ASSERT(channel);
            if(channel)
            {
                MsgChannel * commNodeChannel = _commNode->getLocalChannel();
                commNodeChannel->listenTo(channel);
                bRet = true;
            }
        }
    }

    return bRet;
}
Example #3
0
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
MsgChannel * MsgMgr::createChannel(const char * _channelName)
{
    MsgChannel * newChannel = mChannelList->addChannel(_channelName, generateChannelId(), mMailboxUpdateEvent);

    ChannelId channelId = newChannel->getChannelId();
    regChannelName(_channelName, channelId);

    return newChannel;
}
Example #4
0
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
const char * MsgMgr::getChannelName(ChannelId _channelId)
{
    const char * pRet = NULL;

    {
        NWAutoCritSec critSec(mCritSecDns);

        MsgChannel * channel = mChannelList->getChannel(_channelId);
        if(channel)
        {
            pRet = channel->getName();
        }
    }

    return pRet;
}
Example #5
0
//****************************************************************************
//
//****************************************************************************
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
ChannelId MsgMgr::addCommNodeSenderToChannel(const char * _channelName, CommNode * _commNode)
{
    ASSERT(_commNode);

    ChannelId channelId = InvalidChannelId; 
    
    {
        NWAutoCritSec critSec(mCritSecAddRemoveCommNodes);
        
        channelId = findChannel(_channelName);

        if(channelId == InvalidChannelId)
        {
            MsgChannel * channel = createChannel(_channelName);
            channelId = channel->getChannelId();
        }

        addCommNodeSenderToChannel(channelId, _commNode);
    }

    return channelId;
}
Example #6
0
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
void MsgMgr::removeCommNodeFromChannel(ChannelId _channelId, CommNode * _commNode)
{
    if(_channelId != InvalidChannelId)
    {
        {
            NWAutoCritSec critSec(mCritSecAddRemoveCommNodes);

            MsgChannel * channel = mChannelList->getChannel(_channelId);
            MsgChannel * commNodeChannel = _commNode->getLocalChannel();

            if(channel)
            {
                channel->stopListeningTo(commNodeChannel);
                commNodeChannel->stopListeningTo(channel);

                if(channel->getNumListeners() < 1 && channel->getNumListened() < 1)
                {
                    unregChannelName(getChannelName(_channelId));
                    mChannelList->removeChannel(_channelId);
                }
            }
        }
    }
}
Example #7
0
static int build_remote_int(CompileJob &job, UseCSMsg *usecs, MsgChannel *local_daemon, const string &environment,
                            const string &version_file, const char *preproc_file, bool output )
{
    string hostname = usecs->hostname;
    unsigned int port = usecs->port;
    int job_id = usecs->job_id;
    bool got_env = usecs->got_env;
    job.setJobID( job_id );
    job.setEnvironmentVersion( environment ); // hoping on the scheduler's wisdom
    trace() << "Have to use host " << hostname << ":" << port << " - Job ID: "
        << job.jobID() << " - env: " << usecs->host_platform
        << " - has env: " << (got_env ? "true" : "false")
        << " - match j: " << usecs->matched_job_id
        << "\n";

    int status = 255;

    MsgChannel *cserver = 0;

    try {
            cserver = Service::createChannel(hostname, port, 10);
            if ( !cserver ) {
                log_error() << "no server found behind given hostname " << hostname << ":" << port << endl;
                throw ( 2 );
            }

    if ( !got_env ) {
        log_block b("Transfer Environment");
        // transfer env
        struct stat buf;
        if ( stat( version_file.c_str(), &buf ) ) {
            log_perror( "error stat'ing version file" );
            throw( 4 );
        }

        EnvTransferMsg msg( job.targetPlatform(), job.environmentVersion() );
        if ( !cserver->send_msg( msg ) )
            throw( 6 );

        int env_fd = open( version_file.c_str(), O_RDONLY );
        if (env_fd < 0)
            throw ( 5 );

        write_server_cpp( env_fd, cserver );

        if ( !cserver->send_msg( EndMsg() ) ) {
            log_error() << "write of environment failed" << endl;
            throw( 8 );
        }

        if ( IS_PROTOCOL_31( cserver )) {
            VerifyEnvMsg verifymsg( job.targetPlatform(), job.environmentVersion() );
            if ( !cserver->send_msg( verifymsg ) )
                throw( 22 );
            Msg *msg = cserver->get_msg(60);
            if ( msg && msg->type == M_VERIFY_ENV_RESULT ) {
                if( !static_cast<VerifyEnvResultMsg*>( msg )->ok ) {
                    // The remote can't handle the environment at all (e.g. kernel too old),
                    // mark it as never to be used again for this environment.
                    log_info() << "Host " << hostname << " did not successfully verify environment." << endl;
                    BlacklistHostEnvMsg blacklist( job.targetPlatform(), job.environmentVersion(), hostname );
                    local_daemon->send_msg( blacklist );
                    throw( 24 );
                } else
                    trace() << "Verified host " << hostname << " for environment " << job.environmentVersion()
                        << " (" << job.targetPlatform() << ")" << endl;
            } else
                throw( 25 );
        }
    }

    if( !IS_PROTOCOL_31( cserver ) && ignore_unverified()) {
        log_warning() << "Host " << hostname << " cannot be verified." << endl;
        throw( 26 );
    }

    CompileFileMsg compile_file( &job );
    {
        log_block b("send compile_file");
        if ( !cserver->send_msg( compile_file ) ) {
            log_info() << "write of job failed" << endl;
            throw( 9 );
        }
    }

    if ( !preproc_file ) {
        int sockets[2];
        if (pipe(sockets)) {
            /* for all possible cases, this is something severe */
            exit(errno);
        }

	/* This will fork, and return the pid of the child.  It will not
	   return for the child itself.  If it returns normally it will have
	   closed the write fd, i.e. sockets[1].  */
        pid_t cpp_pid = call_cpp(job, sockets[1], sockets[0] );
        if ( cpp_pid == -1 )
            throw( 18 );

        try {
            log_block bl2("write_server_cpp from cpp");
            write_server_cpp( sockets[0], cserver );
        } catch ( int error ) {
            kill( cpp_pid, SIGTERM );
            throw ( error );
        }

        log_block wait_cpp("wait for cpp");
        while(waitpid( cpp_pid, &status, 0) < 0 && errno == EINTR)
            ;

        if ( shell_exit_status(status) != 0 ) { // failure
            delete cserver;
            cserver = 0;
            return shell_exit_status( status );
        }
    } else {
        int cpp_fd = open( preproc_file, O_RDONLY );
        if ( cpp_fd < 0 )
            throw ( 11 );

        log_block cpp_block("write_server_cpp");
        write_server_cpp( cpp_fd, cserver );
    }

    {
        if ( !cserver->send_msg( EndMsg() ) ) {
            log_info() << "write of end failed" << endl;
            throw( 12 );
        }
    }

    Msg *msg;
    {
        log_block wait_cs("wait for cs");
        msg = cserver->get_msg( 12 * 60 );
        if ( !msg )
            throw( 14 );
    }

    check_for_failure( msg, cserver );
    if ( msg->type != M_COMPILE_RESULT ) {
        log_warning() << "waited for compile result, but got " << (char)msg->type << endl;
        delete msg;
        throw( 13 );
    }

    CompileResultMsg *crmsg = dynamic_cast<CompileResultMsg*>( msg );
    assert ( crmsg );

    status = crmsg->status;

    if ( status && crmsg->was_out_of_memory ) {
        delete crmsg;
        log_info() << "the server ran out of memory, recompiling locally" << endl;
        throw( 17 ); // recompile locally - TODO: handle this as a normal local job not an error case
    }

    if ( output )
    {
        write(STDOUT_FILENO, crmsg->out.c_str(), crmsg->out.size() );

        if(colorify_wanted(job))
            colorify_output(crmsg->err);
        else
            write(STDERR_FILENO, crmsg->err.c_str(), crmsg->err.size() );

        if ( status && ( crmsg->err.length() || crmsg->out.length() ) )
        {
            log_error() << "Compiled on " << hostname << endl;
        }
    }
    delete crmsg;

    assert( !job.outputFile().empty() );

    if( status == 0 ) {
        string tmp_file = job.outputFile() + "_icetmp";
        int obj_fd = open( tmp_file.c_str(), O_CREAT|O_TRUNC|O_WRONLY|O_LARGEFILE, 0666 );

        if ( obj_fd == -1 ) {
            std::string errmsg("can't create ");
            errmsg += tmp_file + ":";
            log_perror(errmsg.c_str());
            return EXIT_DISTCC_FAILED;
        }

        msg = 0;
        size_t uncompressed = 0;
        size_t compressed = 0;
        while ( 1 ) {
            delete msg;

            msg = cserver->get_msg(40);
            if ( !msg ) { // the network went down?
                unlink( tmp_file.c_str());
                throw ( 19 );
            }

	    check_for_failure( msg, cserver );

            if ( msg->type == M_END )
                break;

            if ( msg->type != M_FILE_CHUNK ) {
                unlink( tmp_file.c_str());
                delete msg;
                throw ( 20 );
            }

            FileChunkMsg *fcmsg = dynamic_cast<FileChunkMsg*>( msg );
            compressed += fcmsg->compressed;
            uncompressed += fcmsg->len;
            if ( write( obj_fd, fcmsg->buffer, fcmsg->len ) != ( ssize_t )fcmsg->len ) {
                unlink( tmp_file.c_str());
                delete msg;
                throw ( 21 );
            }
        }
        if (uncompressed)
            trace() << "got " << compressed << " bytes ("
                << (compressed * 100 / uncompressed) << "%)" << endl;


        delete msg;
        if( close( obj_fd ) == 0 )
            rename( tmp_file.c_str(), job.outputFile().c_str());
        else
            unlink( tmp_file.c_str());
    }

    } catch ( int x ) {
        delete cserver;
        cserver = 0;
        throw( x );
    }
    delete cserver;
    return status;
}
Example #8
0
static int build_remote_int(CompileJob &job, UseCSMsg *usecs, MsgChannel *local_daemon,
                            const string &environment, const string &version_file,
                            const char *preproc_file, bool output)
{
    string hostname = usecs->hostname;
    unsigned int port = usecs->port;
    int job_id = usecs->job_id;
    bool got_env = usecs->got_env;
    job.setJobID(job_id);
    job.setEnvironmentVersion(environment);   // hoping on the scheduler's wisdom
    trace() << "Have to use host " << hostname << ":" << port << " - Job ID: "
            << job.jobID() << " - env: " << usecs->host_platform
            << " - has env: " << (got_env ? "true" : "false")
            << " - match j: " << usecs->matched_job_id
            << "\n";

    int status = 255;

    MsgChannel *cserver = 0;

    try {
        cserver = Service::createChannel(hostname, port, 10);

        if (!cserver) {
            log_error() << "no server found behind given hostname " << hostname << ":"
                        << port << endl;
            throw(2);
        }

        if (!got_env) {
            log_block b("Transfer Environment");
            // transfer env
            struct stat buf;

            if (stat(version_file.c_str(), &buf)) {
                log_perror("error stat'ing version file");
                throw(4);
            }

            EnvTransferMsg msg(job.targetPlatform(), job.environmentVersion());

            if (!cserver->send_msg(msg)) {
                throw(6);
            }

            int env_fd = open(version_file.c_str(), O_RDONLY);

            if (env_fd < 0) {
                throw(5);
            }

            write_server_cpp(env_fd, cserver);

            if (!cserver->send_msg(EndMsg())) {
                log_error() << "write of environment failed" << endl;
                throw(8);
            }

            if (IS_PROTOCOL_31(cserver)) {
                VerifyEnvMsg verifymsg(job.targetPlatform(), job.environmentVersion());

                if (!cserver->send_msg(verifymsg)) {
                    throw(22);
                }

                Msg *verify_msg = cserver->get_msg(60);

                if (verify_msg && verify_msg->type == M_VERIFY_ENV_RESULT) {
                    if (!static_cast<VerifyEnvResultMsg*>(verify_msg)->ok) {
                        // The remote can't handle the environment at all (e.g. kernel too old),
                        // mark it as never to be used again for this environment.
                        log_info() << "Host " << hostname
                                   << " did not successfully verify environment."
                                   << endl;
                        BlacklistHostEnvMsg blacklist(job.targetPlatform(),
                                                      job.environmentVersion(), hostname);
                        local_daemon->send_msg(blacklist);
                        throw(24);
                    } else
                        trace() << "Verified host " << hostname << " for environment "
                                << job.environmentVersion() << " (" << job.targetPlatform() << ")"
                                << endl;
                } else {
                    throw(25);
                }
            }
        }

        if (!IS_PROTOCOL_31(cserver) && ignore_unverified()) {
            log_warning() << "Host " << hostname << " cannot be verified." << endl;
            throw(26);
        }

        CompileFileMsg compile_file(&job);
        {
            log_block b("send compile_file");

            if (!cserver->send_msg(compile_file)) {
                log_info() << "write of job failed" << endl;
                throw(9);
            }
        }

        if (!preproc_file) {
            int sockets[2];

            if (pipe(sockets)) {
                /* for all possible cases, this is something severe */
                exit(errno);
            }

            /* This will fork, and return the pid of the child.  It will not
               return for the child itself.  If it returns normally it will have
               closed the write fd, i.e. sockets[1].  */
            pid_t cpp_pid = call_cpp(job, sockets[1], sockets[0]);

            if (cpp_pid == -1) {
                throw(18);
            }

            try {
                log_block bl2("write_server_cpp from cpp");
                write_server_cpp(sockets[0], cserver);
            } catch (int error) {
                kill(cpp_pid, SIGTERM);
                throw(error);
            }

            log_block wait_cpp("wait for cpp");

            while (waitpid(cpp_pid, &status, 0) < 0 && errno == EINTR) {}

            if (shell_exit_status(status) != 0) {   // failure
                delete cserver;
                cserver = 0;
                return shell_exit_status(status);
            }
        } else {
            int cpp_fd = open(preproc_file, O_RDONLY);

            if (cpp_fd < 0) {
                throw(11);
            }

            log_block cpp_block("write_server_cpp");
            write_server_cpp(cpp_fd, cserver);
        }

        if (!cserver->send_msg(EndMsg())) {
            log_info() << "write of end failed" << endl;
            throw(12);
        }

        Msg *msg;
        {
            log_block wait_cs("wait for cs");
            msg = cserver->get_msg(12 * 60);

            if (!msg) {
                throw(14);
            }
        }

        check_for_failure(msg, cserver);

        if (msg->type != M_COMPILE_RESULT) {
            log_warning() << "waited for compile result, but got " << (char)msg->type << endl;
            delete msg;
            throw(13);
        }

        CompileResultMsg *crmsg = dynamic_cast<CompileResultMsg*>(msg);
        assert(crmsg);

        status = crmsg->status;

        if (status && crmsg->was_out_of_memory) {
            delete crmsg;
            log_info() << "the server ran out of memory, recompiling locally" << endl;
            throw(101);
        }

        if (output) {
            if ((!crmsg->out.empty() || !crmsg->err.empty()) && output_needs_workaround(job)) {
                delete crmsg;
                log_info() << "command needs stdout/stderr workaround, recompiling locally" << endl;
                throw(102);
            }

            write(STDOUT_FILENO, crmsg->out.c_str(), crmsg->out.size());

            if (colorify_wanted(job)) {
                colorify_output(crmsg->err);
            } else {
                write(STDERR_FILENO, crmsg->err.c_str(), crmsg->err.size());
            }

            if (status && (crmsg->err.length() || crmsg->out.length())) {
                log_error() << "Compiled on " << hostname << endl;
            }
        }

        delete crmsg;

        assert(!job.outputFile().empty());

        if (status == 0) {
            receive_file(job.outputFile(), cserver);
        }

    } catch (int x) {
        // Handle pending status messages, if any.
        if(cserver) {
            while(Msg* msg = cserver->get_msg(0)) {
                if(msg->type == M_STATUS_TEXT)
                    log_error() << "Remote status (compiled on " << cserver->name << "): "
                                << static_cast<StatusTextMsg*>(msg)->text << endl;
                delete msg;
            }
            delete cserver;
            cserver = 0;
        }

        throw(x);
    }

    delete cserver;
    return status;
}
Example #9
0
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
void MsgMgr::threadMailboxUpdate()
{
    bool bCallNotificationCallback = false;
    bool bContinue = true;

    while(bContinue)
    {
        bContinue = false;

        ChannelId msgChannelFrom = InvalidChannelId;
        MsgChannel * channel = mChannelList->getHeadChannelList();
        while(channel)
        {
            bool signalNewMessages = false;

            ListenedChannel * listened = channel->getHeadListenedChannel();
            while(listened)
            {
                if(listened->mListener->mCurrentMsg)
                {
                    int numMsgs = 0;
                    StoredMsg * msg = listened->mListener->mCurrentMsg->getNext();
                    while(msg)
                    {
                        StoredMsg * newMsg = channel->createStoredMsg();
                        newMsg->copyFrom(*msg);

                        channel->linkStoredMsg(newMsg);

                        signalNewMessages = true;

                        listened->mListener->mCurrentMsg = listened->mListener->mCurrentMsg->getNext();

                        numMsgs++;
                        if(numMsgs > NumMaxMsgsDispatched) // avoid one sender collapse the msg system
                        {
                            bContinue = true;
                            msg = NULL;
                        }
                        else
                        {
                            msg = listened->mListener->mCurrentMsg->getNext();
                        }
                    }
                }

                listened = listened->getNext();
            }

            if(signalNewMessages)
            {
                ChannelListener * listener = channel->getHeadListenerChannel();
                while(listener)
                {
                    if(listener->mEventMessagesAvailable)
                    {
                        listener->mEventMessagesAvailable->signal();
                    }
                    listener = listener->getNext();
                }
                bCallNotificationCallback = true;
            }

            channel = channel->getNext();
        }

        threadPurgeMessages(); // zzz pending : add min time between purges?
    }

    if(bCallNotificationCallback && mNotificationCallback)
    {
        mNotificationCallback->msgMgrNotification();
    }
}