kresolvermanager.cpp

来自「konqueror3 embedded版本, KDE环境下的当家浏览器的嵌入式版」· C++ 代码 · 共 823 行 · 第 1/2 页

CPP
823
字号
{  /////  // This function is called in a worker thread!!  /////  //qDebug("KResolverManager::releaseData(%u/%p): %p has been released", pid, //	 (void*)QThread::currentThread(), (void*)data);  if (data->obj)    {      data->obj->status = KResolver::PostProcessing;	    }        data->worker->m_finished = true;  data->worker->th = 0L;	// this releases the object  // handle finished requests  handleFinished();}// this function is called by KResolverManager::releaseData abovevoid KResolverManager::handleFinished(){    bool redo = false;  QPtrQueue<RequestData> doneRequests;  mutex.lock();  // loop over all items on the currently running list  // we loop from the last to the first so that we catch requests with "requestors" before  // we catch the requestor itself.  RequestData *curr = currentRequests.last();  while (curr)    {      if (curr->worker->th == 0L)	{	  if (handleFinishedItem(curr))	    {	      doneRequests.enqueue(currentRequests.take());	      if (curr->requestor &&		  curr->requestor->nRequests == 0 && 		  curr->requestor->worker->m_finished)		// there's a requestor that is now finished		redo = true;	    }	}            curr = currentRequests.prev();    }        //qDebug("KResolverManager::handleFinished(%u): %d requests to notify", pid, doneRequests.count());  while (RequestData *d = doneRequests.dequeue())    doNotifying(d);  mutex.unlock();  if (redo)    {      //qDebug("KResolverManager::handleFinished(%u): restarting processing to catch requestor",	//     pid);      handleFinished();    }}// This function is called by KResolverManager::handleFinished abovebool KResolverManager::handleFinishedItem(RequestData* curr)					  {  // for all items that aren't currently running, remove from the list  // this includes all finished or cancelled requests  if (curr->worker->m_finished && curr->nRequests == 0)    {      // this one has finished      if (curr->obj)	curr->obj->status = KResolver::PostProcessing; // post-processing is run in doNotifying()      if (curr->requestor)	--curr->requestor->nRequests;      //qDebug("KResolverManager::handleFinishedItem(%u): removing %p since it's done",	//     pid, (void*)curr);      return true;    }  return false;}void KResolverManager::registerNewWorker(KResolverWorkerFactoryBase *factory){  workerFactories.append(factory);}KResolverWorkerBase* KResolverManager::findWorker(KResolverPrivate* p){  /////  // this function can be called on any user thread  /////  // this function is called with an unlocked mutex and it's expected to be   // thread-safe!  // but the factory list is expected not to be changed asynchronously  // This function is responsible for finding a suitable worker for the given  // input. That means we have to do a costly operation to create each worker  // class and call their preprocessing functions. The first one that  // says they can process (i.e., preprocess() returns true) will get the job.  KResolverWorkerBase *worker;  for (KResolverWorkerFactoryBase *factory = workerFactories.first(); factory;        factory = workerFactories.next())    {      worker = factory->create();      // set up the data the worker needs to preprocess      worker->input = &p->input;      if (worker->preprocess())	{	  // good, this one says it can process	  if (worker->m_finished)	   	    p->status = KResolver::PostProcessing;	  else	    p->status = KResolver::Queued;	  return worker;	}      // no, try again      delete worker;    }  // found no worker  return 0L;}void KResolverManager::doNotifying(RequestData *p){  /////  // This function may be called on any thread  // any thread at all: user threads, GUI thread, manager thread or worker thread  /////  // Notification and finalisation  //  // Once a request has finished the normal processing, we call the  // post processing function.  //  // After that is done, we will consolidate all results in the object's  // KResolverResults and then post an event indicating that the signal  // be emitted  //  // In case we detect that the object is waiting for completion, we do not  // post the event, for KResolver::wait will take care of emitting the  // signal.  //  // Once we release the mutex on the object, we may no longer reference it  // for it might have been deleted.  // "User" objects are those that are not created by the manager. Note that  // objects created by worker threads are considered "user" objects. Objects  // created by the manager are those created for KResolver::resolveAsync.  // We should delete them.  if (p->obj)    {      // lock the object      p->obj->mutex.lock();      KResolver* parent = p->obj->parent; // is 0 for non-"user" objects      KResolverResults& r = p->obj->results;      if (p->obj->status == KResolver::Canceled)	{	  p->obj->status = KResolver::Canceled;	  p->obj->errorcode = KResolver::Canceled;	  p->obj->syserror = 0;	  r.setError(KResolver::Canceled, 0);	}      else if (p->worker)	{	  // post processing	  p->worker->postprocess();	// ignore the result	  // copy the results from the worker thread to the final	  // object	  r = p->worker->results;	  // reset address	  r.setAddress(p->input->node, p->input->service);	  //qDebug("KResolverManager::doNotifying(%u/%p): for %p whose status is %d and has %d results", 		 //pid, (void*)QThread::currentThread(), (void*)p, p->obj->status, r.count());	  p->obj->errorcode = r.error();	  p->obj->syserror = r.systemError();	  p->obj->status = !r.isEmpty() ? 	    KResolver::Success : KResolver::Failed;	}      else	{	  r.empty();	  r.setError(p->obj->errorcode, p->obj->syserror);	}      // check whether there's someone waiting      if (!p->obj->waiting && parent)	// no, so we must post an event requesting that the signal be emitted	// sorry for the C-style cast, but neither static nor reintepret cast work	// here; I'd have to do two casts	QApplication::postEvent(parent, new QEvent((QEvent::Type)(ResolutionCompleted)));      // release the mutex      p->obj->mutex.unlock();    }  else    {      // there's no object!      if (p->worker)	p->worker->postprocess();    }  delete p->worker;  // ignore p->requestor and p->nRequests  // they have been dealt with by the main loop  delete p;  // notify any objects waiting in KResolver::wait  notifyWaiters.wakeAll();}// enqueue a new request// this function is called from KResolver::start and // from KResolverWorkerBase::enqueuevoid KResolverManager::enqueue(KResolver *obj, RequestData *requestor){  RequestData *newrequest = new RequestData;  newrequest->nRequests = 0;  newrequest->obj = obj->d;  newrequest->input = &obj->d->input;  newrequest->requestor = requestor;  // when processing a new request, find the most  // suitable worker  if ((newrequest->worker = findWorker(obj->d)) == 0L)    {      // oops, problem      // cannot find a worker class for this guy      obj->d->status = KResolver::Failed;      obj->d->errorcode = KResolver::UnsupportedFamily;      obj->d->syserror = 0;      doNotifying(newrequest);      return;    }  // no, queue it  // p->status was set in findWorker!  if (requestor)    requestor->nRequests++;  if (!newrequest->worker->m_finished)    dispatch(newrequest);  else if (newrequest->nRequests > 0)    {      mutex.lock();      currentRequests.append(newrequest);      mutex.unlock();    }  else    // already done    doNotifying(newrequest);}// a new request has been created// dispatch itvoid KResolverManager::dispatch(RequestData *data){  // As stated in the beginning of the file, this function  // is supposed to verify the availability of threads, start  // any if necessary  QMutexLocker locker(&mutex);  // add to the queue  newRequests.append(data);  // check if we need to start a new thread  //  // we depend on the variables availableThreads and runningThreads to  // know if we are supposed to start any threads:  // - if availableThreads > 0, then there is at least one thread waiting,  //    blocked in KResolverManager::requestData. It can't unblock  //    while we are holding the mutex locked, therefore we are sure that  //    our event will be handled  // - if availableThreads == 0:  //   - if runningThreads < maxThreads  //     we will start a new thread, which will certainly block in  //     KResolverManager::requestData because we are holding the mutex locked  //   - if runningThreads == maxThreads  //     This situation generally means that we have already maxThreads running  //     and that all of them are processing. We will not start any new threads,  //     but will instead wait for one to finish processing and request new data  //  //     There's a possible race condition here, which goes unhandled: if one of  //     threads has timed out waiting for new data and is in the process of  //     exiting. In that case, availableThreads == 0 and runningThreads will not  //     have decremented yet. This means that we will not start a new thread  //     that we could have. However, since there are other threads working, our  //     event should be handled soon.  //     It won't be handled if and only if ALL threads are in the process of   //     exiting. That situation is EXTREMELY unlikely and is not handled either.  //  if (availableThreads == 0 && runningThreads < maxThreads)    {      // yes, a new thread should be started      // find if there's a finished one      KResolverThread *th = workers.first();      while (th && th->running())	th = workers.next();      if (th == 0L)	// no, create one	th = new KResolverThread;      else	workers.take();      th->start();      workers.append(th);      runningThreads++;    }  feedWorkers.wakeAll();  // clean up idle threads  workers.first();  while (workers.current())    {      if (!workers.current()->running())	workers.remove();      else	workers.next();    }}// this function is called by KResolverManager::dequeuebool KResolverManager::dequeueNew(KResolver* obj){  // This function must be called with a locked mutex  // Deadlock warning:  // always lock the global mutex first if both mutexes must be locked  KResolverPrivate *d = obj->d;  // check if it's in the new request list  RequestData *curr = newRequests.first();   while (curr)    if (curr->obj == d)      {	// yes, this object is still in the list	// but it has never been processed	d->status = KResolver::Canceled;	d->errorcode = KResolver::Canceled;	d->syserror = 0;	newRequests.take();	delete curr->worker;	delete curr;		return true;      }    else      curr = newRequests.next();  // check if it's running  curr = currentRequests.first();  while (curr)    if (curr->obj == d)      {	// it's running. We cannot simply take it out of the list.	// it will be handled when the thread that is working on it finishes	d->mutex.lock();	d->status = KResolver::Canceled;	d->errorcode = KResolver::Canceled;	d->syserror = 0;	// disengage from the running threads	curr->obj = 0L;	curr->input = 0L;	if (curr->worker)	  curr->worker->input = 0L;	d->mutex.unlock();      }    else      curr = currentRequests.next();  return false;}// this function is called by KResolver::cancel// it's expected to be thread-safevoid KResolverManager::dequeue(KResolver *obj){  QMutexLocker locker(&mutex);  dequeueNew(obj);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?