Ejemplo n.º 1
0
//
// Register a memory block for deferred release.
//
void MachServer::releaseWhenDone(Allocator &alloc, void *memory)
{
    if (memory) {
        set<Allocation> &releaseSet = perThread().deferredAllocations;
        assert(releaseSet.find(Allocation(memory, alloc)) == releaseSet.end());
        secinfo("machserver", "allocing register %p with alloc %p", memory, &alloc);
        releaseSet.insert(Allocation(memory, alloc));
    }
}
void MachRunLoopServer::run(mach_msg_size_t bufferSize, mach_msg_options_t options)
{
	// allocate reply buffer
	mReplyMessage.setBuffer(bufferSize);
	
	// enable reception
	CFAutoPort::enable();

	// we are it!
	perThread().server = this;
}
Ejemplo n.º 3
0
//
// Run through the accumulated deferred allocations and release them.
// This is done automatically on every pass through the server loop;
// it must be called by subclasses that implement their loop in some
// other way.
// @@@X Needs to be thread local
//
void MachServer::releaseDeferredAllocations()
{
    set<Allocation> &releaseSet = perThread().deferredAllocations;
	for (set<Allocation>::iterator it = releaseSet.begin(); it != releaseSet.end(); it++) {
        secinfo("machserver", "releasing alloc at %p with %p", it->addr, it->allocator);

        // before we release the deferred allocation, zap it so that secrets aren't left in memory
        size_t memSize = malloc_size(it->addr);
        bzero(it->addr, memSize);
		it->allocator->free(it->addr);
    }
	releaseSet.erase(releaseSet.begin(), releaseSet.end());
}
    void DocInverterPerField::processFields(Collection<FieldablePtr> fields, int32_t count)
    {
        fieldState->reset(docState->doc->getBoost());
        
        int32_t maxFieldLength = docState->maxFieldLength;
        bool doInvert = consumer->start(fields, count);
        DocumentsWriterPtr docWriter(docState->_docWriter);
        DocInverterPerThreadPtr perThread(_perThread);
        
        for (int32_t i = 0; i < count; ++i)
        {
            FieldablePtr field = fields[i];
            if (field->isIndexed() && doInvert)
            {
                bool anyToken;
                
                if (fieldState->length > 0)
                    fieldState->position += docState->analyzer->getPositionIncrementGap(fieldInfo->name);
                
                if (!field->isTokenized())
                {
                    // un-tokenized field
                    String stringValue(field->stringValue());
                    int32_t valueLength = (int32_t)stringValue.length();
                    perThread->singleToken->reinit(stringValue, 0, valueLength);
                    fieldState->attributeSource = perThread->singleToken;
                    consumer->start(field);

                    bool success = false;
                    LuceneException finally;
                    try
                    {
                        consumer->add();
                        success = true;
                    }
                    catch (LuceneException& e)
                    {
                        finally = e;
                    }
                    if (!success)
                        docWriter->setAborting();
                    finally.throwException();
                    fieldState->offset += valueLength;
                    ++fieldState->length;
                    ++fieldState->position;
                    anyToken = (valueLength > 0);
                }
                else
                {
                    // tokenized field
                    TokenStreamPtr stream;
                    TokenStreamPtr streamValue(field->tokenStreamValue());
                    
                    if (streamValue)
                        stream = streamValue;
                    else
                    {
                        // the field does not have a TokenStream, so we have to obtain one from the analyzer
                        ReaderPtr reader; // find or make Reader
                        ReaderPtr readerValue(field->readerValue());
                        
                        if (readerValue)
                            reader = readerValue;
                        else
                        {
                            String stringValue(field->stringValue());
                            perThread->stringReader->init(stringValue);
                            reader = perThread->stringReader;
                        }
                        
                        // Tokenize field and add to postingTable
                        stream = docState->analyzer->reusableTokenStream(fieldInfo->name, reader);
                    }
                    
                    // reset the TokenStream to the first token
                    stream->reset();
                    
                    int32_t startLength = fieldState->length;
                    
                    LuceneException finally;
                    try
                    {
                        int32_t offsetEnd = fieldState->offset - 1;
                        
                        bool hasMoreTokens = stream->incrementToken();
                        
                        fieldState->attributeSource = stream;
                        
                        OffsetAttributePtr offsetAttribute(fieldState->attributeSource->addAttribute<OffsetAttribute>());
                        PositionIncrementAttributePtr posIncrAttribute(fieldState->attributeSource->addAttribute<PositionIncrementAttribute>());
                        
                        consumer->start(field);
                    
                        while (true)
                        {
                            // If we hit an exception in stream.next below (which is fairly common, eg if analyzer
                            // chokes on a given document), then it's non-aborting and (above) this one document
                            // will be marked as deleted, but still consume a docID
                            if (!hasMoreTokens)
                                break;
                            
                            int32_t posIncr = posIncrAttribute->getPositionIncrement();
                            fieldState->position += posIncr;
                            if (fieldState->position > 0)
                                --fieldState->position;
                            
                            if (posIncr == 0)
                                ++fieldState->numOverlap;
                            
                            bool success = false;
                            try
                            {
                                // If we hit an exception in here, we abort all buffered documents since the last
                                // flush, on the likelihood that the internal state of the consumer is now corrupt 
                                // and should not be flushed to a new segment
                                consumer->add();
                                success = true;
                            }
                            catch (LuceneException& e)
                            {
                                finally = e;
                            }
                            if (!success)
                                docWriter->setAborting();
                            finally.throwException();
                            ++fieldState->position;
                            offsetEnd = fieldState->offset + offsetAttribute->endOffset();
                            if (++fieldState->length >= maxFieldLength)
                            {
                                if (docState->infoStream)
                                    *docState->infoStream << L"maxFieldLength " << StringUtils::toString(maxFieldLength) << L" reached for field " << fieldInfo->name << L", ignoring following tokens\n";
                                break;
                            }
                            
                            hasMoreTokens = stream->incrementToken();
                        }
                        
                        // trigger streams to perform end-of-stream operations
                        stream->end();
                        
                        fieldState->offset += offsetAttribute->endOffset();
                        anyToken = (fieldState->length > startLength);
                    }
                    catch (LuceneException& e)
                    {
                        finally = e;
                    }
                    stream->close();
                    finally.throwException();
                }
                
                if (anyToken)
                    fieldState->offset += docState->analyzer->getOffsetGap(field);
                fieldState->boost *= field->getBoost();
            }
            
            // don't hang onto the field
            fields[i].reset();
        }
        
        consumer->finish();
        endConsumer->finish();
    }
 void DocInverterPerField::initialize()
 {
     DocInverterPerThreadPtr perThread(_perThread);
     consumer = perThread->consumer->addField(shared_from_this(), fieldInfo);
     endConsumer = perThread->endConsumer->addField(shared_from_this(), fieldInfo);
 }
Ejemplo n.º 6
0
void MachServer::runServerThread(bool doTimeout)
{
	// allocate request/reply buffers
    Message bufRequest(mMaxSize);
    Message bufReply(mMaxSize);
	
	// all exits from runServerThread are through exceptions
	try {
		// register as a worker thread
		perThread().server = this;

		for (;;) {
			// progress hook
			eventDone();
			
			// process all pending timers
			while (processTimer()) {}
		
			// check for worker idle timeout
			{	StLock<Mutex> _(managerLock);
				// record idle thread low-water mark in scan interval
				if (idleCount < leastIdleWorkers)
					leastIdleWorkers = idleCount;
				
				// perform self-timeout processing
				if (doTimeout) {
					if (workerCount > maxWorkerCount)	// someone reduced maxWorkerCount recently...
						break;							// ... so release this thread immediately
					Time::Absolute rightNow = Time::now();
					if (rightNow >= nextCheckTime) {	// reaping period complete; process
						UInt32 idlers = leastIdleWorkers;
                        secinfo("machserver", "reaping workers: %d %d", (uint32_t) workerCount, (uint32_t) idlers);
						nextCheckTime = rightNow + workerTimeout;
						leastIdleWorkers = INT_MAX;
						if (idlers > 1)					// multiple idle threads throughout measuring interval...
							break;						// ... so release this thread now
					}
				}
			}
			
			// determine next timeout (if any)
            bool indefinite = false;
			Time::Interval timeout = workerTimeout;
			{	StLock<Mutex> _(managerLock);
				if (timers.empty()) {
					indefinite = !doTimeout;
				} else {
					timeout = max(Time::Interval(0), timers.next() - Time::now());
					if (doTimeout && workerTimeout < timeout)
						timeout = workerTimeout;
                }
			}

			// receive next IPC request (or wait for timeout)
			mach_msg_return_t mr = indefinite ?
				mach_msg_overwrite(bufRequest,
					MACH_RCV_MSG | mMsgOptions,
					0, mMaxSize, mPortSet,
					MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
					(mach_msg_header_t *) 0, 0)
                    :
				mach_msg_overwrite(bufRequest,
					MACH_RCV_MSG | MACH_RCV_TIMEOUT | MACH_RCV_INTERRUPT | mMsgOptions,
					0, mMaxSize, mPortSet,
					mach_msg_timeout_t(timeout.mSeconds()), MACH_PORT_NULL,
					(mach_msg_header_t *) 0, 0);
					
			switch (mr) {
			case MACH_MSG_SUCCESS:
				// process received request message below
				break;
			default:
                secinfo("machserver", "received error: %d", mr);
				continue;
			}
			
			// process received message
			if (bufRequest.msgId() >= MACH_NOTIFY_FIRST &&
				bufRequest.msgId() <= MACH_NOTIFY_LAST) {
				// mach kernel notification message
				// we assume this is quick, so no thread arbitration here
				cdsa_notify_server(bufRequest, bufReply);
			} else {
				// normal request message
				StLock<MachServer, &MachServer::busy, &MachServer::idle> _(*this);
                secinfo("machserver", "begin request: %d, %d", bufRequest.localPort().port(), bufRequest.msgId());
				
				// try subsidiary handlers first
				bool handled = false;
				for (HandlerSet::const_iterator it = mHandlers.begin();
						it != mHandlers.end(); it++)
					if (bufRequest.localPort() == (*it)->port()) {
						(*it)->handle(bufRequest, bufReply);
						handled = true;
					}
				if (!handled) {
					// unclaimed, send to main handler
                    handle(bufRequest, bufReply);
                }

                secinfo("machserver", "end request");
			}

			// process reply generated by handler
            if (!(bufReply.bits() & MACH_MSGH_BITS_COMPLEX) &&
                bufReply.returnCode() != KERN_SUCCESS) {
                    if (bufReply.returnCode() == MIG_NO_REPLY)
						continue;
                    // don't destroy the reply port right, so we can send an error message
                    bufRequest.remotePort(MACH_PORT_NULL);
                    mach_msg_destroy(bufRequest);
            }

            if (bufReply.remotePort() == MACH_PORT_NULL) {
                // no reply port, so destroy the reply
                if (bufReply.bits() & MACH_MSGH_BITS_COMPLEX)
                    bufReply.destroy();
                continue;
            }

            /*
             *  We don't want to block indefinitely because the client
             *  isn't receiving messages from the reply port.
             *  If we have a send-once right for the reply port, then
             *  this isn't a concern because the send won't block.
             *  If we have a send right, we need to use MACH_SEND_TIMEOUT.
             *  To avoid falling off the kernel's fast RPC path unnecessarily,
             *  we only supply MACH_SEND_TIMEOUT when absolutely necessary.
             */
			mr = mach_msg_overwrite(bufReply,
                          (MACH_MSGH_BITS_REMOTE(bufReply.bits()) ==
                                                MACH_MSG_TYPE_MOVE_SEND_ONCE) ?
                          MACH_SEND_MSG | mMsgOptions :
                          MACH_SEND_MSG | MACH_SEND_TIMEOUT | mMsgOptions,
                          bufReply.length(), 0, MACH_PORT_NULL,
                          0, MACH_PORT_NULL, NULL, 0);
			switch (mr) {
			case MACH_MSG_SUCCESS:
				break;
			default:
                secinfo("machserver", "send error: %d %d", mr, bufReply.remotePort().port());
				bufReply.destroy();
				break;
			}

            
            // clean up after the transaction
            releaseDeferredAllocations();
        }
		perThread().server = NULL;
		
	} catch (...) {
		perThread().server = NULL;
		throw;
	}
}
MachRunLoopServer::~MachRunLoopServer()
{
    // no longer active on this thread
    perThread().server = NULL;
}