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