--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/windowing/windowserver/nonnga/SERVER/EVQUEUE.CPP Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,947 @@
+// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Window server event queue handling
+//
+//
+
+#include "EVQUEUE.H"
+
+#include "server.h"
+#include "wstop.h"
+#include "panics.h"
+#include "pointer.h"
+#include "wstraces.h"
+
+GLREF_D CDebugLogBase *wsDebugLog;
+
+#if defined(_DEBUG)
+#define __CHECK_QUEUE() CheckQueue()
+#define __ZAP_EVENTS(pointer,len) ZapEvents(pointer,len)
+#define __ZAP_EVENT(pointer) ZapEvent(pointer)
+#else
+#define __CHECK_QUEUE()
+#define __ZAP_EVENTS(pointer,len)
+#define __ZAP_EVENT(pointer)
+#endif
+
+const TInt ECopyBufSize=4;
+
+TDblQue<CEventQueue> CEventQueue::iQueueList(_FOFF(CEventQueue,iLink));
+TWsEvent *CEventQueue::iGlobalEventQueue=NULL;
+TInt CEventQueue::iGlobalEventQueueSize=0;
+TInt CEventQueue::iNumConnections=0;
+RMutex CEventQueue::iMutex;
+TWsEvent CEventQueue::iNullEvent;
+
+// CEventBase
+
+CEventBase::~CEventBase()
+ {
+ if (!iEventMsg.IsNull() && CWsTop::ShuttingDown())
+ {
+ iEventMsg.Complete(KErrServerTerminated);
+ }
+ }
+
+CEventBase::CEventBase(CWsClient *aOwner) : iWsOwner(aOwner)
+ {
+ }
+
+void CEventBase::SignalEvent(TInt aCode)
+ {
+ if (wsDebugLog)
+ wsDebugLog->SignalEvent(iWsOwner->ConnectionHandle());
+ iEventMsg.Complete(aCode);
+ iEventSignalledState|=EEventFlagSignalled;
+ }
+
+inline TBool CEventBase::IsEventCancelled()
+ {
+ return (iEventSignalledState & EEventFlagCancelled);
+ }
+
+void CEventBase::CancelRead()
+//
+// If there is an outstanding read cancel it.
+//
+ {
+ if (!iEventMsg.IsNull())
+ {
+ iEventMsg.Complete(KErrCancel);
+ }
+ iEventSignalledState|=EEventFlagCancelled;
+ }
+
+void CEventBase::GetData(TAny *aData, TInt aLen)
+ {
+ if (!(iEventSignalledState&EEventFlagSignalled))
+ {
+ iWsOwner->PPanic(EWservPanicUnsignalledEventData);
+ }
+ iEventSignalledState&=~EEventFlagSignalled;
+ CWsClient::ReplyBuf(aData,aLen);
+ }
+
+void CEventBase::EventReadyCheck()
+//
+// Queue a read of an event notification
+//
+ {
+ if ((iEventSignalledState&EEventFlagSignalled && !(iEventSignalledState&EEventFlagCancelled)) || !iEventMsg.IsNull())
+ {
+ iWsOwner->PPanic(EWservPanicReadOutstanding);
+ }
+ }
+
+void CEventBase::EventReady(const RMessagePtr2& aEventMsg)
+ {
+ EventReadyCheck();
+ iEventMsg=aEventMsg;
+ }
+
+// CEventQueue - Queue organisation functions
+
+#if defined(_DEBUG)
+void CEventQueue::CheckQueue()
+ {
+ TDblQueIter<CEventQueue> iter(iQueueList);
+ CEventQueue *qptr;
+ iter.SetToFirst();
+ while((qptr=iter++)!=NULL)
+ {
+ WS_ASSERT_DEBUG(qptr->iQueueSize>=0 && qptr->iQueueSize<=iGlobalEventQueueSize, EWsPanicCheckEventQueue);
+ WS_ASSERT_DEBUG(qptr->iQueueSize==0 || qptr->iHead<qptr->iQueueSize, EWsPanicCheckEventQueue);
+ WS_ASSERT_DEBUG(qptr->iCount<=qptr->iQueueSize, EWsPanicCheckEventQueue);
+ WS_ASSERT_DEBUG(qptr->iEventPtr>=iGlobalEventQueue && qptr->iEventPtr<=(iGlobalEventQueue+iGlobalEventQueueSize), EWsPanicCheckEventQueue);
+ }
+ for(TInt index=0;index<iCount;index++)
+ {
+ TWsEvent *ev=EventPtr(index);
+ WS_ASSERT_DEBUG(ev->Type()!=EEventMarkInvalid, EWsPanicCheckEventQueue);
+ }
+ }
+
+void CEventQueue::ZapEvent(TWsEvent *aTarget)
+ {
+ aTarget->SetType(EEventMarkInvalid);
+ aTarget->SetHandle(555);
+ }
+
+void CEventQueue::ZapEvents(TWsEvent *aTarget, TInt aLen)
+ {
+ for(TInt index=0;index<aLen;index++)
+ ZapEvent(aTarget+index);
+ }
+
+#endif
+
+void CEventQueue::EventCopy(TWsEvent *aTarget, TWsEvent *aSource, TInt aNumEvents)
+ {
+ WS_ASSERT_DEBUG(aTarget>=iGlobalEventQueue, EWsPanicEventQueueCopy);
+ WS_ASSERT_DEBUG((aTarget+aNumEvents)<=(iGlobalEventQueue+iGlobalEventQueueSize), EWsPanicEventQueueCopy);
+ Mem::Copy(aTarget,aSource,aNumEvents*sizeof(TWsEvent));
+ }
+
+TInt CEventQueue::RequiredQueueSize(TInt aNumConnections)
+ {
+ return(aNumConnections*EMinQueueSize+EMaxQueueSize+EExtraQueueSize);
+ }
+
+/**
+Adjust the Global Queue Size.
+@param aNewSize the size for event queue.
+*/
+void CEventQueue::AdjustQueueSizeL(TInt aNewSize)
+ {
+ TWsEvent* oldQ=iGlobalEventQueue;
+ if (aNewSize < iGlobalEventQueueSize)
+ {
+ // Re-alloc wont move the cell down to a lower address, this means once this cell is
+ // high up in memory it may never move down again, thus wasting loads of global heap space.
+ const CEventQueue* last=iQueueList.Last();
+ if ((last->iEventPtr + last->iQueueSize) >= (iGlobalEventQueue + aNewSize))
+ {
+ return;
+ }
+ TInt allocSize = aNewSize * sizeof(TWsEvent);
+ iGlobalEventQueue=static_cast<TWsEvent*>(User::AllocL(allocSize));
+ Mem::Copy(iGlobalEventQueue,oldQ,allocSize);
+ User::Free(oldQ);
+ }
+ else
+ {
+ iGlobalEventQueue = static_cast<TWsEvent*>(User::ReAllocL(iGlobalEventQueue, aNewSize * sizeof(TWsEvent)));
+ }
+ __ZAP_EVENTS(iGlobalEventQueue + iGlobalEventQueueSize, aNewSize - iGlobalEventQueueSize);
+ iGlobalEventQueueSize = aNewSize;
+ // coverity[use_after_free]
+ TInt diff=(reinterpret_cast<TInt8*>(iGlobalEventQueue)-reinterpret_cast<TInt8*>(oldQ));
+ if (diff)
+ {
+ TDblQueIter<CEventQueue> iter(iQueueList);
+ CEventQueue* qptr;
+ while((qptr=iter++)!=NULL)
+ {
+ qptr->iEventPtr=reinterpret_cast<TWsEvent*>(reinterpret_cast<TInt8*>(qptr->iEventPtr)+diff);
+ }
+ }
+ }
+
+void CEventQueue::AddQueueL()
+ {
+ Wait();
+ if ((iNumConnections%EQueueGranularity)==0)
+ {
+ const TInt newSize = RequiredQueueSize(iNumConnections + EQueueGranularity);
+ TRAPD(err,AdjustQueueSizeL(newSize));
+ if (err!=KErrNone)
+ {
+ __CHECK_QUEUE();
+ Signal();
+ User::Leave(err);
+ }
+ }
+ iNumConnections++;
+ if (iQueueList.IsEmpty())
+ iEventPtr=iGlobalEventQueue;
+ else
+ {
+ CEventQueue *qptr=iQueueList.Last();
+ iEventPtr=qptr->iEventPtr+qptr->iQueueSize;
+ }
+ iQueueList.AddLast(*this);
+
+ //Initialize the queue size to at least EMinQueueSize
+ //Check the queue by doing standard queue compression.
+ TBool isExpanded = ETrue;
+ do {isExpanded = Expand(EEventPriorityLow);} while ((iQueueSize < EMinQueueSize) && isExpanded);
+ while (iQueueSize < EMinQueueSize)
+ {
+ //Cannot get enough spaces by doing standard queue compression,
+ //try to grow the global queue.
+ TInt sizeRequired = EMinQueueSize - iQueueSize;
+ const TInt newSize = iGlobalEventQueueSize + sizeRequired;
+ TRAPD(err, AdjustQueueSizeL(newSize));
+ if (err != KErrNone)
+ {
+ //Cannot get enough spaces by growing global queue.
+ //try to purge the oldest events from inactive clients.
+ TInt numEventCleared = PurgeInactiveEvents(sizeRequired);
+ if (numEventCleared == 0)
+ {
+ __CHECK_QUEUE();
+ Signal();
+ User::Leave(err);
+ }
+ }
+ while (doExpand(ECompressNoPurge)) {};
+ }
+ __CHECK_QUEUE();
+ Signal();
+ }
+
+void CEventQueue::RemoveQueue()
+ {
+ Wait();
+ if (iEventPtr) // If this is still NULL this class hasn't been linked into the Q list
+ {
+ __ZAP_EVENTS(iEventPtr, iQueueSize);
+ iLink.Deque();
+ if (--iNumConnections==0)
+ {
+ User::Free(iGlobalEventQueue);
+ iGlobalEventQueue=NULL;
+ iGlobalEventQueueSize=0;
+ }
+ else if ((iNumConnections%EQueueGranularity)==0)
+ {
+ TDblQueIter<CEventQueue> iter(iQueueList);
+ CEventQueue* qptr=iter++;
+ qptr->Compress(ECompressNoPurge);
+ while((qptr=iter++)!=NULL)
+ {
+ qptr->SqueezeDown();
+ }
+ const TInt newSize = RequiredQueueSize(iNumConnections);
+ TRAP_IGNORE(AdjustQueueSizeL(newSize));
+ // Can easily leave as we need to allocate the new smaller queue before freeing
+ // the old queue. But if it does it doesn't matter as we'll simply be left with
+ // a larger than necessary buffer until the next realloc
+ }
+ iCount=0;
+ }
+ __CHECK_QUEUE();
+ Signal();
+ }
+
+void CEventQueue::IncreaseQueueSize(TInt aNumSpaces)
+ {
+ if ((iQueueSize+aNumSpaces)>EMaxQueueSize)
+ aNumSpaces=EMaxQueueSize-iQueueSize;
+ EventCopy(iEventPtr+iHead+aNumSpaces, iEventPtr+iHead, iQueueSize-iHead);
+ __ZAP_EVENTS(iEventPtr+iHead, aNumSpaces);
+ iQueueSize+=aNumSpaces;
+ iHead=(iHead+aNumSpaces)%iQueueSize;
+ }
+
+TBool CEventQueue::Expand(TWservEventPriorities aPriority)
+ {
+ if (iQueueSize==EMaxQueueSize)
+ {
+ if (aPriority==EEventPriorityHigh)
+ {
+ Purge();
+ if (iCount<iQueueSize)
+ return(ETrue); // Success!
+ }
+ }
+ else if (doExpand(ECompressNoPurge) ||
+ doExpand(ECompressPurge1) ||
+ (aPriority==EEventPriorityHigh && doExpand(ECompressPurge2)))
+ return(ETrue);
+ return(EFalse); // Failure
+ }
+
+TBool CEventQueue::doExpand(TCompressMode aCompressMode)
+ {
+ TDblQueIter<CEventQueue> iter(iQueueList);
+ iter.SetToLast();
+ CEventQueue* qptr=NULL;
+ TInt spare=0;
+
+ // while loop from last queue till current queue, moving all queues up
+ // to get all the space from between them
+ while((qptr=iter)!=this)
+ {
+ spare=qptr->SqueezeUp();
+ if (spare==0)
+ qptr->Compress(aCompressMode);
+ iter--;
+ }
+
+ // current queue, if we have space then expand the same and return
+ spare=FollowingGap();
+ if (spare>0)
+ {
+ IncreaseQueueSize(spare);
+ __CHECK_QUEUE();
+ return(ETrue);
+ }
+
+ // while loop from current queue till first queue, looking for a gap
+ // between queues and using the first one it finds
+ iter--;
+ TInt expanded=0;
+ while((qptr=iter)!=NULL)
+ {
+ expanded=qptr->SqueezeUp();
+ if (expanded>0)
+ {
+ return MoveDownAndExpand(iter, expanded);
+ }
+ else
+ qptr->Compress(aCompressMode);
+ iter--;
+ }
+
+ // Even by doing all the above if we did not find space then check if first
+ // queue has some space before it. If so then make use of it and movedown all the
+ // queue till the current queue and then use the space for expansion
+ iter.SetToFirst();
+ qptr=iter;
+ if (qptr->iEventPtr>iGlobalEventQueue)
+ {
+ return MoveDownAndExpand(iter, qptr->iEventPtr-iGlobalEventQueue);
+ }
+
+ __CHECK_QUEUE();
+ return(EFalse); // Failed to expand enough room
+ }
+
+// This function moves the queue down by given amount and repeats this until
+// the current queue and then expand the same
+TBool CEventQueue::MoveDownAndExpand(TDblQueIter<CEventQueue> &aIter, TInt aExpand)
+ {
+ CEventQueue* qptr=NULL;
+ FOREVER
+ {
+ qptr=aIter++;
+ qptr->MoveDown(aExpand);
+ if (qptr==this)
+ {
+ IncreaseQueueSize(aExpand);
+ __CHECK_QUEUE();
+ break;
+ }
+ }
+ return ETrue;
+ }
+
+void CEventQueue::MoveDown(TInt aMove)
+ {
+ if (!aMove)
+ {
+ return;
+ }
+ EventCopy(iEventPtr-aMove,iEventPtr,iQueueSize);
+ iEventPtr-=aMove;
+ }
+
+/*void CEventQueue::LogUpDownEvents(TChar aChar)
+ {
+ TWsEvent *event;
+ TBuf<128> buf;
+ buf.Zero();
+ buf.Append(aChar);
+ buf.Append('#');
+ buf.Append('#');
+ TBool some=EFalse;
+ TInt index;
+
+ for (index=0;index<iCount;index++)
+ {
+ event=EventPtr(index);
+ if (event->Type()==EEventPointer)
+ {
+ if (event->Pointer()->iType==TPointerEvent::EButton1Down
+ || event->Pointer()->iType==TPointerEvent::EButton1Up)
+ {
+ some=ETrue;
+ if (event->Pointer()->iType==TPointerEvent::EButton1Down)
+ buf.Append('D');
+ else
+ buf.Append('U');
+ buf.AppendNum(index);
+ }
+ }
+ }
+ if (wsDebugLog)
+ wsDebugLog->MiscMessage(ELogImportant,buf);
+ }*/
+
+void CEventQueue::Purge()
+ {
+// Purgable events are:
+// Pointer Up/Down pairs
+// Pointer moves & drags
+// Key messages
+// Key Up/Down pairs
+// Key Ups if not foreground connection
+// Focus lost/gained pairs
+//
+// Events that must no be purged
+// Key ups for foreground connections queue
+// Lone pointer ups, must be delivered to match preceeding pointer down
+// Lone focus lost/gained messages
+//
+ TWsEvent *event;
+ TWsEvent *event2;
+ TInt index2;
+ TInt index=iCount;
+ while(index>0)
+ {
+ event=EventPtr(--index);
+ switch(event->Type())
+ {
+ case EEventPassword:
+ break;
+ case EEventMarkInvalid:
+#if defined(_DEBUG)
+ WS_PANIC_DEBUG(EWsPanicCheckEventQueue);
+#endif
+ case EEventNull:
+ case EEventKey:
+ case EEventPointerEnter:
+ case EEventPointerExit:
+ case EEventDragDrop:
+breakLoopAndRemoveEvent:
+ RemoveEvent(index);
+ return;
+ case EEventKeyUp:
+ if (iQueueList.First()!=this)
+ goto breakLoopAndRemoveEvent;
+ break;
+ case EEventKeyDown:
+ if (iQueueList.First()!=this)
+ goto breakLoopAndRemoveEvent;
+ for (index2=index+1;index2<iCount;index2++)
+ {
+ event2=EventPtr(index2);
+ if (event2->Type()==EEventKeyUp && event2->Key()->iScanCode==event->Key()->iScanCode)
+ {
+ *event2=iNullEvent;
+ goto breakLoopAndRemoveEvent;
+ }
+ }
+ break;
+ case EEventModifiersChanged:
+ for (index2=index;index2>0;)
+ {
+ event2=EventPtr(--index2);
+ if (event2->Type()==EEventModifiersChanged)
+ {
+ event->ModifiersChanged()->iChangedModifiers|=event2->ModifiersChanged()->iChangedModifiers;
+ index=index2;
+ goto breakLoopAndRemoveEvent;
+ }
+ }
+ break;
+ case EEventPointerBufferReady:
+ CWsPointerBuffer::DiscardPointerMoveBuffer(event->Handle());
+ goto breakLoopAndRemoveEvent;
+ case EEventFocusLost:
+ case EEventFocusGained:
+ if ((index+1)<iCount)
+ {
+ event2=EventPtr(index+1);
+ if (event2->Type()==EEventFocusLost || event2->Type()==EEventFocusGained)
+ {
+ *event2=iNullEvent;
+ goto breakLoopAndRemoveEvent;
+ }
+ }
+ break;
+ case EEventSwitchOn:
+ if ((index+1)<iCount && EventPtr(index+1)->Type()==EEventSwitchOn)
+ goto breakLoopAndRemoveEvent;
+ break;
+ case EEventPointer:
+ {
+ TPointerEvent::TType upType;
+ switch(event->Pointer()->iType)
+ {
+ case TPointerEvent::EDrag:
+ case TPointerEvent::EMove:
+ case TPointerEvent::EButtonRepeat:
+ case TPointerEvent::ESwitchOn:
+ goto breakLoopAndRemoveEvent;
+ case TPointerEvent::EButton1Down:
+ upType=TPointerEvent::EButton1Up;
+ goto purgeDownUp;
+ case TPointerEvent::EButton2Down:
+ upType=TPointerEvent::EButton2Up;
+ goto purgeDownUp;
+ case TPointerEvent::EButton3Down:
+ upType=TPointerEvent::EButton3Up;
+purgeDownUp: for (index2=index+1;index2<iCount;index2++)
+ {
+ event2=EventPtr(index2);
+ if (event2->Type()==EEventPointer && event2->Handle()==event->Handle() && event2->Pointer()->iType==upType)
+ {
+ *event2=iNullEvent;
+ goto breakLoopAndRemoveEvent;
+ }
+ }
+ WsPointer::UnmatchedDownPurged(upType, event->Handle());
+ goto breakLoopAndRemoveEvent;
+ case TPointerEvent::EButton1Up:
+ case TPointerEvent::EButton2Up:
+ case TPointerEvent::EButton3Up:
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+void CEventQueue::PurgePointerEvents()
+ {
+ TWsEvent *event;
+ TWsEvent *event2;
+ TInt index2;
+ TInt index=iCount;
+ while(index>0)
+ {
+ event=EventPtr(--index);
+ switch(event->Type())
+ {
+ case EEventPointerBufferReady:
+ CWsPointerBuffer::DiscardPointerMoveBuffer(event->Handle());
+ RemoveEvent(index);
+ break;
+ case EEventPointer:
+ {
+ TPointerEvent::TType upType;
+ switch(event->Pointer()->iType)
+ {
+ case TPointerEvent::EDrag:
+ case TPointerEvent::EMove:
+ case TPointerEvent::EButtonRepeat:
+ case TPointerEvent::ESwitchOn:
+ RemoveEvent(index);
+ break;
+ case TPointerEvent::EButton1Down:
+ upType=TPointerEvent::EButton1Up;
+ goto purgeDownUp2;
+ case TPointerEvent::EButton2Down:
+ upType=TPointerEvent::EButton2Up;
+ goto purgeDownUp2;
+ case TPointerEvent::EButton3Down:
+ upType=TPointerEvent::EButton3Up;
+purgeDownUp2: for (index2=index+1;index2<iCount;index2++)
+ {
+ event2=EventPtr(index2);
+ if (event2->Type()==EEventPointer && event2->Handle()==event->Handle() && event2->Pointer()->iType==upType)
+ {
+ *event2=iNullEvent;
+ goto purgedUp;
+ }
+ }
+ WsPointer::UnmatchedDownPurged(upType, event->Handle());
+purgedUp: RemoveEvent(index);
+ break;
+ case TPointerEvent::EButton1Up:
+ case TPointerEvent::EButton2Up:
+ case TPointerEvent::EButton3Up:
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+/**
+Purge requested number of oldest events from inactive event queue.
+@param aSizeRequired the total events required to be cleared.
+@return The number of events cleared.
+*/
+TInt CEventQueue::PurgeInactiveEvents(const TInt& aSizeRequired)
+ {
+ TInt numEventsCleared = 0;
+ CEventQueue* qptr;
+ TBool isRemoved;
+ do {
+ TDblQueIter<CEventQueue> iter(iQueueList);
+ isRemoved = EFalse;
+ while ((qptr = iter++) != NULL && (aSizeRequired > numEventsCleared))
+ {
+ if ((qptr->IsEventCancelled() || (qptr->iEventMsg.IsNull() && !qptr->iEventSignalledState)) &&
+ (qptr->iQueueSize > EMinQueueSize))
+ {
+ // we have a client that is not listening with a size larger than min queue size.
+ // so lets remove it's oldest event until the number of removed events meet the requirement.
+ qptr->RemoveEvent(0);
+ numEventsCleared++;
+ isRemoved = ETrue;
+ }
+ }
+ } while ((aSizeRequired > numEventsCleared) && isRemoved);
+ return numEventsCleared;
+ }
+
+void CEventQueue::Compress(TCompressMode aCompressMode)
+ {
+//
+// The different purge modes are
+//
+// ECompressNoPurge, // Don't purge anything
+// ECompressPurge1, // Don't purge foreground queue
+// ECompressPurge2, // Purge all queues
+//
+ if (aCompressMode==ECompressPurge2 ||
+ (this!=iQueueList.First() && aCompressMode==ECompressPurge1))
+ Purge();
+ TInt compress=iQueueSize-(iCount>EMinQueueSize?iCount:EMinQueueSize);
+ if (compress>0)
+ {
+ compress=(compress+1)/2; // Compress half the free space in the queue
+ TWsEvent *head=EventPtr(0);
+ TWsEvent *tail=EventPtr(iCount);
+ if (head>tail)
+ {
+ EventCopy(iEventPtr+compress,iEventPtr,tail-iEventPtr);
+ iHead-=compress;
+ }
+ else
+ {
+ EventCopy(iEventPtr+compress,head,iCount);
+ iHead=0;
+ }
+ iEventPtr+=compress;
+ iQueueSize-=compress;
+ }
+ }
+
+void CEventQueue::MoveUp(TInt aNumEvents)
+ {
+ if (!aNumEvents)
+ {
+ return;
+ }
+ EventCopy(iEventPtr+aNumEvents,iEventPtr,iQueueSize);
+ iEventPtr+=aNumEvents;
+ }
+
+TInt CEventQueue::FollowingGap() const
+ {
+ TDblQueIter<CEventQueue> iter(iQueueList);
+ CEventQueue *qptr;
+ iter.Set(*(CEventQueue *)this);
+ iter++;
+ TWsEvent *end;
+ if ((qptr=iter)!=NULL)
+ end=qptr->iEventPtr;
+ else
+ end=iGlobalEventQueue+iGlobalEventQueueSize;
+ return(end-(iEventPtr+iQueueSize));
+ }
+
+TInt CEventQueue::SqueezeUp()
+ {
+ TInt gap=FollowingGap();
+ MoveUp(gap);
+ return(gap);
+ }
+
+void CEventQueue::SqueezeDown()
+ {
+ TDblQueIter<CEventQueue> iter(iQueueList);
+ iter.Set(*this);
+ iter--;
+ CEventQueue *qptr=iter;
+ if (qptr!=NULL)
+ {
+ Compress(ECompressNoPurge);
+ TInt gap=qptr->FollowingGap();
+ MoveDown(gap);
+ }
+ }
+
+void CEventQueue::MoveToFront()
+ {
+ if (this==iQueueList.First())
+ return;
+ Wait();
+ CEventQueue *qptr;
+ TInt gap=0;
+ TDblQueIter<CEventQueue> iter(iQueueList);
+ iter.SetToLast();
+ while((qptr=iter--)!=NULL)
+ {
+ if (gap<iQueueSize)
+ qptr->Compress(ECompressNoPurge);
+ gap=qptr->SqueezeUp();
+ }
+ if (gap>=iQueueSize)
+ EventCopy(iGlobalEventQueue,iEventPtr,iQueueSize);
+ else
+ {
+ EventCopy(iGlobalEventQueue,iEventPtr,gap);
+ iEventPtr+=gap;
+ TWsEvent copyBuf[ECopyBufSize]; // temp buffer, can copy upto ECopyBufSize events at a time
+ TInt eventsToGo=iQueueSize-gap;
+ iQueueSize=gap;
+ do
+ {
+ TInt copy=Min(eventsToGo,ECopyBufSize);
+ Mem::Copy(©Buf[0],iEventPtr,copy*sizeof(TWsEvent));
+ iter.Set(*this);
+ iter--;
+ while((qptr=iter--)!=NULL)
+ qptr->MoveUp(copy);
+ EventCopy(iGlobalEventQueue+iQueueSize,©Buf[0],copy);
+ iQueueSize+=copy;
+ eventsToGo-=copy;
+ iEventPtr+=copy;
+ } while(eventsToGo>0);
+ }
+ iEventPtr=iGlobalEventQueue;
+ this->iLink.Deque();
+ iQueueList.AddFirst(*this);
+ __CHECK_QUEUE();
+ Signal();
+ }
+
+// CEventQueue
+
+CEventQueue::CEventQueue(CWsClient *aOwner) : CEventBase(aOwner)
+ {
+ __DECLARE_NAME(_S("CEventQueue"));
+ }
+
+CEventQueue::~CEventQueue()
+ {
+ RemoveQueue();
+ }
+
+void CEventQueue::InitStaticsL()
+ {
+ User::LeaveIfError(iMutex.CreateLocal());
+ }
+
+void CEventQueue::DeleteStaticsL()
+ {
+ iMutex.Close();
+ }
+
+void CEventQueue::ConstructL()
+ {
+ AddQueueL();
+ Mem::FillZ(&iNullEvent,sizeof(iNullEvent));
+ }
+
+TWsEvent *CEventQueue::EventPtr(TInt index)
+ {
+ return(iEventPtr+((iHead+index)%iQueueSize));
+ }
+
+TBool CEventQueue::QueueEvent(const TWsEvent &event)
+ {
+ TWservEventPriorities priority=EEventPriorityLow;
+#ifdef SYMBIAN_PROCESS_MONITORING_AND_STARTUP
+ if (event.Type()==EEventPassword || event.Type()==EEventSwitchOff ||
+ event.Type()==EEventKeySwitchOff || event.Type()==EEventRestartSystem)
+#else
+ if (event.Type()==EEventPassword || event.Type()==EEventSwitchOff || event.Type()==EEventKeySwitchOff)
+#endif
+ {
+ priority=EEventPriorityHigh;
+ }
+ return(QueueEvent(event,priority));
+ }
+
+TBool CEventQueue::CheckRoom()
+//
+// If the queue is full and room is created return ETrue
+//
+ {
+ TBool ret=EFalse;
+ Wait();
+ if (iCount==iQueueSize && Expand(EEventPriorityHigh))
+ ret=ETrue;
+ Signal();
+ return(ret);
+ }
+
+TBool CEventQueue::QueueEvent(const TWsEvent &event, TWservEventPriorities aPriority)
+//
+// Queue an event, returns ETrue if queued or delivered, EFalse if the queue was full.
+//
+ {
+ WS_TRACE_SERVER_QUEUEEVENT();
+ TBool ret=ETrue;
+ Wait();
+ if (iCount==iQueueSize && !Expand(aPriority))
+ ret=EFalse;
+ else
+ {
+ if (!iEventMsg.IsNull())
+ {
+ SignalEvent();
+ }
+ *EventPtr(iCount++)=event;
+ }
+ Signal();
+ return(ret);
+ }
+
+TBool CEventQueue::QueueEvent(TUint32 aTarget, TInt aEvent)
+ {
+ TWsEvent event;
+ event.SetType(aEvent);
+ event.SetHandle(aTarget);
+ event.SetTimeNow();
+ return(QueueEvent(event));
+ }
+
+void CEventQueue::UpdateLastEvent(const TWsEvent &event)
+ {
+ WS_ASSERT_DEBUG(iCount>0, EWsPanicQueueUpdateCount);
+ Mem::Copy(EventPtr(iCount-1)->EventData(),event.EventData(),TWsEvent::EWsEventDataSize);
+ Signal();
+ }
+
+void CEventQueue::GetData()
+//
+// If there is an outstanding event in the queue, reply with it's data and remove it from the Q
+//
+ {
+ if (iCount>0)
+ {
+ WS_ASSERT_DEBUG((iEventPtr+iHead)->Type()!=EEventMarkInvalid, EWsPanicCheckEventQueue);
+ CEventBase::GetData(iEventPtr+iHead,sizeof(*iEventPtr));
+ __ZAP_EVENT(iEventPtr+iHead);
+ iHead=(iHead+1)%iQueueSize;
+ iCount--;
+ }
+ else
+ CEventBase::GetData(&iNullEvent,sizeof(iNullEvent));
+ }
+
+void CEventQueue::EventReady(const RMessagePtr2& aEventMsg)
+//
+// Queue a read of an event notification
+//
+ {
+ EventReadyCheck();
+ Wait();
+ iEventMsg=aEventMsg;
+ if (iCount>0)
+ SignalEvent();
+ Signal();
+ }
+
+void CEventQueue::RemoveEvent(TInt index)
+//
+// Remove event 'index' in the queue, this event MUST exist in the queue
+//
+ {
+ WS_ASSERT_DEBUG(index < iCount, EWsPanicCheckEventQueue);
+ iCount--;
+ for(;index<iCount;index++)
+ *EventPtr(index)= *EventPtr(index+1);
+ __ZAP_EVENT(EventPtr(iCount));
+ }
+
+const TWsEvent *CEventQueue::PeekLastEvent()
+//
+// Return a read only pointer to the last event in the queue (or NULL if no event)
+//
+ {
+ if (iCount==0)
+ return(NULL);
+ return(EventPtr(iCount-1));
+ }
+
+void CEventQueue::Wait()
+ {
+ iMutex.Wait();
+ }
+
+void CEventQueue::Signal()
+ {
+ iMutex.Signal();
+ }
+
+void CEventQueue::WalkEventQueue(EventQueueWalk aFunc, TAny *aFuncParam)
+ {
+ Wait();
+restart:
+ for (TInt index=0;index<iCount;index++)
+ {
+ TWsEvent *event=EventPtr(index);
+ switch((aFunc)(aFuncParam,event))
+ {
+ case EEventQueueWalkDeleteEvent:
+ RemoveEvent(index--);
+ case EEventQueueWalkOk:
+ break;
+ case EEventQueueWalkRestart:
+ goto restart;
+ }
+ }
+ Signal();
+ }