/* $Id: CbcThread.cpp 2097 2014-11-21 10:57:22Z forrest $ */
// Copyright (C) 2002, International Business Machines
// Corporation and others.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

#if defined(_MSC_VER)
// Turn off compiler warning about long names
#  pragma warning(disable:4786)
#endif

#include "CbcConfig.h"

//#define THREAD_DEBUG
#include <string>
#include <cassert>
#include <cmath>
#include <cfloat>

#include "CbcEventHandler.hpp"

#include "OsiSolverInterface.hpp"
#include "OsiRowCutDebugger.hpp"
#include "CbcThread.hpp"
#include "CbcTree.hpp"
#include "CbcHeuristic.hpp"
#include "CbcCutGenerator.hpp"
#include "CbcModel.hpp"
#include "CbcFathom.hpp"
#include "CbcSimpleIntegerDynamicPseudoCost.hpp"
#include "ClpDualRowDantzig.hpp"
#include "OsiAuxInfo.hpp"

#include "CoinTime.hpp"
#ifdef CBC_THREAD
/// Thread functions
static void * doNodesThread(void * voidInfo);
static void * doCutsThread(void * voidInfo);
static void * doHeurThread(void * voidInfo);
// Default Constructor
CbcSpecificThread::CbcSpecificThread ()
        : basePointer_(NULL),
        masterMutex_(NULL),
        locked_(false)
{
#ifdef CBC_PTHREAD
    pthread_mutex_init(&mutex2_, NULL);
    pthread_cond_init(&condition2_, NULL);
    threadId_.status = 0;
#else
#endif
}
// Useful Constructor
CbcSpecificThread::CbcSpecificThread (CbcSpecificThread * master, pthread_mutex_t * masterMutex)
        : basePointer_(master),
        masterMutex_(masterMutex),
        locked_(false)

{
#ifdef CBC_PTHREAD
    pthread_mutex_init(&mutex2_, NULL);
    pthread_cond_init(&condition2_, NULL);
    threadId_.status = 0;
#else
#endif

}
// Useful stuff
void
CbcSpecificThread::setUsefulStuff (CbcSpecificThread * master, void *& masterMutex)

{
#ifdef CBC_PTHREAD
    basePointer_ = master;
    if (masterMutex) {
        masterMutex_ = reinterpret_cast<pthread_mutex_t *>(masterMutex);
    } else {
        // create master mutex
        masterMutex_ = new pthread_mutex_t;
        pthread_mutex_init(masterMutex_, NULL);
        masterMutex = reinterpret_cast<void *>(masterMutex_);
    }
#else
#endif
}

CbcSpecificThread::~CbcSpecificThread()
{
#ifdef CBC_PTHREAD
    pthread_mutex_destroy (&mutex2_);
    if (basePointer_ == this) {
        pthread_mutex_destroy (masterMutex_);
        delete masterMutex_;
    }
#else
#endif
}
/*
  Locks a thread if parallel so that stuff like cut pool
  can be updated and/or used.
*/
void
CbcSpecificThread::lockThread()
{
#ifdef CBC_PTHREAD
    // Use master mutex
    assert (basePointer_->masterMutex_ == masterMutex_);
    pthread_mutex_lock (masterMutex_);
#else
#endif
}
/*
  Unlocks a thread if parallel to say cut pool stuff not needed
*/
void
CbcSpecificThread::unlockThread()
{
#ifdef CBC_PTHREAD
    // Use master mutex
    pthread_mutex_unlock (masterMutex_);
#else
#endif
}
//  Locks a thread for testing whether to start etc
void
CbcSpecificThread::lockThread2(bool doAnyway)
{
    if (!locked_ || doAnyway) {
#ifdef CBC_PTHREAD
        pthread_mutex_lock (&mutex2_);
#else
#endif
        locked_ = true;
    }
}
//  Unlocks a thread for testing whether to start etc
void
CbcSpecificThread::unlockThread2(bool doAnyway)
{
    if (locked_ || doAnyway) {
#ifdef CBC_PTHREAD
        pthread_mutex_unlock (&mutex2_);
#else
#endif
        locked_ = false;
    }
}
#ifdef HAVE_CLOCK_GETTIME
inline int my_gettime(struct timespec* tp)
{
    return clock_gettime(CLOCK_REALTIME, tp);
}
#else
#ifndef _MSC_VER
inline int my_gettime(struct timespec* tp)
{
    struct timeval tv;
    int ret = gettimeofday(&tv, NULL);
    tp->tv_sec = tv.tv_sec;
    tp->tv_nsec = tv.tv_usec * 1000;
    return ret;
}
#else
inline int my_gettime(struct timespec* tp)
{
    double t = CoinGetTimeOfDay();
    tp->tv_sec = (int)floor(t);
    tp->tv_nsec = (int)((tp->tv_sec - floor(t)) / 1000000.0);
    return 0;
}
#endif
#endif
// Get time
static double getTime()
{
    struct timespec absTime2;
    my_gettime(&absTime2);
    double time2 = absTime2.tv_sec + 1.0e-9 * 
      static_cast<double>(absTime2.tv_nsec);
    return time2;
}
// Timed wait in nanoseconds - if negative then seconds
void
CbcSpecificThread::timedWait(int time)
{

#ifdef CBC_PTHREAD
    struct timespec absTime;
    my_gettime(&absTime);
    if (time > 0) {
        absTime.tv_nsec += time;
        if (absTime.tv_nsec >= 1000000000) {
            absTime.tv_nsec -= 1000000000;
            absTime.tv_sec++;
        }
    } else {
        absTime.tv_sec -= time;
    }
    pthread_cond_timedwait(&condition2_, &mutex2_, &absTime);
#else
#endif
}
// Signal
void
CbcSpecificThread::signal()
{
#ifdef CBC_PTHREAD
    pthread_cond_signal(&condition2_);
#else
#endif
}
// Actually starts a thread
void
CbcSpecificThread::startThread(void * (*routine ) (void *), CbcThread * thread)
{
#ifdef CBC_PTHREAD
    pthread_create(&(threadId_.thr), NULL, routine, thread);
    threadId_.status = 1;
#else
#endif
}
// Exits thread (from master)
int
CbcSpecificThread::exit()
{
#ifdef CBC_PTHREAD
    pthread_cond_signal(&condition2_); // unlock
    return pthread_join(threadId_.thr, NULL);
#else
#endif
}
// Exits thread
void
CbcSpecificThread::exitThread()
{
#ifdef CBC_PTHREAD
    pthread_mutex_unlock(&mutex2_);
    pthread_exit(NULL);
#else
#endif

}
// Get status
int
CbcSpecificThread::status() const
{
#ifdef CBC_PTHREAD
    return static_cast<int>(threadId_.status);
#else
#endif
}
// Set status
void
CbcSpecificThread::setStatus(int value)
{
#ifdef CBC_PTHREAD
    threadId_.status = value;
#else
#endif
}
// Parallel heuristics
void
parallelHeuristics (int numberThreads,
                    int sizeOfData,
                    void * argBundle)
{
    Coin_pthread_t * threadId = new Coin_pthread_t [numberThreads];
    char * args = reinterpret_cast<char *>(argBundle);
    for (int i = 0; i < numberThreads; i++) {
        pthread_create(&(threadId[i].thr), NULL, doHeurThread,
                       args + i*sizeOfData);
    }
    // now wait
    for (int i = 0; i < numberThreads; i++) {
        pthread_join(threadId[i].thr, NULL);
    }
    delete [] threadId;
}
// End of specific thread stuff

/// Default constructor
CbcThread::CbcThread()
        :
        baseModel_(NULL),
        thisModel_(NULL),
        node_(NULL), // filled in every time
        createdNode_(NULL), // filled in every time on return
        returnCode_(-1), // -1 available, 0 busy, 1 finished , 2??
        timeLocked_(0.0),
        timeWaitingToLock_(0.0),
        timeWaitingToStart_(0.0),
        timeInThread_(0.0),
        numberTimesLocked_(0),
        numberTimesUnlocked_(0),
        numberTimesWaitingToStart_(0),
        dantzigState_(0), // 0 unset, -1 waiting to be set, 1 set
        locked_(false),
        nDeleteNode_(0),
        delNode_(NULL),
        maxDeleteNode_(0),
        nodesThisTime_(0),
        iterationsThisTime_(0),
        deterministic_(0)
{
}
void
CbcThread::gutsOfDelete()
{
    baseModel_ = NULL;
    thisModel_ = NULL;
    node_ = NULL;
    createdNode_ = NULL;
    delNode_ = NULL;
}
// Destructor
CbcThread::~CbcThread()
{
}
// Fills in useful stuff
void
CbcThread::setUsefulStuff (CbcModel * model, int deterministic, CbcModel * baseModel,
                           CbcThread * master,
                           void *& masterMutex)
{
    baseModel_ = baseModel;
    thisModel_ = model;
    deterministic_ = deterministic;
    threadStuff_.setUsefulStuff(&master->threadStuff_, masterMutex);
    node_ = NULL;
    createdNode_ = NULL;
    master_ = master;
    returnCode_ = -1;
    timeLocked_ = 0.0;
    timeWaitingToLock_ = 0.0;
    timeWaitingToStart_ = 0.0;
    timeInThread_ = 0.0;
    numberTimesLocked_ = 0;
    numberTimesUnlocked_ = 0;
    numberTimesWaitingToStart_ = 0;
    dantzigState_ = 0; // 0 unset, -1 waiting to be set, 1 set
    locked_ = false;
    delNode_ = NULL;
    maxDeleteNode_ = 0;
    nDeleteNode_ = 0;
    nodesThisTime_ = 0;
    iterationsThisTime_ = 0;
    if (model != baseModel) {
        // thread
        thisModel_->setInfoInChild(-3, this);
        if (deterministic_ >= 0)
            thisModel_->moveToModel(baseModel, -1);
        if (deterministic == -1)
            threadStuff_.startThread( doCutsThread, this);
        else
            threadStuff_.startThread( doNodesThread, this);
    }
}
/*
  Locks a thread if parallel so that stuff like cut pool
  can be updated and/or used.
*/
void
CbcThread::lockThread()
{
    if (!locked_) {
        double time2 = getTime();
        threadStuff_.lockThread();
        locked_ = true;
        timeWhenLocked_ = getTime();
        timeWaitingToLock_ += timeWhenLocked_ - time2;;
        numberTimesLocked_++;
#ifdef THREAD_DEBUG
        lockCount_ ++;
#if THREAD_DEBUG>1
        if (threadNumber_ == -1)
            printf("locking master %d\n", lockCount_);
        else
            printf("locking thread %d %d\n", threadNumber_, lockCount_);
#endif
    } else {
        if (threadNumber_ == -1)
            printf("master already locked %d\n", lockCount_);
        else
            printf("thread already locked %d %d\n", threadNumber_, lockCount_);
#endif
    }
}
/*
  Unlocks a thread if parallel
*/
void
CbcThread::unlockThread()
{
    if (locked_) {
        locked_ = false;
        threadStuff_.unlockThread();
        double time2 = getTime();
        timeLocked_ += time2 - timeWhenLocked_;
        numberTimesUnlocked_++;
#ifdef THREAD_DEBUG
#if THREAD_DEBUG>1
        if (threadNumber_ == -1)
            printf("unlocking master %d\n", lockCount_);
        else
            printf("unlocking thread %d %d\n", threadNumber_, lockCount_);
#endif
    } else {
        if (threadNumber_ == -1)
            printf("master already unlocked %d\n", lockCount_);
        else
            printf("thread already unlocked %d %d\n", threadNumber_, lockCount_);
#endif
    }
}
/* Wait for child to have return code NOT == to currentCode
   type - 0 timed wait
   1 wait
   returns true if return code changed */
bool
CbcThread::wait(int type, int currentCode)
{
    if (!type) {
        // just timed wait
        master_->threadStuff_.lockThread2();
        master_->threadStuff_.timedWait(1000000);
        master_->threadStuff_.unlockThread2();
    } else {
        // wait until return code changes
        while (returnCode_ == currentCode) {
            threadStuff_.signal();
            master_->threadStuff_.lockThread2();
            master_->threadStuff_.timedWait(1000000);
            master_->threadStuff_.unlockThread2();
        }
    }
    return (returnCode_ != currentCode);
}
#if 0
pthread_cond_signal(&condition2_);
-
if (!locked_)
{
    pthread_mutex_lock (&mutex2_);
    locked_ = true;
}
-
pthread_cond_timedwait(&condition2_, &mutex2_, &absTime);
-
if (locked_)
{
    pthread_mutex_unlock (&mutex2_);
    locked_ = false;
}
#endif
// Waits until returnCode_ goes to zero
void
CbcThread::waitThread()
{
    double time = getTime();
    threadStuff_.lockThread2();
    while (returnCode_) {
        threadStuff_.timedWait(-10); // 10 seconds
    }
    timeWaitingToStart_ += getTime() - time;
    numberTimesWaitingToStart_++;
}
// Just wait for so many nanoseconds
void
CbcThread::waitNano(int time)
{
    threadStuff_.lockThread2();
    threadStuff_.timedWait(time);
    threadStuff_.unlockThread2();
}
// Signal child to carry on
void
CbcThread::signal()
{
    threadStuff_.signal();
}
// Lock from master with mutex2 and signal before lock
void
CbcThread::lockFromMaster()
{
    threadStuff_.signal();
    master_->threadStuff_.lockThread2(true);
}
// Unlock from master with mutex2 and signal after unlock
void
CbcThread::unlockFromMaster()
{
    master_->threadStuff_.unlockThread2(true); // unlock anyway
    threadStuff_.signal();
}
// Lock from thread with mutex2 and signal before lock
void
CbcThread::lockFromThread()
{
    master_->threadStuff_.signal();
    threadStuff_.lockThread2();
}
// Unlock from thread with mutex2 and signal after unlock
void
CbcThread::unlockFromThread()
{
    master_->threadStuff_.signal();
    threadStuff_.unlockThread2();
}
// Exits thread (from master)
int
CbcThread::exit()
{
    return threadStuff_.exit();
}
// Exits thread
void
CbcThread::exitThread()
{
    threadStuff_.exitThread();
}
// Default constructor
CbcBaseModel::CbcBaseModel()
        :
        numberThreads_(0),
        children_(NULL),
        type_(0),
        threadCount_(NULL),
        threadModel_(NULL),
        numberObjects_(0),
        saveObjects_(NULL),
        defaultParallelIterations_(400),
        defaultParallelNodes_(2)
{
}
// Constructor with model
CbcBaseModel::CbcBaseModel (CbcModel & model,  int type)
        :
        children_(NULL),
        type_(type),
        threadCount_(NULL),
        threadModel_(NULL),
        numberObjects_(0),
        saveObjects_(NULL),
        defaultParallelIterations_(400),
        defaultParallelNodes_(2)
{
    numberThreads_ = model.getNumberThreads();
    if (numberThreads_) {
        children_ = new CbcThread [numberThreads_+1];
        // Do a partial one for base model
        void * mutex_main = NULL;
        children_[numberThreads_].setUsefulStuff(&model, type_, &model,
                children_ + numberThreads_, mutex_main);
#ifdef THREAD_DEBUG
        children_[numberThreads_].threadNumber_ = -1;
        children_[numberThreads_].lockCount_ = 0;
#endif
        threadCount_ = new int [numberThreads_];
        CoinZeroN(threadCount_, numberThreads_);
        threadModel_ = new CbcModel * [numberThreads_+1];
        memset(threadStats_, 0, sizeof(threadStats_));
        if (type_ > 0) {
            // May need for deterministic
            numberObjects_ = model.numberObjects();
            saveObjects_ = new OsiObject * [numberObjects_];
            for (int i = 0; i < numberObjects_; i++) {
                saveObjects_[i] = model.object(i)->clone();
            }
        }
        // we don't want a strategy object
        CbcStrategy * saveStrategy = model.strategy();
        model.setStrategy(NULL);
        for (int i = 0; i < numberThreads_; i++) {
            //threadModel_[i] = new CbcModel(model, true);
            threadModel_[i] = model. clone (true);
            threadModel_[i]->synchronizeHandlers(1);
#ifdef COIN_HAS_CLP
            // Solver may need to know about model
            CbcModel * thisModel = threadModel_[i];
            CbcOsiSolver * solver =
                dynamic_cast<CbcOsiSolver *>(thisModel->solver()) ;
            if (solver)
                solver->setCbcModel(thisModel);
#endif
            children_[i].setUsefulStuff(threadModel_[i], type_, &model,
                                        children_ + numberThreads_, mutex_main);
#ifdef THREAD_DEBUG
            children_[i].threadNumber_ = i;
            children_[i].lockCount_ = 0;
#endif
        }
        model.setStrategy(saveStrategy);
    }
}
// Stop threads
void
CbcBaseModel::stopThreads(int type)
{
    CbcModel * baseModel = children_[0].baseModel();
    if (type < 0) {
	// max nodes ?
	bool finished = false;
	while (!finished) {
	  finished = true;
	  for (int i = 0; i < numberThreads_; i++) {
            if (abs(children_[i].returnCode()) != 1) {
	      children_[i].wait(1, 0); 
	      finished=false;
	    }
	  }
        }
	for (int i = 0; i < numberThreads_; i++) {
	  baseModel->incrementExtra(threadModel_[i]->getExtraNodeCount(),
				    threadModel_[i]->numberExtraIterations(),
				    threadModel_[i]->getFathomCount());
	  threadModel_[i]->zeroExtra();
	}
        return;
    }
    for (int i = 0; i < numberThreads_; i++) {
        children_[i].wait(1, 0);
        assert (children_[i].returnCode() == -1);
	baseModel->incrementExtra(threadModel_[i]->getExtraNodeCount(),
				  threadModel_[i]->numberExtraIterations(),
				  threadModel_[i]->getFathomCount());
        threadModel_[i]->setInfoInChild(-2, NULL);
        children_[i].setReturnCode( 0);
        children_[i].exit();
        children_[i].setStatus( 0);
    }
    // delete models and solvers
    for (int i = 0; i < numberThreads_; i++) {
        threadModel_[i]->setInfoInChild(type_, NULL);
        delete threadModel_[i];
    }
    delete [] children_;
    delete [] threadModel_;
    for (int i = 0; i < numberObjects_; i++)
        delete saveObjects_[i];
    delete [] saveObjects_;
    children_ = NULL;
    threadModel_ = NULL;
    saveObjects_ = NULL;
    numberObjects_ = 0;
    numberThreads_ = 0;
}
// Wait for threads in tree
int
CbcBaseModel::waitForThreadsInTree(int type)
{
    CbcModel * baseModel = children_[0].baseModel();
    int anyLeft = 0;
    // May be able to combine parts later
    if (type == 0) {
        bool locked = true;
#ifdef COIN_DEVELOP
        printf("empty\n");
#endif
        // may still be outstanding nodes
        while (true) {
            int iThread;
            for (iThread = 0; iThread < numberThreads_; iThread++) {
                if (children_[iThread].status()) {
		  if (children_[iThread].returnCode() == 0) {
                        break;
		  }
                }
            }
            if (iThread < numberThreads_) {
#ifdef COIN_DEVELOP
                printf("waiting for thread %d code 0\n", iThread);
#endif
                unlockThread();
                locked = false;
                children_[iThread].wait(1, 0);
                assert(children_[iThread].returnCode() == 1);
                threadModel_[iThread]->moveToModel(baseModel, 1);
#ifdef THREAD_PRINT
                printf("off thread2 %d node %x\n", iThread, children_[iThread].node());
#endif
                children_[iThread].setNode(NULL);
                anyLeft = 1;
                assert (children_[iThread].returnCode() == 1);
                if (children_[iThread].dantzigState() == -1) {
                    // 0 unset, -1 waiting to be set, 1 set
                    children_[iThread].setDantzigState(1);
                    CbcModel * model = children_[iThread].thisModel();
                    OsiClpSolverInterface * clpSolver2
                    = dynamic_cast<OsiClpSolverInterface *> (model->solver());
                    assert (clpSolver2);
                    ClpSimplex * simplex2 = clpSolver2->getModelPtr();
                    ClpDualRowDantzig dantzig;
                    simplex2->setDualRowPivotAlgorithm(dantzig);
                }
                // say available
                children_[iThread].setReturnCode( -1);
                threadStats_[4]++;
#ifdef COIN_DEVELOP
                printf("thread %d code now -1\n", iThread);
#endif
                break;
            } else {
#ifdef COIN_DEVELOP
                printf("no threads at code 0 \n");
#endif
                // now check if any have just finished
                for (iThread = 0; iThread < numberThreads_; iThread++) {
                    if (children_[iThread].status()) {
                        if (children_[iThread].returnCode() == 1)
                            break;
                    }
                }
                if (iThread < numberThreads_) {
                    unlockThread();
                    locked = false;
                    threadModel_[iThread]->moveToModel(baseModel, 1);
#ifdef THREAD_PRINT
                    printf("off thread3 %d node %x\n", iThread, children_[iThread].node());
#endif
                    children_[iThread].setNode(NULL);
                    anyLeft = 1;
                    assert (children_[iThread].returnCode() == 1);
                    // say available
                    children_[iThread].setReturnCode( -1);
                    threadStats_[4]++;
#ifdef COIN_DEVELOP
                    printf("thread %d code now -1\n", iThread);
#endif
                    break;
                }
            }
            if (!baseModel->tree()->empty()) {
#ifdef COIN_DEVELOP
                printf("tree not empty!!!!!!\n");
#endif
                if (locked)
                    unlockThread();
                return 1;
                break;
            }
            for (iThread = 0; iThread < numberThreads_; iThread++) {
                if (children_[iThread].status()) {
                    if (children_[iThread].returnCode() != -1) {
                        printf("bad end of tree\n");
                        abort();
                    }
                }
            }
            break;
        }
#ifdef COIN_DEVELOP
        printf("finished ************\n");
#endif
        if (locked)
            unlockThread();
        return anyLeft;
    } else if (type == 1) {
        // normal
        double cutoff = baseModel->getCutoff();
        CbcNode * node = baseModel->tree()->bestNode(cutoff) ;
        // Possible one on tree worse than cutoff
        if (!node || node->objectiveValue() > cutoff)
            return 1;
        threadStats_[0]++;
        //need to think
        int iThread;
        // Start one off if any available
        for (iThread = 0; iThread < numberThreads_; iThread++) {
	  if (children_[iThread].returnCode() == -1) {
                break;
	  }
        }
        if (iThread < numberThreads_) {
            children_[iThread].setNode(node);
#ifdef THREAD_PRINT
            printf("empty thread %d node %x\n", iThread, children_[iThread].node());
#endif
            assert (children_[iThread].returnCode() == -1);
            // say in use
            threadModel_[iThread]->moveToModel(baseModel, 0);
            // This has to be AFTER moveToModel
            children_[iThread].setReturnCode( 0);
            children_[iThread].signal();
            threadCount_[iThread]++;
        }
        lockThread();
        // see if any finished
        for (iThread = 0; iThread < numberThreads_; iThread++) {
            if (children_[iThread].returnCode() > 0)
                break;
        }
        unlockThread();
        if (iThread < numberThreads_) {
            threadModel_[iThread]->moveToModel(baseModel, 1);
#ifdef THREAD_PRINT
            printf("off thread4 %d node %x\n", iThread, children_[iThread].node());
#endif
            children_[iThread].setNode(NULL);
            anyLeft = 1;
            assert (children_[iThread].returnCode() == 1);
            // say available
            children_[iThread].setReturnCode( -1);
            // carry on
            threadStats_[3]++;
        } else {
            // Start one off if any available
            for (iThread = 0; iThread < numberThreads_; iThread++) {
                if (children_[iThread].returnCode() == -1)
                    break;
            }
            if (iThread < numberThreads_) {
                // If any on tree get
                if (!baseModel->tree()->empty()) {
                    //node = baseModel->tree()->bestNode(cutoff) ;
                    //assert (node);
                    threadStats_[1]++;
                    return 1; // ** get another node
                }
            }
            // wait (for debug could sleep and use test)
            bool finished = false;
            while (!finished) {
                double time = getTime();
                children_[numberThreads_].wait(0, 0);
                children_[numberThreads_].incrementTimeInThread(getTime() - time);
                for (iThread = 0; iThread < numberThreads_; iThread++) {
                    if (children_[iThread].returnCode() > 0) {
                        finished = true;
                        break;
                    } else if (children_[iThread].returnCode() == 0) {
                        children_[iThread].signal(); // unlock
                    }
                }
            }
            assert (iThread < numberThreads_);
            // move information to model
            threadModel_[iThread]->moveToModel(baseModel, 1);
            anyLeft = 1;
#ifdef THREAD_PRINT
            printf("off thread %d node %x\n", iThread, children_[iThread].node());
#endif
            children_[iThread].setNode(NULL);
            assert (children_[iThread].returnCode() == 1);
            // say available
            children_[iThread].setReturnCode( -1);
        }
        // carry on
        threadStats_[2]++;
        for (int iThread = 0; iThread < numberThreads_; iThread++) {
            if (children_[iThread].status()) {
                if (children_[iThread].returnCode() != -1) {
                    anyLeft = 1;
                    break;
                }
            }
        }
        return anyLeft;
    } else if (type == 2) {
        if (!baseModel->tree()->empty()) {
  	  // max nodes ?
	  bool finished = false;
	  while (!finished) {
	    finished = true;
	    for (int iThread = 0; iThread < numberThreads_; iThread++) {
	      if (children_[iThread].returnCode() == 0) { 
		double time = getTime();
		children_[numberThreads_].wait(0, 0);
		children_[numberThreads_].incrementTimeInThread(getTime() - time);
		finished = false;
		children_[iThread].signal(); // unlock
	      }
	    }
	  }
        }
        int i;
        // do statistics
        // Seems to be bug in CoinCpu on Linux - does threads as well despite documentation
        double time = 0.0;
        for (i = 0; i < numberThreads_; i++)
            time += children_[i].timeInThread();
        bool goodTimer = time < (baseModel->getCurrentSeconds());
        for (i = 0; i < numberThreads_; i++) {
            while (children_[i].returnCode() == 0) {
                children_[i].signal();
                double time = getTime();
                children_[numberThreads_].wait(0, 0);
                children_[numberThreads_].incrementTimeInThread(getTime() - time);
            }
            children_[i].lockFromMaster();
            threadModel_[i]->setNumberThreads(0); // say exit
            if (children_[i].deterministic() > 0)
                delete [] children_[i].delNode();
	    if (children_[i].node()) {
	      delete children_[i].node();
	      children_[i].setNode(NULL);
	    }
            children_[i].setReturnCode( 0);
            children_[i].unlockFromMaster();
#ifndef NDEBUG
            int returnCode = children_[i].exit();
            assert (!returnCode);
#else
            children_[i].exit();
#endif
            children_[i].setStatus( 0);
            //else
            threadModel_[i]->moveToModel(baseModel, 2);
            assert (children_[i].numberTimesLocked() == children_[i].numberTimesUnlocked());
            baseModel->messageHandler()->message(CBC_THREAD_STATS, baseModel->messages())
            << "Thread";
            baseModel->messageHandler()->printing(true)
            << i << threadCount_[i] << children_[i].timeWaitingToStart();
            baseModel->messageHandler()->printing(goodTimer) << children_[i].timeInThread();
            baseModel->messageHandler()->printing(false) << 0.0;
            baseModel->messageHandler()->printing(true) << children_[i].numberTimesLocked()
            << children_[i].timeLocked() << children_[i].timeWaitingToLock()
            << CoinMessageEol;
        }
        assert (children_[numberThreads_].numberTimesLocked() == children_[numberThreads_].numberTimesUnlocked());
        baseModel->messageHandler()->message(CBC_THREAD_STATS, baseModel->messages())
        << "Main thread";
        baseModel->messageHandler()->printing(false) << 0 << 0 << 0.0;
        baseModel->messageHandler()->printing(false) << 0.0;
        baseModel->messageHandler()->printing(true) << children_[numberThreads_].timeInThread();
        baseModel->messageHandler()->printing(true) << children_[numberThreads_].numberTimesLocked()
        << children_[numberThreads_].timeLocked() << children_[numberThreads_].timeWaitingToLock()
        << CoinMessageEol;
        // delete models (here in case some point to others)
        for (i = 0; i < numberThreads_; i++) {
            // make sure handler will be deleted
            threadModel_[i]->setDefaultHandler(true);
            //delete threadModel_[i];
        }
    } else {
        abort();
    }
    return 0;
}
void
CbcBaseModel::waitForThreadsInCuts(int type, OsiCuts * eachCuts,
                                   int whichGenerator)
{
    if (type == 0) {
        // cuts while doing
        bool finished = false;
        int iThread = -1;
        // see if any available
        for (iThread = 0; iThread < numberThreads_; iThread++) {
            if (children_[iThread].returnCode()) {
                finished = true;
                break;
            } else if (children_[iThread].returnCode() == 0) {
                children_[iThread].signal();
            }
        }
        while (!finished) {
            children_[numberThreads_].waitNano(1000000);
            for (iThread = 0; iThread < numberThreads_; iThread++) {
                if (children_[iThread].returnCode() > 0) {
                    finished = true;
                    break;
                } else if (children_[iThread].returnCode() == 0) {
                    children_[iThread].signal();
                }
            }
        }
        assert (iThread < numberThreads_);
        assert (children_[iThread].returnCode());
        // Use dantzigState to signal which generator
        children_[iThread].setDantzigState(whichGenerator);
        // and delNode for eachCuts
        children_[iThread].fakeDelNode(reinterpret_cast<CbcNode **> (eachCuts));
        // allow to start
        children_[iThread].setReturnCode( 0);
        children_[iThread].signal();
    } else if (type == 1) {
        // cuts - finish up
        for (int iThread = 0; iThread < numberThreads_; iThread++) {
            if (children_[iThread].returnCode() == 0) {
                bool finished = false;
                while (!finished) {
                    children_[numberThreads_].wait(0, 0);
                    if (children_[iThread].returnCode() > 0) {
                        finished = true;
                        break;
                        //#ifndef NEW_STYLE_PTHREAD
                        //} else if (children_[iThread].returnCode_ == 0) {
                        //pthread_cond_signal(&children_[iThread].threadStuff_.condition2_); // unlock
                        //#endif
                    }
                }
            }
            assert (children_[iThread].returnCode());
            // say available
            children_[iThread].setReturnCode( -1);
            //delete threadModel_[iThread]->solver();
            //threadModel_[iThread]->setSolver(NULL);
        }
    } else {
        abort();
    }
}
// Returns pointer to master thread
CbcThread *
CbcBaseModel::masterThread() const
{
    return children_ + numberThreads_;
}

// Split model and do work in deterministic parallel
void
CbcBaseModel::deterministicParallel()
{
    CbcModel * baseModel = children_[0].baseModel();
    for (int i = 0; i < numberThreads_; i++)
        threadCount_[i]++;
    int saveTreeSize = baseModel->tree()->size();
    // For now create threadModel - later modify splitModel
    CbcModel ** threadModel = new CbcModel * [numberThreads_];
    int iThread;
    for (iThread = 0; iThread < numberThreads_; iThread++)
        threadModel[iThread] = children_[iThread].thisModel();

    int nAffected = baseModel->splitModel(numberThreads_, threadModel, defaultParallelNodes_);
    // do all until finished
    for (iThread = 0; iThread < numberThreads_; iThread++) {
        // obviously tune
        children_[iThread].setNDeleteNode(defaultParallelIterations_);
    }
    // Save current state
    int iObject;
    OsiObject ** object = baseModel->objects();
    for (iObject = 0; iObject < numberObjects_; iObject++) {
        saveObjects_[iObject]->updateBefore(object[iObject]);
    }
    //#define FAKE_PARALLEL
#ifndef FAKE_PARALLEL
    for (iThread = 0; iThread < numberThreads_; iThread++) {
        children_[iThread].setReturnCode( 0);
        children_[iThread].signal();
    }
    // wait
    bool finished = false;
    double time = getTime();
    while (!finished) {
        children_[numberThreads_].waitNano( 1000000); // millisecond
        finished = true;
        for (iThread = 0; iThread < numberThreads_; iThread++) {
            if (children_[iThread].returnCode() <= 0) {
                finished = false;
            }
        }
    }
    for (iThread = 0; iThread < numberThreads_; iThread++)
        children_[iThread].setReturnCode(-1);
#else
    // wait
    bool finished = false;
    double time = getTime();
    for (iThread = 0; iThread < numberThreads_; iThread++) {
        children_[iThread].setReturnCode( 0);
        children_[iThread].signal();
	while (!finished) {
	  children_[numberThreads_].waitNano( 1000000); // millisecond
	  finished = (children_[iThread].returnCode() >0);
	}
        children_[iThread].setReturnCode(-1);
	finished=false;
    }
#endif
    children_[numberThreads_].incrementTimeInThread(getTime() - time);
    // Unmark marked
    for (int i = 0; i < nAffected; i++) {
        baseModel->walkback()[i]->unmark();
    }
    int iModel;
    double scaleFactor = 1.0;
    for (iModel = 0; iModel < numberThreads_; iModel++) {
        //printf("model %d tree size %d\n",iModel,threadModel[iModel]->baseModel->tree()->size());
        if (saveTreeSize > 4*numberThreads_*defaultParallelNodes_) {
            if (!threadModel[iModel]->tree()->size()) {
                scaleFactor *= 1.05;
            }
        }
        threadModel[iModel]->moveToModel(baseModel, 11);
        // Update base model
        OsiObject ** threadObject = threadModel[iModel]->objects();
        for (iObject = 0; iObject < numberObjects_; iObject++) {
            object[iObject]->updateAfter(threadObject[iObject], saveObjects_[iObject]);
        }
    }
    if (scaleFactor != 1.0) {
        int newNumber = static_cast<int> (defaultParallelNodes_ * scaleFactor + 0.5001);
        if (newNumber*2 < defaultParallelIterations_) {
            if (defaultParallelNodes_ == 1)
                newNumber = 2;
            if (newNumber != defaultParallelNodes_) {
                char general[200];
                sprintf(general, "Changing tree size from %d to %d",
                        defaultParallelNodes_, newNumber);
                baseModel->messageHandler()->message(CBC_GENERAL,
                                                     baseModel->messages())
                << general << CoinMessageEol ;
                defaultParallelNodes_ = newNumber;
            }
        }
    }
    delete [] threadModel;
}
// Destructor
CbcBaseModel::~CbcBaseModel()
{
    delete [] threadCount_;
#if 1
    for (int i = 0; i < numberThreads_; i++)
        delete threadModel_[i];
    delete [] threadModel_;
    delete [] children_;
#endif
    for (int i = 0; i < numberObjects_; i++)
        delete saveObjects_[i];
    delete [] saveObjects_;
}
// Sets Dantzig state in children
void
CbcBaseModel::setDantzigState()
{
    for (int i = 0; i < numberThreads_; i++) {
        children_[i].setDantzigState(-1);
    }
}
static void * doNodesThread(void * voidInfo)
{
    CbcThread * stuff = reinterpret_cast<CbcThread *> (voidInfo);
    CbcModel * thisModel = stuff->thisModel();
    CbcModel * baseModel = stuff->baseModel();
    while (true) {
        stuff->waitThread();
        //printf("start node %x\n",stuff->node);
        int mode = thisModel->getNumberThreads();
        if (mode) {
            // normal
            double time2 = CoinCpuTime();
            assert (stuff->returnCode() == 0);
            if (thisModel->parallelMode() >= 0) {
                CbcNode * node = stuff->node();
                //assert (node->nodeInfo());
                CbcNode * createdNode = stuff->createdNode();
		// try and see if this has slipped through
		if (node) {
		  thisModel->doOneNode(baseModel, node, createdNode);
		} else {
		  //printf("null node\n");
		  createdNode=NULL;
		}
                stuff->setNode(node);
                stuff->setCreatedNode(createdNode);
                stuff->setReturnCode( 1);
            } else {
                assert (!stuff->node());
                assert (!stuff->createdNode());
                int numberIterations = stuff->nDeleteNode();
                int nDeleteNode = 0;
                int maxDeleteNode = stuff->maxDeleteNode();
                CbcNode ** delNode = stuff->delNode();
                int returnCode = 1;
                // this should be updated by heuristics strong branching etc etc
                assert (numberIterations > 0);
                thisModel->setNumberThreads(0);
                int nodesThisTime = thisModel->getNodeCount();
                int iterationsThisTime = thisModel->getIterationCount();
                int strongThisTime = thisModel->numberStrongIterations();
                thisModel->setStopNumberIterations(thisModel->getIterationCount() + numberIterations);
                int numberColumns = thisModel->getNumCols();
                int * used = CoinCopyOfArray(thisModel->usedInSolution(), numberColumns);
                int numberSolutions = thisModel->getSolutionCount();
                while (true) {
                    if (thisModel->tree()->empty()) {
                        returnCode = 1 + 1;
#ifdef CLP_INVESTIGATE_2
                        printf("%x tree empty - time %18.6f\n", thisModel, CoinGetTimeOfDay() - 1.2348e9);
#endif
                        break;
                    }
#define NODE_ITERATIONS 2
                    int nodesNow = thisModel->getNodeCount();
                    int iterationsNow = thisModel->getIterationCount();
                    int strongNow = thisModel->numberStrongIterations();
                    bool exit1 = (NODE_ITERATIONS * ((nodesNow - nodesThisTime) +
                                                     ((strongNow - strongThisTime) >> 1)) +
                                  (iterationsNow - iterationsThisTime) > numberIterations);
                    //bool exit2 =(thisModel->getIterationCount()>thisModel->getStopNumberIterations()) ;
                    //assert (exit1==exit2);
                    if (exit1 && nodesNow - nodesThisTime >= 10) {
                        // out of loop
                        //printf("out of loop\n");
#ifdef CLP_INVESTIGATE3
                        printf("%x tree %d nodes left, done %d and %d its - time %18.6f\n", thisModel,
                               thisModel->tree()->size(), nodesNow - nodesThisTime,
                               iterationsNow - iterationsThisTime, CoinGetTimeOfDay() - 1.2348e9);
#endif
                        break;
                    }
                    double cutoff = thisModel->getCutoff() ;
                    CbcNode *node = thisModel->tree()->bestNode(cutoff) ;
                    // Possible one on tree worse than cutoff
                    if (!node)
                        continue;
                    CbcNode * createdNode = NULL;
                    // Do real work of node
                    thisModel->doOneNode(NULL, node, createdNode);
                    assert (createdNode);
                    if (!createdNode->active()) {
                        delete createdNode;
                    } else {
                        // Say one more pointing to this **** postpone if marked
                        node->nodeInfo()->increment() ;
                        thisModel->tree()->push(createdNode) ;
                    }
                    if (node->active()) {
                        assert (node->nodeInfo());
                        if (node->nodeInfo()->numberBranchesLeft()) {
                            thisModel->tree()->push(node) ;
                        } else {
                            node->setActive(false);
                        }
                    } else {
                        if (node->nodeInfo()) {
                            if (!node->nodeInfo()->numberBranchesLeft())
                                node->nodeInfo()->allBranchesGone(); // can clean up
                            // So will delete underlying stuff
                            node->setActive(true);
                        }
                        if (nDeleteNode == maxDeleteNode) {
                            maxDeleteNode = (3 * maxDeleteNode) / 2 + 10;
                            stuff->setMaxDeleteNode(maxDeleteNode);
                            stuff->setDelNode(new CbcNode * [maxDeleteNode]);
                            for (int i = 0; i < nDeleteNode; i++)
                                stuff->delNode()[i] = delNode[i];
                            delete [] delNode;
                            delNode = stuff->delNode();
                        }
                        delNode[nDeleteNode++] = node;
                    }
                }
                // end of this sub-tree
                int * usedA = thisModel->usedInSolution();
                for (int i = 0; i < numberColumns; i++) {
                    usedA[i] -= used[i];
                }
                delete [] used;
                thisModel->setSolutionCount(thisModel->getSolutionCount() - numberSolutions);
                stuff->setNodesThisTime(thisModel->getNodeCount() - nodesThisTime);
                stuff->setIterationsThisTime(thisModel->getIterationCount() - iterationsThisTime);
                stuff->setNDeleteNode(nDeleteNode);
                stuff->setReturnCode( returnCode);
                thisModel->setNumberThreads(mode);
            }
            //printf("end node %x\n",stuff->node);
            stuff->unlockFromThread();
            stuff->incrementTimeInThread(CoinCpuTime() - time2);
        } else {
            // exit
            break;
        }
    }
    //printf("THREAD exiting\n");
    stuff->exitThread();
    return NULL;
}
static void * doHeurThread(void * voidInfo)
{
    typedef struct {
        double solutionValue;
        CbcModel * model;
        double * solution;
        int foundSol;
    } argBundle;
    argBundle * stuff = reinterpret_cast<argBundle *> (voidInfo);
    stuff->foundSol =
        stuff->model->heuristic(0)->solution(stuff->solutionValue,
                                             stuff->solution);
    return NULL;
}
static void * doCutsThread(void * voidInfo)
{
    CbcThread * stuff = reinterpret_cast<CbcThread *> (voidInfo);
    CbcModel * thisModel =  stuff->thisModel();
    while (true) {
        stuff->waitThread();
        //printf("start node %x\n",stuff->node);
        int mode = thisModel->getNumberThreads();
        if (mode) {
            // normal
            assert (stuff->returnCode() == 0);
            int fullScan = thisModel->getNodeCount() == 0 ? 1 : 0; //? was >0
            CbcCutGenerator * generator = thisModel->cutGenerator(stuff->dantzigState());
            generator->refreshModel(thisModel);
            OsiCuts * cuts = reinterpret_cast<OsiCuts *> (stuff->delNode());
            OsiSolverInterface * thisSolver = thisModel->solver();
            generator->generateCuts(*cuts, fullScan, thisSolver, NULL);
            stuff->setReturnCode( 1);
            stuff->unlockFromThread();
        } else {
            // exit
            break;
        }
    }
    stuff->exitThread();
    return NULL;
}
// Split up nodes - returns number of CbcNodeInfo's affected
int
CbcModel::splitModel(int numberModels, CbcModel ** model,
                     int numberNodes)
{
    int iModel;
    int i;
    for (iModel = 0; iModel < numberModels; iModel++) {
        CbcModel * otherModel = model[iModel];
        otherModel->moveToModel(this, 10);
        assert (!otherModel->tree()->size());
        otherModel->tree()->resetNodeNumbers();
        otherModel->bestPossibleObjective_ = bestPossibleObjective_;
        otherModel->sumChangeObjective1_ = sumChangeObjective1_;
        otherModel->sumChangeObjective2_ = sumChangeObjective2_;
        int numberColumns = solver_->getNumCols();
        if (otherModel->bestSolution_) {
            assert (bestSolution_);
            memcpy(otherModel->bestSolution_, bestSolution_, numberColumns*sizeof(double));
        } else if (bestSolution_) {
            otherModel->bestSolution_ = CoinCopyOfArray(bestSolution_, numberColumns);
        }
        otherModel->globalCuts_ = globalCuts_;
        otherModel->numberSolutions_ = numberSolutions_;
        otherModel->numberHeuristicSolutions_ = numberHeuristicSolutions_;
        otherModel->numberNodes_ = numberNodes_;
        otherModel->numberIterations_ = numberIterations_;
#ifdef JJF_ZERO
        if (maximumNumberCuts_ > otherModel->maximumNumberCuts_) {
            otherModel->maximumNumberCuts_ = maximumNumberCuts_;
            delete [] otherModel->addedCuts_;
            otherModel->addedCuts_ = new CbcCountRowCut * [maximumNumberCuts_];
        }
        if (maximumDepth_ > otherModel->maximumDepth_) {
            otherModel->maximumDepth_ = maximumDepth_;
            delete [] otherModel->walkback_;
            otherModel->walkback_ = new CbcNodeInfo * [maximumDepth_];
        }
#endif
        otherModel->currentNumberCuts_ = currentNumberCuts_;
        if (otherModel->usedInSolution_) {
            assert (usedInSolution_);
            memcpy(otherModel->usedInSolution_, usedInSolution_, numberColumns*sizeof(int));
        } else if (usedInSolution_) {
            otherModel->usedInSolution_ = CoinCopyOfArray(usedInSolution_, numberColumns);
        }
        /// ??? tree_;
        // Need flag (stopNumberIterations_>0?) which says don't update cut etc counts
        for (i = 0; i < numberObjects_; i++) {
            otherModel->object_[i]->updateBefore(object_[i]);
        }
        otherModel->maximumDepthActual_ = maximumDepthActual_;
        // Real cuts are in node info
        otherModel->numberOldActiveCuts_ = numberOldActiveCuts_;
        otherModel->numberNewCuts_ = numberNewCuts_;
        otherModel->numberStrongIterations_ = numberStrongIterations_;
    }
    double cutoff = getCutoff();
    int nAffected = 0;
    while (!tree_->empty()) {
        for (iModel = 0; iModel < numberModels; iModel++) {
            if (tree_->empty())
                break;
            CbcModel * otherModel = model[iModel];
            CbcNode * node = tree_->bestNode(cutoff) ;
            CbcNodeInfo * nodeInfo = node->nodeInfo();
            assert (nodeInfo);
            if (!nodeInfo->marked()) {
                //while (nodeInfo&&!nodeInfo->marked()) {
                if (nAffected == maximumDepth_) {
                    redoWalkBack();
                }
                nodeInfo->mark();
                //nodeInfo->incrementCuts(1000000);
                walkback_[nAffected++] = nodeInfo;
                //nodeInfo = nodeInfo->parent() ;
                //}
            }
            // Make node join otherModel
            OsiBranchingObject * bobj = node->modifiableBranchingObject();
            CbcBranchingObject * cbcobj = dynamic_cast<CbcBranchingObject *> (bobj);
            //assert (cbcobj);
            if (cbcobj) {
                CbcObject * object = cbcobj->object();
                assert (object);
                int position = object->position();
                assert (position >= 0);
                assert (object_[position] == object);
                CbcObject * objectNew =
                    dynamic_cast<CbcObject *> (otherModel->object_[position]);
                cbcobj->setOriginalObject(objectNew);
            }
            otherModel->tree_->push(node);
        }
        numberNodes--;
        if (!numberNodes)
            break;
    }
    return nAffected;
}
// Start threads
void
CbcModel::startSplitModel(int /*numberIterations*/)
{
    abort();
}
// Merge models
void
CbcModel::mergeModels(int /*numberModel*/, CbcModel ** /*model*/,
                      int /*numberNodes*/)
{
    abort();
}
/* Move/copy information from one model to another
   -1 - initial setup
   0 - from base model
   1 - to base model (and reset)
   2 - add in final statistics etc (and reset so can do clean destruction)
   10 - from base model (deterministic)
   11 - to base model (deterministic)
*/
void
CbcModel::moveToModel(CbcModel * baseModel, int mode)
{
#ifdef THREAD_DEBUG
    {
      CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
      if (stuff) 
	printf("mode %d node_ %p createdNode_ %p - stuff %p\n",
	       mode,stuff->node(),stuff->createdNode(),stuff);
      else
	printf("mode %d null stuff\n",mode);
    }
#endif
    if (mode == 0) {
        setCutoff(baseModel->getCutoff());
        bestObjective_ = baseModel->bestObjective_;
        //assert (!baseModel->globalCuts_.sizeRowCuts());
        if (numberSolutions_ < baseModel->numberSolutions_&& baseModel->bestSolution_) {
	  int numberColumns = solver_->getNumCols();
	  if (!bestSolution_)
	    bestSolution_ = new double [numberColumns];
	  memcpy(bestSolution_,baseModel->bestSolution_,
		 numberColumns*sizeof(double));
	  numberSolutions_ = baseModel->numberSolutions_;
	}
        stateOfSearch_ = baseModel->stateOfSearch_;
        numberNodes_ = baseModel->numberNodes_;
        numberIterations_ = baseModel->numberIterations_;
        numberFixedAtRoot_ = numberIterations_; // for statistics
        numberSolves_ = 0;
        phase_ = baseModel->phase_;
        assert (!nextRowCut_);
        nodeCompare_ = baseModel->nodeCompare_;
        tree_ = baseModel->tree_;
        assert (!subTreeModel_);
        //branchingMethod_ = NULL; // need something but what
        numberOldActiveCuts_ = baseModel->numberOldActiveCuts_;
        cutModifier_ = NULL;
        assert (!analyzeResults_);
        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
        assert (stuff);
        //if (stuff)
        stuff->setCreatedNode(NULL);
        // ?? searchStrategy_;
        searchStrategy_ = baseModel->searchStrategy_;
        stuff->saveStuff()[0] = searchStrategy_;
        stateOfSearch_ = baseModel->stateOfSearch_;
        stuff->saveStuff()[1] = stateOfSearch_;
        for (int iObject = 0 ; iObject < numberObjects_ ; iObject++) {
            CbcSimpleIntegerDynamicPseudoCost * dynamicObject =
                dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(object_[iObject]) ;
            if (dynamicObject) {
                CbcSimpleIntegerDynamicPseudoCost * baseObject =
                    dynamic_cast <CbcSimpleIntegerDynamicPseudoCost *>(baseModel->object_[iObject]) ;
                assert (baseObject);
                dynamicObject->copySome(baseObject);
            }
        }
	// add new global cuts
	CbcRowCuts * baseGlobal = baseModel->globalCuts();
	CbcRowCuts * thisGlobal = globalCuts();
	int baseNumberCuts = baseGlobal->sizeRowCuts();
	int thisNumberCuts = thisGlobal->sizeRowCuts();
	for (int i=thisNumberCuts;i<baseNumberCuts;i++) {
	  thisGlobal->addCutIfNotDuplicate(*baseGlobal->cut(i));
	}
	numberGlobalCutsIn_ = baseNumberCuts; 
    } else if (mode == 1) {
        lockThread();
        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
        assert (stuff);
        //stateOfSearch_
        if (stuff->saveStuff()[0] != searchStrategy_) {
#ifdef COIN_DEVELOP
            printf("changing searchStrategy from %d to %d\n",
                   baseModel->searchStrategy_, searchStrategy_);
#endif
            baseModel->searchStrategy_ = searchStrategy_;
        }
        if (stuff->saveStuff()[1] != stateOfSearch_) {
#ifdef COIN_DEVELOP
            printf("changing stateOfSearch from %d to %d\n",
                   baseModel->stateOfSearch_, stateOfSearch_);
#endif
            baseModel->stateOfSearch_ = stateOfSearch_;
        }
        if (numberUpdateItems_) {
            for (int i = 0; i < numberUpdateItems_; i++) {
                CbcObjectUpdateData * update = updateItems_ + i;
                int objectNumber = update->objectNumber_;
                CbcObject * object = dynamic_cast<CbcObject *> (baseModel->object_[objectNumber]);
                if (object)
                    object->updateInformation(*update);
            }
            numberUpdateItems_ = 0;
        }
        if (eventHappened_)
            baseModel->eventHappened_ = true;
        baseModel->numberNodes_++;
        baseModel->numberIterations_ +=
            numberIterations_ - numberFixedAtRoot_;
        baseModel->numberSolves_ += numberSolves_;
        if (stuff->node())
            baseModel->tree_->push(stuff->node());
        if (stuff->createdNode())
            baseModel->tree_->push(stuff->createdNode());
	// add new global cuts to base and take off
	CbcRowCuts * baseGlobal = baseModel->globalCuts();
	CbcRowCuts * thisGlobal = globalCuts();
	int thisNumberCuts = thisGlobal->sizeRowCuts();
	for (int i=thisNumberCuts-1;i>=numberGlobalCutsIn_;i--) {
	  baseGlobal->addCutIfNotDuplicate(*thisGlobal->cut(i),thisGlobal->cut(i)->whichRow());
	  thisGlobal->eraseRowCut(i);
	}
	//thisGlobal->truncate(numberGlobalCutsIn_);
	numberGlobalCutsIn_ = 999999; 
        unlockThread();
    } else if (mode == 2) {
        baseModel->sumChangeObjective1_ += sumChangeObjective1_;
        baseModel->sumChangeObjective2_ += sumChangeObjective2_;
        //baseModel->numberIterations_ += numberIterations_;
        for (int iGenerator = 0; iGenerator < numberCutGenerators_; iGenerator++) {
            CbcCutGenerator * generator = baseModel->generator_[iGenerator];
            CbcCutGenerator * generator2 = generator_[iGenerator];
            generator->incrementNumberTimesEntered(generator2->numberTimesEntered());
            generator->incrementNumberCutsInTotal(generator2->numberCutsInTotal());
            generator->incrementNumberCutsActive(generator2->numberCutsActive());
            generator->incrementTimeInCutGenerator(generator2->timeInCutGenerator());
        }
        if (parallelMode() >= 0)
            nodeCompare_ = NULL;
        baseModel->maximumDepthActual_ = CoinMax(baseModel->maximumDepthActual_, maximumDepthActual_);
        baseModel->numberDJFixed_ += numberDJFixed_;
        baseModel->numberStrongIterations_ += numberStrongIterations_;
        int i;
        for (i = 0; i < 3; i++)
            baseModel->strongInfo_[i] += strongInfo_[i];
        if (parallelMode() >= 0) {
            walkback_ = NULL;
            lastNodeInfo_ = NULL;
            lastNumberCuts_ = NULL;
            lastCut_ = NULL;
            //addedCuts_ = NULL;
            tree_ = NULL;
        }
	if ((moreSpecialOptions2_&32)!=0)
	  delete eventHandler_;
        eventHandler_ = NULL;
        delete solverCharacteristics_;
        solverCharacteristics_ = NULL;
        bool newMethod = (baseModel->branchingMethod_ && baseModel->branchingMethod_->chooseMethod());
        if (newMethod) {
            // new method - we were using base models
            numberObjects_ = 0;
            object_ = NULL;
        }
    } else if (mode == -1) {
        delete eventHandler_;
	if ((moreSpecialOptions2_&32)==0||!baseModel->eventHandler_) {
	  eventHandler_ = baseModel->eventHandler_;
	} else {
	  eventHandler_ = baseModel->eventHandler_->clone();
	  eventHandler_->setModel(this);
	}
        assert (!statistics_);
        assert(baseModel->solverCharacteristics_);
        solverCharacteristics_ = new OsiBabSolver (*baseModel->solverCharacteristics_);
        solverCharacteristics_->setSolver(solver_);
        setMaximumNodes(COIN_INT_MAX);
        if (parallelMode() >= 0) {
            delete [] walkback_;
            //delete [] addedCuts_;
            walkback_ = NULL;
            //addedCuts_ = NULL;
            delete [] lastNodeInfo_ ;
            lastNodeInfo_ = NULL;
            delete [] lastNumberCuts_ ;
            lastNumberCuts_ = NULL;
            delete [] lastCut_ ;
            lastCut_ = NULL;
            delete tree_;
            tree_ = NULL;
            delete nodeCompare_;
            nodeCompare_ = NULL;
        } else {
            delete tree_;
            tree_ = new CbcTree();
            tree_->setComparison(*nodeCompare_) ;
        }
	delete continuousSolver_;
        continuousSolver_ = baseModel->continuousSolver_->clone();
	// make sure solvers have correct message handler
	solver_->passInMessageHandler(handler_);
	continuousSolver_->passInMessageHandler(handler_);
        bool newMethod = (baseModel->branchingMethod_ && baseModel->branchingMethod_->chooseMethod());
        if (newMethod) {
            // new method uses solver - but point to base model
            // We may update an object in wrong order - shouldn't matter?
            numberObjects_ = baseModel->numberObjects_;
            if (parallelMode() >= 0) {
                object_ = baseModel->object_;
            } else {
                printf("*****WARNING - fix testosi option\n");
                object_ = baseModel->object_;
            }
        }
        int i;
        for (i = 0; i < numberHeuristics_; i++) {
            delete heuristic_[i];
            heuristic_[i] = baseModel->heuristic_[i]->clone();
            heuristic_[i]->setModelOnly(this);
        }
        for (i = 0; i < numberCutGenerators_; i++) {
            delete generator_[i];
            generator_[i] = new CbcCutGenerator(*baseModel->generator_[i]);
            // refreshModel was overkill as thought too many rows
	    if (generator_[i]->needsRefresh())
	      generator_[i]->refreshModel(this);
	    else
	      generator_[i]->setModel(this);
        }
    } else if (mode == 10) {
        setCutoff(baseModel->getCutoff());
        bestObjective_ = baseModel->bestObjective_;
        //assert (!baseModel->globalCuts_.sizeRowCuts());
        numberSolutions_ = baseModel->numberSolutions_;
        assert (usedInSolution_);
        assert (baseModel->usedInSolution_);
        memcpy(usedInSolution_, baseModel->usedInSolution_, solver_->getNumCols()*sizeof(int));
        stateOfSearch_ = baseModel->stateOfSearch_;
        //numberNodes_ = baseModel->numberNodes_;
        //numberIterations_ = baseModel->numberIterations_;
        //numberFixedAtRoot_ = numberIterations_; // for statistics
        phase_ = baseModel->phase_;
        assert (!nextRowCut_);
        delete nodeCompare_;
        nodeCompare_ = baseModel->nodeCompare_->clone();
        tree_->setComparison(*nodeCompare_) ;
        assert (!subTreeModel_);
        //branchingMethod_ = NULL; // need something but what
        numberOldActiveCuts_ = baseModel->numberOldActiveCuts_;
        cutModifier_ = NULL;
        assert (!analyzeResults_);
        CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
        assert (stuff);
        //if (stuff)
        stuff->setCreatedNode(NULL);
        // ?? searchStrategy_;
        searchStrategy_ = baseModel->searchStrategy_;
        stuff->saveStuff()[0] = searchStrategy_;
        stateOfSearch_ = baseModel->stateOfSearch_;
        stuff->saveStuff()[1] = stateOfSearch_;
        OsiObject ** baseObject = baseModel->object_;
        for (int iObject = 0 ; iObject < numberObjects_ ; iObject++) {
            object_[iObject]->updateBefore(baseObject[iObject]);
        }
        //delete [] stuff->nodeCount;
        //stuff->nodeCount = new int [baseModel->maximumDepth_+1];
    } else if (mode == 11) {
        if (parallelMode() < 0) {
            // from deterministic
            CbcThread * stuff = reinterpret_cast<CbcThread *> (masterThread_);
            assert (stuff);
            // Move solution etc
            // might as well mark all including continuous
            int numberColumns = solver_->getNumCols();
            for (int i = 0; i < numberColumns; i++) {
                baseModel->usedInSolution_[i] += usedInSolution_[i];
                //usedInSolution_[i]=0;
            }
            baseModel->numberSolutions_ += numberSolutions_;
            if (bestObjective_ < baseModel->bestObjective_ && bestObjective_ < baseModel->getCutoff()) {
                baseModel->bestObjective_ = bestObjective_ ;
                int numberColumns = solver_->getNumCols();
                if (!baseModel->bestSolution_)
                    baseModel->bestSolution_ = new double[numberColumns];
                CoinCopyN(bestSolution_, numberColumns, baseModel->bestSolution_);
                baseModel->setCutoff(getCutoff());
                baseModel->handler_->message(CBC_ROUNDING, messages_)
                << bestObjective_
                << "heuristic"
                << baseModel->numberIterations_
                << baseModel->numberNodes_ << getCurrentSeconds()
                << CoinMessageEol;
            }
            //stateOfSearch_
            if (stuff->saveStuff()[0] != searchStrategy_) {
#ifdef COIN_DEVELOP
                printf("changing searchStrategy from %d to %d\n",
                       baseModel->searchStrategy_, searchStrategy_);
#endif
                baseModel->searchStrategy_ = searchStrategy_;
            }
            if (stuff->saveStuff()[1] != stateOfSearch_) {
#ifdef COIN_DEVELOP
                printf("changing stateOfSearch from %d to %d\n",
                       baseModel->stateOfSearch_, stateOfSearch_);
#endif
                baseModel->stateOfSearch_ = stateOfSearch_;
            }
            int i;
            if (eventHappened_)
                baseModel->eventHappened_ = true;
            baseModel->numberNodes_ += stuff->nodesThisTime();
            baseModel->numberIterations_ += stuff->iterationsThisTime();
            double cutoff = baseModel->getCutoff();
            while (!tree_->empty()) {
                CbcNode * node = tree_->bestNode(COIN_DBL_MAX) ;
                if (node->objectiveValue() < cutoff) {
                    assert(node->nodeInfo());
                    // Make node join correctly
                    OsiBranchingObject * bobj = node->modifiableBranchingObject();
                    CbcBranchingObject * cbcobj = dynamic_cast<CbcBranchingObject *> (bobj);
                    if (cbcobj) {
                        CbcObject * object = cbcobj->object();
                        assert (object);
                        int position = object->position();
                        assert (position >= 0);
                        assert (object_[position] == object);
                        CbcObject * objectNew =
                            dynamic_cast<CbcObject *> (baseModel->object_[position]);
                        cbcobj->setOriginalObject(objectNew);
                    }
                    baseModel->tree_->push(node);
                } else {
                    delete node;
                }
            }
            for (i = 0; i < stuff->nDeleteNode(); i++) {
                //printf("CbcNode %x stuff delete\n",stuff->delNode[i]);
                delete stuff->delNode()[i];
            }
        }
    } else {
        abort();
    }
}
// Generate one round of cuts - parallel mode
int
CbcModel::parallelCuts(CbcBaseModel * master, OsiCuts & theseCuts,
                       CbcNode * /*node*/, OsiCuts & slackCuts, int lastNumberCuts)
{
    /*
      Is it time to scan the cuts in order to remove redundant cuts? If so, set
      up to do it.
    */
    int fullScan = 0 ;
    if ((numberNodes_ % SCANCUTS) == 0 || (specialOptions_&256) != 0) {
        fullScan = 1 ;
        if (!numberNodes_ || (specialOptions_&256) != 0)
            fullScan = 2;
        specialOptions_ &= ~256; // mark as full scan done
    }
    // do cuts independently
    OsiCuts * eachCuts = new OsiCuts [numberCutGenerators_];;
    int i;
    assert (master);
    for (i = 0; i < numberThreads_; i++) {
        // set solver here after cloning
        master->model(i)->solver_ = solver_->clone();
        master->model(i)->numberNodes_ = (fullScan) ? 1 : 0;
    }
    // generate cuts
    int status = 0;
    const OsiRowCutDebugger * debugger = NULL;
    bool onOptimalPath = false;
    for (i = 0; i < numberCutGenerators_; i++) {
        bool generate = generator_[i]->normal();
        // skip if not optimal and should be (maybe a cut generator has fixed variables)
        if (generator_[i]->needsOptimalBasis() && !solver_->basisIsAvailable())
            generate = false;
        if (generator_[i]->switchedOff())
            generate = false;;
        if (generate) {
            master->waitForThreadsInCuts(0, eachCuts + i, i);
        }
    }
    // wait
    master->waitForThreadsInCuts(1, eachCuts, 0);
    // Now put together
    for (i = 0; i < numberCutGenerators_; i++) {
        // add column cuts
        int numberColumnCutsBefore = theseCuts.sizeColCuts() ;
        int numberColumnCuts = eachCuts[i].sizeColCuts();
        int numberColumnCutsAfter = numberColumnCutsBefore
                                    + numberColumnCuts;
        int j;
        for (j = 0; j < numberColumnCuts; j++) {
            theseCuts.insert(eachCuts[i].colCut(j));
        }
        int numberRowCutsBefore = theseCuts.sizeRowCuts() ;
        int numberRowCuts = eachCuts[i].sizeRowCuts();
        // insert good cuts
        if (numberRowCuts) {
            int n = numberRowCuts;
            numberRowCuts = 0;
            for (j = 0; j < n; j++) {
                const OsiRowCut * thisCut = eachCuts[i].rowCutPtr(j) ;
                if (thisCut->lb() <= 1.0e10 && thisCut->ub() >= -1.0e10) {
                    theseCuts.insert(eachCuts[i].rowCut(j));
                    numberRowCuts++;
                }
            }
            if (generator_[i]->mustCallAgain() && status >= 0)
                status = 1; // say must go round
        }
        int numberRowCutsAfter = numberRowCutsBefore
                                 + numberRowCuts;
        if (numberRowCuts) {
            // Check last cut to see if infeasible
            const OsiRowCut * thisCut = theseCuts.rowCutPtr(numberRowCutsAfter - 1) ;
            if (thisCut->lb() > thisCut->ub()) {
                status = -1; // sub-problem is infeasible
                break;
            }
        }
#ifdef CBC_DEBUG
        {
            int k ;
            for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
                OsiRowCut thisCut = theseCuts.rowCut(k) ;
                /* check size of elements.
                   We can allow smaller but this helps debug generators as it
                   is unsafe to have small elements */
                int n = thisCut.row().getNumElements();
                const int * column = thisCut.row().getIndices();
                const double * element = thisCut.row().getElements();
                //assert (n);
                for (int i = 0; i < n; i++) {
                    double value = element[i];
                    assert(fabs(value) > 1.0e-12 && fabs(value) < 1.0e20);
                }
            }
        }
#endif
        if ((specialOptions_&1) != 0) {
            if (onOptimalPath) {
                int k ;
                for (k = numberRowCutsBefore; k < numberRowCutsAfter; k++) {
                    OsiRowCut thisCut = theseCuts.rowCut(k) ;
                    if (debugger->invalidCut(thisCut)) {
                        solver_->getRowCutDebuggerAlways()->printOptimalSolution(*solver_);
                        solver_->writeMpsNative("badCut.mps", NULL, NULL, 2);
#ifdef NDEBUG
                        printf("Cut generator %d (%s) produced invalid cut (%dth in this go)\n",
                               i, generator_[i]->cutGeneratorName(), k - numberRowCutsBefore);
                        const double *lower = getColLower() ;
                        const double *upper = getColUpper() ;
                        int numberColumns = solver_->getNumCols();
                        for (int i = 0; i < numberColumns; i++)
                            printf("%d bounds %g,%g\n", i, lower[i], upper[i]);
                        abort();
#endif
                    }
                    assert(!debugger->invalidCut(thisCut)) ;
                }
            }
        }
        /*
          The cut generator has done its thing, and maybe it generated some
          cuts.  Do a bit of bookkeeping: load
          whichGenerator[i] with the index of the generator responsible for a cut,
          and place cuts flagged as global in the global cut pool for the model.

          lastNumberCuts is the sum of cuts added in previous iterations; it's the
          offset to the proper starting position in whichGenerator.
        */
        int numberBefore =
            numberRowCutsBefore + numberColumnCutsBefore + lastNumberCuts ;
        int numberAfter =
            numberRowCutsAfter + numberColumnCutsAfter + lastNumberCuts ;
        // possibly extend whichGenerator
        resizeWhichGenerator(numberBefore, numberAfter);

        for (j = numberRowCutsBefore; j < numberRowCutsAfter; j++) {
            whichGenerator_[numberBefore++] = i  ;
            const OsiRowCut * thisCut = theseCuts.rowCutPtr(j) ;
            if (thisCut->lb() > thisCut->ub())
                status = -1; // sub-problem is infeasible
            if (thisCut->globallyValid()) {
                // add to global list
                OsiRowCut newCut(*thisCut);
                newCut.setGloballyValid(true);
                newCut.mutableRow().setTestForDuplicateIndex(false);
                globalCuts_.addCutIfNotDuplicate(newCut) ;
            }
        }
        for (j = numberColumnCutsBefore; j < numberColumnCutsAfter; j++) {
            //whichGenerator_[numberBefore++] = i ;
            const OsiColCut * thisCut = theseCuts.colCutPtr(j) ;
            if (thisCut->globallyValid()) {
                // add to global list
                makeGlobalCut(thisCut);
            }
        }
    }
    // Add in any violated saved cuts
    if (!theseCuts.sizeRowCuts() && !theseCuts.sizeColCuts()) {
        int numberOld = theseCuts.sizeRowCuts() + lastNumberCuts;
        int numberCuts = slackCuts.sizeRowCuts() ;
        int i;
        // possibly extend whichGenerator
        resizeWhichGenerator(numberOld, numberOld + numberCuts);
        double primalTolerance;
        solver_->getDblParam(OsiPrimalTolerance, primalTolerance) ;
        for ( i = 0; i < numberCuts; i++) {
            const OsiRowCut * thisCut = slackCuts.rowCutPtr(i) ;
            if (thisCut->violated(cbcColSolution_) > 100.0*primalTolerance) {
                if (messageHandler()->logLevel() > 2)
                    printf("Old cut added - violation %g\n",
                           thisCut->violated(cbcColSolution_)) ;
                whichGenerator_[numberOld++] = 999;
                theseCuts.insert(*thisCut) ;
            }
        }
    }
    delete [] eachCuts;
    return status;
}
/*
  Locks a thread if parallel so that stuff like cut pool
  can be updated and/or used.
*/
void
CbcModel::lockThread()
{
    if (masterThread_ && (threadMode_&1) == 0)
        masterThread_->lockThread();
}
/*
  Unlocks a thread if parallel
*/
void
CbcModel::unlockThread()
{
    if (masterThread_ && (threadMode_&1) == 0)
        masterThread_->unlockThread();
}
// Returns true if locked
bool
CbcModel::isLocked() const
{
    if (masterThread_) {
        return (masterThread_->locked());
    } else {
        return true;
    }
}
// Stop a child
void
CbcModel::setInfoInChild(int type, CbcThread * info)
{
    if (type == -3) {
        // set up
        masterThread_ = info;
    } else if (type == -2) {
        numberThreads_ = 0; // signal to stop
    } else {
        // make sure message handler will be deleted
        defaultHandler_ = true;
        ownObjects_ = false;
        delete solverCharacteristics_;
        solverCharacteristics_ = NULL;
        if (type >= 0) {
            delete [] object_; // may be able to when all over to CbcThread
            for (int i = 0; i < numberCutGenerators_; i++) {
                delete generator_[i];
                generator_[i] = NULL;
                //delete virginGenerator_[i];
                //virginGenerator_[i]=NULL;
            }
            //generator_[0] = NULL;
            //delete [] generator_;
            //generator_ = NULL;
            numberCutGenerators_ = 0;
        } else {
            for (int i = 0; i < numberCutGenerators_; i++) {
                generator_[i] = NULL;
            }
        }
        object_ = NULL;
    }
}

/// Indicates whether Cbc library has been compiled with multithreading support
bool CbcModel::haveMultiThreadSupport() { return true; }

#else
// Default constructor
CbcBaseModel::CbcBaseModel() {}

bool CbcModel::haveMultiThreadSupport() { return false; }
#endif

