Ejemplo n.º 1
0
void Transport::closeComponents() {
    collectNewComponets();
    list<IOComponent*>::iterator iter = _checkingList.begin();
    while ( iter != _checkingList.end() ) {
        IOComponent *ioc = *iter;
        ANET_LOG(DEBUG,"IOC(%p)->subRef(), [%d]", ioc, ioc->getRef());
        ioc->close();
        ioc->subRef();
        iter = _checkingList.erase(iter);
    }

    IOComponent *list, *ioc;
    list = _iocListHead;
    while (list) {
        ioc = list; 
        ANET_LOG(DEBUG,"IOC(%p)->subRef(), [%d]", ioc, ioc->getRef());
        list = list->_next;
        ioc->close();
        ioc->subRef();
    }
    _iocListHead = _iocListTail = NULL;

    //SHOULD clear commands at last!
    vector<TransportCommand>::iterator i = _commands.begin();
    while (i != _commands.end()) {
        ANET_LOG(DEBUG,"IOC(%p)->subRef(), [%d]", i->ioc, i->ioc->getRef());
        i->ioc->subRef();
        i++;
    }
    _commands.clear();
}
Ejemplo n.º 2
0
bool BeckhoffdProperty::run(std::vector<Value> &params) {
    //if (params.size() == 4) {
	IOComponent *m = IOComponent::lookup_device(params[1].asString());
    if (m) {
        if (params.size() == 3) {
            long x;
            char *p;
            x = strtol(params[2].asString().c_str(), &p, 0);
            if (*p == 0)
                m->setValue(x);
            else {
                result_str = "Require integer parameter";
                return false;
			}
        }
        else {
            result_str = "usage: PROPERTY name value";
            return false;
		}

        result_str = "OK";
        return true;
    }
    else {
        result_str = "Unknown device";
        return false;
    }
}
Ejemplo n.º 3
0
void IOComponent::setupIOMap() {
	boost::recursive_mutex::scoped_lock lock(processing_queue_mutex);
	max_offset = 0;
	min_offset = 1000000L;
	io_map.clear();

	if (indexed_components) delete indexed_components;
	std::cout << "\n\n setupIOMap\n";
	// find the highest and lowest offset location within the process data
	std::list<IOComponent *>::iterator iter = processing_queue.begin();
	while (iter != processing_queue.end()) {
		IOComponent *ioc = *iter++;
		std::cout << ioc->getName() << " " << ioc->address << "\n";
		unsigned int offset = ioc->address.io_offset;
		unsigned int bitpos = ioc->address.io_bitpos;
		offset += bitpos/8;
		//bitpos = bitpos % 8;
		if (ioc->address.bitlen>=8) offset += ioc->address.bitlen/8 - 1;
		if (offset > max_offset) max_offset = offset;
		assert(max_offset < 10000);
		if (offset < min_offset) min_offset = offset;
	}
	if (min_offset > max_offset) min_offset = max_offset;
	std::cout << "min io offset: " << min_offset << "\n";
	std::cout << "max io offset: " << max_offset << "\n";
	std::cout << ( (max_offset+1)*sizeof(IOComponent*)) << " bytes reserved for index io\n";

	indexed_components = new std::vector<IOComponent*>( (max_offset+1) *8);

	if (io_process_data) delete[] io_process_data;
	process_data_size = max_offset+1;
	io_process_data = new uint8_t[process_data_size];
	memset(io_process_data, 0, process_data_size);

	io_map.resize(max_offset+1);
	for (unsigned int i=0; i<=max_offset; ++i) io_map[i] = 0;
	iter = processing_queue.begin();
	while (iter != processing_queue.end()) {
		IOComponent *ioc = *iter++;
		if (ioc->io_name == "") continue;
		unsigned int offset = ioc->address.io_offset;
		unsigned int bitpos = ioc->address.io_bitpos;
		offset += bitpos/8;
		int bytes = 1;
		for (unsigned int i=0; i<ioc->address.bitlen; ++i) 
			(*indexed_components)[offset*8 + bitpos + i] = ioc;
		for (int i=0; i<bytes; ++i) {
			std::list<IOComponent *> *cl = io_map[offset+i];
			if (!cl) cl = new std::list<IOComponent *>();
			cl->push_back(ioc);
			io_map[offset+i] = cl;
			std::cout << "offset: " << (offset+i) << " io name: " << ioc->io_name << "\n";
		}
	}
	std::cout << "\n\n\n";
	io_process_mask = generateProcessMask(io_process_mask, process_data_size);
}
Ejemplo n.º 4
0
void handle_io_sampling(uint64_t io_clock) {
	uint64_t now = microsecs();
	if (now - last_sample < 10000) return;
	last_sample = now;
	std::set <IOComponent*>::iterator iter = regular_polls.begin();
	while (iter != regular_polls.end() ) {
		IOComponent *ioc = *iter++;
		ioc->read_time = io_clock;
		ioc->filter(ioc->address.value);
	}
}
/**
 * 主动断开
 */
bool Transport::disconnect(Connection *conn) {
    IOComponent *ioc = NULL;
    if (conn == NULL || (ioc = conn->getIOComponent()) == NULL) {
        return false;
    }
    ioc->setAutoReconn(false);
    ioc->subRef();
    if (ioc->_socket) {
        ioc->_socket->shutdown();
    }
    return true;
}
Ejemplo n.º 6
0
void Transport::timeoutIteration(int64_t now) {
    collectNewComponets();
    list<IOComponent*>::iterator iter = _checkingList.begin();
    while ( iter != _checkingList.end() ) {
        IOComponent *ioc = *iter;
        if (ioc->checkTimeout(now)) {
            iter ++;
        } else {
            ioc->subRef();
            iter = _checkingList.erase(iter);
        }
    }
    _nextCheckTime = now + 100000;
}
Ejemplo n.º 7
0
bool ChatServer::start(const char *host, int thread)
{
	IOComponent *ioc = this->listen(host, triones::TPROTOCOL_TEXT);
	if (ioc == NULL)
	{
		printf("listen error \n");
		return false;
	}
	_tp = ioc->get_trans_proto();
	_id_user.set_trans_proto(_tp);

	init(thread);
	return true;
}
Ejemplo n.º 8
0
// 处理用户发送消息
void ChatServer::handle_user_send_msg(IOComponent* ioc, SendMsg *sendmsg, Response* resp)
{
	std::string name = ioc->get_userid();
	if (name.empty())
	{
		resp->_result = sendmsg->_from_name + " has not logined in";
		return;
	}

	std::string xml = ChatXml::build_receive_xml(sendmsg->_msg, sendmsg->_from_name);

	std::list<std::string>& tousers = sendmsg->_to_list;
	std::list<std::string>::iterator it;
	for (it = tousers.begin(); it != tousers.end(); ++it)
	{
		size_t index = _id_user.get_hash_index(*it);

		BaseUser* user = NULL;
		IOComponent* ioc = NULL;

		bool send_succ = false;
		UNUSED(send_succ);

		_id_user.ct_read_lock(index);
		user = _id_user.get_user(index, *it);
		if (user)
		{
			ioc = user->get_ioc();
			if (ioc)
			{
				Packet* pack = new Packet();
				pack->writeBytes(xml.c_str(), xml.length());
				if (!ioc->post_packet(pack))
				{
					//printf("+++++++++++send to %s %s\n", it->c_str(), (send_succ ? "succ" : "false"));
					delete pack;
				}
				else
				{
					send_succ = true;
				}
			}
		}
		_id_user.ct_read_unlock(index);

		//printf(">>>>>>>>>>>send to %s %s\n", it->c_str(), (send_succ ? "succ" : "false"));
	}

	resp->_result = "succ";
}
Ejemplo n.º 9
0
void EchoServer::start() {
    DefaultPacketFactory factory;
    DefaultPacketStreamer streamer(&factory);
    
    IOComponent *ioc = _transport.listen(_spec.c_str(), &streamer, this);
    if (ioc == NULL) {
        ANET_LOG(ERROR, "listen error.");
        return;
    }
    ANET_LOG(INFO, "EchoServer(%s) started.", _spec.c_str());
    _transport.run();
    ANET_LOG(INFO, "EchoServer(%s) Quiting...", _spec.c_str());
    ANET_GLOBAL_STAT.log();
    ioc->close();
    ioc->subRef();
}
Ejemplo n.º 10
0
  void TCPCONNECTIONTF::testReadMaliciousDataInfinitLoop() {
    ANET_LOG(DEBUG, "Begin testReadMaliciousDataInfinitLoop");
    int64_t now = TimeUtil::getTime();
    Transport tranClient;
    Transport tranServer;
    const char sepc[] = "tcp:localhost:12346";
    ConnPacketFactory factory;
    DefaultPacketStreamer defaultStreamer(&factory);
    DefaultPacketHandler defaultHandler;
    TCPServerAdapter adapter;
    MaliciousStreamer maliciousStreamer(&factory);

    
    IOComponent *listener = 
      tranServer.listen(sepc, &defaultStreamer, &adapter);
    CPPUNIT_ASSERT(listener);
    ANET_LOG(SPAM,"After tranServer->listen()");
    tranServer.eventIteration(now);
    ANET_LOG(SPAM,"After tranServer->eventIteration(now)");

    //create a connection
    Connection *conn = tranClient.connect(sepc, &maliciousStreamer);
    ANET_LOG(SPAM,"After tranClient->connect(spec, _streamer, false)");
    CPPUNIT_ASSERT(conn);
    tranClient.eventIteration(now);
    ANET_LOG(SPAM,"After tranClient->eventIteration(now)");

    //accept the connection
    tranServer.eventIteration(now);
    ANET_LOG(SPAM,"After tranServer->eventIteration(now)");

    conn->postPacket(new ConnPacket(11), &defaultHandler, NULL);
    maliciousStreamer._maliciousLen = 0x80000000 + 10;
    ANET_LOG(DEBUG,"before conn->writeData()");
    conn->writeData();
    ANET_LOG(DEBUG,"before connAcc->readData()");
    tranServer.eventIteration(now);
    ANET_LOG(DEBUG,"after connAcc->readData()");
    tranClient.eventIteration(now);
    CPPUNIT_ASSERT(conn->isClosed());
    ANET_LOG(DEBUG,"after tranClient.eventIteration(now)");
    conn->subRef();
    listener->subRef();
    ANET_LOG(DEBUG, "End testReadMaliciousDataInfinitLoop");
  }
Ejemplo n.º 11
0
  /**
   * test Server and Client memory leak
   * test whether packets are deleted when connection closed
   */
  void TCPCONNECTIONTF::testMemLeak() {
    char spec[] = "tcp:localhost:13147";
    int64_t now = TimeUtil::getTime();
    Transport *tranServer = new Transport;
    Transport *tranClient = new Transport;

    ConnServerAdapter *adapter = new ConnServerAdapter;

    //add listener to tranServer
    IOComponent *listener = tranServer->listen(spec, _streamer, adapter);
    CPPUNIT_ASSERT(listener);
    tranServer->eventIteration(now);
    
    //create a connection
    Connection *conn = tranClient->connect(spec, _streamer, false);
    CPPUNIT_ASSERT(conn);
    tranClient->eventIteration(now);

    //accept the connection
    tranServer->eventIteration(now);

    // client send two packets

    _conn->postPacket(new ConnPacket, _handler, NULL, true);    
    _conn->postPacket(new ConnPacket, _handler, NULL, true);
    tranClient->eventIteration(now);

    //server accept two packets
    tranServer->eventIteration(now);
    IOComponent *ioc = tranServer->_iocListTail;
    Connection *tmpConn = ((TCPComponent *)ioc)->_connection;
    //client close the connection
    _conn->close();
    tranClient->eventIteration(now);
    
    tranServer->eventIteration(now);
    CPPUNIT_ASSERT_EQUAL((size_t)0, tmpConn->_outputQueue.size());

    delete adapter;
    delete tranClient;
    delete tranServer;
    listener->subRef();
    conn->subRef();
  }
Ejemplo n.º 12
0
void Transport::eventLoop(SocketEvent *socketEvent) {
IOEvent events[MAX_SOCKET_EVENTS];

while (!_stop) {
// 检查是否有事件发生
int cnt = socketEvent->getEvents(1000, events, MAX_SOCKET_EVENTS);
if (cnt < 0) {
if(errno == EINTR)continue;
SYS_LOG(INFO, "得到events出错了: %s(%d)\n", strerror(errno), errno);
}

for (int i = 0; i < cnt; i++) {
IOComponent *ioc = events[i]._ioc;
if (ioc == NULL) {
continue;
}
if (events[i]._errorOccurred) { // 错误发生了
removeComponent(ioc);
continue;
}

ioc->addRef();
// 读写
bool rc = true;
if (events[i]._readOccurred) {
rc = ioc->handleReadEvent();
}
if (rc && events[i]._writeOccurred) {
rc = ioc->handleWriteEvent();
}
ioc->subRef();

if (!rc) {
removeComponent(ioc);
}
}
}
}
Ejemplo n.º 13
0
void Transport::eventIteration( int64_t &now) {
    IOEvent events[MAX_SOCKET_EVENTS];
    int cnt = _socketEvent.getEvents(100, events, MAX_SOCKET_EVENTS);
    now = TimeUtil::getTime();
    for (int i = 0; i < cnt; i++) {
        IOComponent *ioc = events[i]._ioc;
        assert(ioc);
        bool rc = true;
        if (events[i]._errorOccurred) { // 错误发生了
            rc = ioc->handleErrorEvent();
        }

        // 读写
        if (rc && events[i]._readOccurred) {
            rc = ioc->handleReadEvent();
        }
        if (rc && events[i]._writeOccurred) {
            rc = ioc->handleWriteEvent();
        }
        ioc->updateUseTime(now);
    }
    processCommands();
}
Ejemplo n.º 14
0
static uint8_t *generateUpdateMask() {
	//  returns null if there are no updates, otherwise returns
	// a mask for the update data

	//std::cout << "generating mask\n";
	if (updatedComponentsOut.empty()) return 0;

	unsigned int min = IOComponent::getMinIOOffset();
	unsigned int max = IOComponent::getMaxIOOffset();
	uint8_t *res = new uint8_t[max+1];
	memset(res, 0, max+1);
	//std::cout << "mask is " << (max+1) << " bytes\n";

	std::set<IOComponent*>::iterator iter = updatedComponentsOut.begin();
	while (iter != updatedComponentsOut.end()) {
		IOComponent *ioc = *iter; //TBD this can be null
		if (ioc->ownersEnabled()) iter++; else iter = updatedComponentsOut.erase(iter);

		if (ioc->direction() != IOComponent::DirOutput && ioc->direction() != IOComponent::DirBidirectional) 
			continue;
		unsigned int offset = ioc->address.io_offset;
		unsigned int bitpos = ioc->address.io_bitpos;
		offset += bitpos/8;
		bitpos = bitpos % 8;
		uint8_t mask = 0x01 << bitpos;
		// set  a bit in the mask for each bit of this value
		for (unsigned int i=0; i<ioc->address.bitlen; ++i) {
			res[offset] |= mask;
			mask = mask << 1;
			if (!mask) {mask = 0x01; ++offset; }
		}
	}
#if VERBOSE_DEBUG
	std::cout << "generated mask: "; display(res, max-min+1); std::cout << "\n";
#endif
	return res;
}
Ejemplo n.º 15
0
  void TCPCONNECTIONTF::testClose()
  {
    TCPServerAdapter adapter;
    Transport *tranServer = new Transport;
    char spec[] = "tcp:localhost:13345";

    tranServer->start();
    IOComponent *listener = tranServer->listen(spec, _streamer, &adapter);
    CPPUNIT_ASSERT(listener);

    
    //start client
    Transport *tranClient = new Transport;
    tranClient->start();
    Connection *conn = tranClient->connect(spec, _streamer, false);
    CPPUNIT_ASSERT(conn);
    CPPUNIT_ASSERT(_conn->postPacket(new ConnPacket(31), _handler, NULL));
    
    // the close() has not implement
    ANET_LOG(SPAM,"Before Calling _conn->close();");
    _conn->close();
    ANET_LOG(SPAM,"After Calling _conn->close();");
    CPPUNIT_ASSERT(_conn->isClosed());
    ANET_LOG(SPAM,"After Assert(_conn->isClosed();");
    tranClient->stop();
    ANET_LOG(SPAM,"After Calling tranClient->stop();");
    tranClient->wait();
    ANET_LOG(SPAM,"After Calling tranClient->wait();");
    tranServer->stop();
    ANET_LOG(SPAM,"After Calling tran_server->stop();");
    tranServer->wait();
    ANET_LOG(SPAM,"After Calling tranClient->wait();");
    delete tranClient;
    delete tranServer;
    listener->subRef();
    conn->subRef();
  }
Ejemplo n.º 16
0
    bool BeckhoffdListJSON::run(std::vector<Value> &params) {
        cJSON *root = cJSON_CreateArray();
        std::map<std::string, IOComponent*>::const_iterator iter = IOComponent::devices.begin();
        while (iter != IOComponent::devices.end()) {
			std::string name_str = (*iter).first;
            IOComponent *ioc = (*iter++).second;
			if (name_str == "!") continue; //TBD
			cJSON *node = cJSON_CreateObject();
    		cJSON_AddStringToObject(node, "name", name_str.c_str());
			cJSON_AddStringToObject(node, "class", ioc->type());
			cJSON_AddNumberToObject(node, "value", ioc->value());
			cJSON_AddNumberToObject(node, "module", ioc->address.module_position);
			ECModule *mod = ECInterface::findModule(ioc->address.module_position);
			if (mod) {
				cJSON_AddStringToObject(node, "module_name", mod->name.c_str());
			}
			if (strcmp(ioc->type(), "Output") == 0)
    				cJSON_AddStringToObject(node, "tab", "Outputs");
			else if (strcmp(ioc->type(), "AnalogueOutput") == 0)
    				cJSON_AddStringToObject(node, "tab", "Ana.Out");
			else if (strcmp(ioc->type(), "AnalogueInput") == 0)
    				cJSON_AddStringToObject(node, "tab", "Ana.In");
			else
    				cJSON_AddStringToObject(node, "tab", "Inputs");

			cJSON_AddStringToObject(node, "state", ioc->getStateString());
//			if (ioc->isOn())
//    			cJSON_AddStringToObject(node, "state", "on");
//			else if (ioc->isOff())
//    			cJSON_AddStringToObject(node, "state", "off");
//			else
//    			cJSON_AddStringToObject(node, "state", "unknown");
		cJSON_AddTrueToObject(node, "enabled");

   		    cJSON_AddItemToArray(root, node);
        }
        char *res = cJSON_Print(root);
        cJSON_Delete(root);
        bool done;
		char *p = res; while (*p) { *p &= 0x7f; ++p; }
        if (res) {
            result_str = res;
            free(res);
            done = true;
        }
        else {
            error_str = "JSON error";
            done = false;
        }
        return done;
    }
/*
 * 超时检查, 被run函数调用
 */
void Transport::timeoutLoop() {
    IOComponent *mydelHead = NULL;
    IOComponent *mydelTail = NULL;
    std::vector<IOComponent*> mylist;
    while (!_stop) {
        // 先写复制到list中
        _iocsMutex.lock();
        if (_iocListChanged) {
            mylist.clear();
            IOComponent *iocList = _iocListHead;
            while (iocList) {
                mylist.push_back(iocList);
                iocList = iocList->_next;
            }
            _iocListChanged = false;
        }
        // 加入到mydel中
        if (_delListHead != NULL && _delListTail != NULL) {
            if (mydelTail == NULL) {
                mydelHead = _delListHead;
            } else {
                mydelTail->_next = _delListHead;
                _delListHead->_prev = mydelTail;
            }
            mydelTail = _delListTail;
            // 清空delList
            _delListHead = _delListTail = NULL;
        }
        _iocsMutex.unlock();

        // 对每个iocomponent进行检查
        for (int i=0; i<(int)mylist.size(); i++) {
            IOComponent *ioc = mylist[i];
            ioc->checkTimeout(tbsys::CTimeUtil::getTime());
        }

        // 删除掉
        IOComponent *tmpList = mydelHead;
        int64_t nowTime = tbsys::CTimeUtil::getTime() - static_cast<int64_t>(900000000); // 15min
        while (tmpList) {
            if (tmpList->getRef() <= 0) {
                tmpList->subRef();
            }
            if (tmpList->getRef() <= -10 || tmpList->getLastUseTime() < nowTime) {
                // 从链中删除
                if (tmpList == mydelHead) { // head
                    mydelHead = tmpList->_next;
                }
                if (tmpList == mydelTail) { // tail
                    mydelTail = tmpList->_prev;
                }
                if (tmpList->_prev != NULL)
                    tmpList->_prev->_next = tmpList->_next;
                if (tmpList->_next != NULL)
                    tmpList->_next->_prev = tmpList->_prev;

                IOComponent *ioc = tmpList;
                tmpList = tmpList->_next;
                TBSYS_LOG(INFO, "DELIOC, %s, IOCount:%d, IOC:%p\n",
                          ioc->getSocket()->getAddr().c_str(), _iocListCount, ioc);
                delete ioc;
            } else {
                tmpList = tmpList->_next;
            }
        }

        usleep(500000);  // 最小间隔100ms
    }

    // 写回到_delList上,让destroy销毁
    _iocsMutex.lock();
    if (mydelHead != NULL) {
        if (_delListTail == NULL) {
            _delListHead = mydelHead;
        } else {
            _delListTail->_next = mydelHead;
            mydelHead->_prev = _delListTail;
        }
        _delListTail = mydelTail;
    }
    _iocsMutex.unlock();
}
Ejemplo n.º 18
0
void IOComponent::processAll(uint64_t clock, size_t data_size, uint8_t *mask, uint8_t *data, 
			std::set<IOComponent *> &updated_machines) {
	io_clock = clock;
	// receive process data updates and mask to yield updated components
    current_time = microsecs();

	assert(data != io_process_data);

#if VERBOSE_DEBUG
	for (size_t ii=0; ii<data_size; ++ii) if (mask[ii]) {
		std::cout << "IOComponent::processAll()\n";
		std::cout << "size: " << data_size << "\n";
		std::cout << "pdta: "; display( io_process_data, data_size); std::cout << "\n";
		std::cout << "pmsk: "; display( io_process_mask, data_size); std::cout << "\n";
		std::cout << "data: "; display( data, data_size); std::cout << "\n";
		std::cout << "mask: "; display( mask, data_size); std::cout << "\n";
		break;
	}
#endif

	assert(data_size == process_data_size);

	if (hardware_state == s_hardware_preinit) {
		// the initial process data has arrived from EtherCAT. keep the previous data as the defaults
		// so they can be applied asap
		memcpy(io_process_data, data, process_data_size);
		//setHardwareState(s_hardware_init);
		return;
	}

	// step through the incoming mask and update bits in process data
	uint8_t *p = data;
	uint8_t *m = mask;
	uint8_t *q = io_process_data;
	IOComponent *just_added = 0;
	for (unsigned int i=0; i<process_data_size; ++i) {
		if (!last_process_data) {
			if (*m) notifyComponentsAt(i);
		}
//		if (*m && *p==*q) {
//			std::cout<<"warning: incoming_data == process_data but mask indicates a change at byte "
//			<< (int)(m-mask) << std::setw(2) <<  std::hex << " value: 0x" << (int)(*m) << std::dec << "\n";
//		}
		if (*p != *q && *m) { // copy masked bits if any
			uint8_t bitmask = 0x01;
			int j = 0;
			// check each bit against the mask and if the mask if
			// set, check if the bit has changed. If the bit has
			// changed, notify components that use this bit and 
			// update the bit
			while (bitmask) {
				if ( *m & bitmask) {
					//std::cout << "looking up " << i << ":" << j << "\n";
					IOComponent *ioc = (*indexed_components)[ i*8+j ];
					if (ioc && ioc != just_added) {
						just_added = ioc;
						//if (!ioc) std::cout << "no component at " << i << ":" << j << " found\n"; 
						//else std::cout << "found " << ioc->io_name << "\n";
#if 0
						if (ioc && ioc->last_event != e_none) { 
							// pending locally sourced change on this io
							std::cout << " adding " << ioc->io_name << " due to event " << ioc->last_event << "\n";
							updatedComponentsIn.insert(ioc);
						}
#endif
						if ( (*p & bitmask) != (*q & bitmask) ) {
							// remotely source change on this io
							if (ioc) {
								//std::cout << " adding " << ioc->io_name << " due to bit change\n";
								boost::recursive_mutex::scoped_lock lock(processing_queue_mutex);
								updatedComponentsIn.insert(ioc);
							}

							if (*p & bitmask) *q |= bitmask; 
							else *q &= (uint8_t)(0xff - bitmask);
						}
						//else { 
						//	std::cout << "no change " << (unsigned int)*p << " vs " << 
						//		(unsigned int)*q << "\n";}
					}
					else {
						if (!ioc) std::cout << "IOComponent::processAll(): no io component at " << i <<":" <<j <<" but mask bit is set\n";
						if ( (*p & bitmask) != (*q & bitmask) ) {
							if (*p & bitmask) *q |= bitmask; 
							else *q &= (uint8_t)(0xff - bitmask);
						}
					}
				}
				bitmask = bitmask << 1;
				++j;
			}
		}
		++p; ++q; ++m;
	}
	
	if (hardware_state == s_operational) {
		// save the domain data for the next check
		if (!last_process_data) {
			last_process_data = new uint8_t[process_data_size];
		}
		memcpy(last_process_data, io_process_data, process_data_size);
	}
    
	{
		boost::recursive_mutex::scoped_lock lock(processing_queue_mutex);
	if (!updatedComponentsIn.size())
		return;
//	std::cout << updatedComponentsIn.size() << " component updates from hardware\n";
#ifdef USE_EXPERIMENTAL_IDLE_LOOP
	// look at the components that changed and remove them from the outgoing queue as long as the 
	// outputs have been sent to the hardware
	std::set<IOComponent*>::iterator iter = updatedComponentsIn.begin();
	while (iter != updatedComponentsIn.end()) {
		IOComponent *ioc = *iter++;
		ioc->read_time = io_clock;
		//std::cerr << "processing " << ioc->io_name << " time: " << ioc->read_time << "\n";
		updatedComponentsIn.erase(ioc); 
		if (updates_sent && updatedComponentsOut.count(ioc)) {
			//std::cout << "output request for " << ioc->io_name << " resolved\n";
			updatedComponentsOut.erase(ioc);
		}
		//else std::cout << "still waiting for " << ioc->io_name << " event: " << ioc->last_event << "\n";
		updated_machines.insert(ioc);
	}
	// for machines with updates to send, if these machines already have the same value
	// as the hardware (and updates have been sent) we also remove them from the
	// outgoing queue
	if (updates_sent) {
		iter = updatedComponentsOut.begin();
		while (iter != updatedComponentsOut.end()) {
			IOComponent *ioc = *iter++;
			if (ioc->pending_value == (uint32_t)ioc->address.value) {
				//std::cout << "output request for " << ioc->io_name << " cleared as hardware value matches\n";
				updatedComponentsOut.erase(ioc);
			}
		}
	}
#else
	std::list<IOComponent *>::iterator iter = processing_queue.begin();
	while (iter != processing_queue.end()) {
		IOComponent *ioc = *iter++;
		ioc->read_time = io_clock;
		ioc->idle();
	}
#endif
	}
	outputs_waiting = updatedComponentsOut.size();
}