void RChannelFifoNBWriter:: StartSupplier(RChannelBufferPrefetchInfo* prefetchCookie) { ChannelUnitList unblockedList; { AutoCriticalSection acs(&m_baseDR); LogAssert(m_supplierState == SS_Stopped); LogAssert(m_writerState != WS_Closed); LogAssert(m_outstandingUnits == 0); BOOL bRet = ::ResetEvent(m_supplierDrainEvent); LogAssert(bRet != 0); m_supplierState = SS_Running; while (m_blockedList.IsEmpty() == false) { ++m_outstandingUnits; RChannelFifoUnit* blockedUnit = m_blockedList.CastOut(m_blockedList.GetHead()); unblockedList.TransitionToTail(unblockedList. CastIn(blockedUnit)); } m_sendLatch.AcceptList(&unblockedList); } SendUnits(&unblockedList); }
void RChannelFifoWriter::AcceptReturningUnit(RChannelFifoUnit* unit) { ChannelUnitList unblockedList; ChannelFifoUnitList returnList; bool wakeUpWriterDrain = false; bool wakeUpSupplierDrain = false; { AutoCriticalSection acs(&m_baseDR); LogAssert(m_outstandingUnits > 0); --m_outstandingUnits; if (unit == m_terminationUnit) { LogAssert(m_outstandingUnits == 0); LogAssert(m_blockedList.IsEmpty()); m_terminationUnit = NULL; if (m_writerState == WS_Draining) { wakeUpWriterDrain = true; } } returnList.InsertAsTail(returnList.CastIn(unit)); unit = NULL; if (m_supplierState == SS_Draining) { /* the supplier has requested a drain */ if (m_outstandingUnits == 0) { /* we have been building up written items in the blocked list while waiting for the outstanding units to be returned. We can send them all back now. */ LogAssert(m_readerTerminationItem != NULL); RChannelItemType drainType = m_readerTerminationItem->GetType(); wakeUpWriterDrain = ReWriteBlockedListForEarlyReturn(drainType) || wakeUpWriterDrain; returnList.TransitionToTail(&m_blockedList); m_supplierState = SS_Stopped; ++m_supplierEpoch; wakeUpSupplierDrain = true; } LogAssert(m_availableUnits == 0); } else if (m_supplierState != SS_Interrupted) { LogAssert(m_supplierState == SS_Running); if (m_blockedList.IsEmpty()) { if (m_writerTerminationItem == NULL) { /* there's nothing blocked, so just add a unit to the available list and return without doing anything else */ ++m_availableUnits; } } else { /* there was a blocked request waiting to be sent to the FIFO: put it in now that we have a space available. */ LogAssert(m_supplierState == SS_Running); RChannelFifoUnit* blockedUnit = m_blockedList.CastOut(m_blockedList.GetHead()); unblockedList.TransitionToTail(unblockedList. CastIn(blockedUnit)); ++m_outstandingUnits; m_sendLatch.AcceptList(&unblockedList); } } m_returnLatch.AcceptList(&returnList); } if (wakeUpWriterDrain) { LogAssert(unblockedList.IsEmpty()); BOOL bRet = ::SetEvent(m_writerDrainEvent); LogAssert(bRet != 0); } else { SendUnits(&unblockedList); } ReturnHandlers(&returnList); if (wakeUpSupplierDrain) { BOOL bRet = ::SetEvent(m_supplierDrainEvent); LogAssert(bRet != 0); } }
void RChannelFifoWriter:: EnqueueItemArray(RChannelItemArrayRef& itemArrayIn, RChannelItemArrayWriterHandler* handler, SyncHandler* syncHandler) { ChannelUnitList sendList; ChannelFifoUnitList returnList; bool writerHasTerminated = false; RChannelFifoUnit* unit = new RChannelFifoUnit(this); RChannelItemArrayRef itemArray; /* ensure that the caller no longer holds a reference to this array */ itemArray.TransferFrom(itemArrayIn); LogAssert(itemArray->GetNumberOfItems() > 0); { AutoCriticalSection acs(&m_baseDR); unit->SetPayload(itemArray, handler, RChannelItem_MarshalError); LogAssert(m_writerState != WS_Closed); writerHasTerminated = CheckForTerminationItem(unit); if (writerHasTerminated) { /* some previous invocation (perhaps is another thread) has already sent a termination item so signal that we aren't accepting any more items by just returning the handler immediately with this status code */ unit->SetStatusCode(RChannelItem_EndOfStream); } else { LogAssert(m_writerState == WS_Running); if (m_supplierState == SS_Interrupted) { /* the writer has not terminated, but the reader is about to request a drain. Queue up the handler to be returned with the appropriate code once the drain actually arrives. */ LogAssert(m_readerTerminationItem == NULL); LogAssert(m_availableUnits == 0); LogAssert(unit->GetItemArray()->GetNumberOfItems() > 0); StartBlocking(unit, syncHandler); unit = NULL; } else if (m_supplierState == SS_Draining) { /* the writer has not terminated, but the reader has requested a drain. */ LogAssert(m_readerTerminationItem != NULL); RChannelItemType drainType = m_readerTerminationItem->GetType(); LogAssert(drainType != RChannelItem_MarshalError); LogAssert(m_availableUnits == 0); if (m_outstandingUnits > 0) { /* queue up this item to be returned after the in-flight items have come back. At that point the extra item reference will be removed, so leave it there for now. */ LogAssert(unit->GetItemArray()->GetNumberOfItems() > 0); StartBlocking(unit, syncHandler); unit = NULL; } else { /* if there are no in-flight items we should have returned the handlers from any previous items already so we can return this handler immediately */ LogAssert(m_blockedList.IsEmpty()); unit->SetStatusCode(drainType); unit->DiscardItems(); if (m_terminationUnit == unit) { m_terminationUnit = NULL; } } } else if (m_supplierState == SS_Stopped) { LogAssert(m_availableUnits == 0); if (m_supplierEpoch == m_writerEpoch) { /* the supplier hasn't yet been started so queue up the unit for when it is */ unit->SetStatusCode(RChannelItem_Data); LogAssert(unit->GetItemArray()->GetNumberOfItems() > 0); StartBlocking(unit, syncHandler); unit = NULL; } else { /* the supplier has already shut down so just return this immediately */ LogAssert(m_supplierEpoch == m_writerEpoch+1); LogAssert(m_readerTerminationItem != NULL); RChannelItemType drainType = m_readerTerminationItem->GetType(); LogAssert(drainType != RChannelItem_MarshalError); LogAssert(m_blockedList.IsEmpty()); unit->DiscardItems(); unit->SetStatusCode(drainType); if (m_terminationUnit == unit) { m_terminationUnit = NULL; } } } else { LogAssert(m_supplierState == SS_Running); LogAssert(unit->GetItemArray()->GetNumberOfItems() > 0); unit->SetStatusCode(RChannelItem_Data); if (m_availableUnits == 0) { /* we have no spare slots in the FIFO so add the item to the blocked list: this has the side-effect of preventing the handler being returned immediately. */ StartBlocking(unit, syncHandler); unit = NULL; } else { LogAssert(m_blockedList.IsEmpty()); /* we're ready to send this on to the reader: use the send latch to ensure the ordering is preserved. We will return the handler immediately since the FIFO was not full and it is OK to send more items. */ --m_availableUnits; RChannelFifoUnit* sendUnit; if (unit == m_terminationUnit) { /* always block on the termination item to ensure its handler gets delivered last */ StartBlocking(unit, syncHandler); unit = NULL; /* cheat by stealing this back off the end of the blocking queue and send it immediately */ sendUnit = m_blockedList.CastOut(m_blockedList. RemoveTail()); /* throw away any spare FIFO units since we won't be writing any more items */ m_availableUnits = 0; } else { /* return the handler to the user immediately while also forwarding the unit to the reader */ sendUnit = DuplicateUnit(unit, itemArray); } sendList.InsertAsTail(sendList.CastIn(sendUnit)); m_sendLatch.AcceptList(&sendList); ++m_outstandingUnits; } } } if (unit != NULL) { LogAssert(unit->GetStatusCode() != RChannelItem_MarshalError); returnList.InsertAsTail(returnList.CastIn(unit)); m_returnLatch.AcceptList(&returnList); if (returnList.IsEmpty() && syncHandler != NULL) { /* another thread is returning the handler for us, so we need to wait for its event */ syncHandler->UseEvent(m_eventCache.GetEvent(true)); } } } if (writerHasTerminated) { LogAssert(sendList.IsEmpty()); LogAssert(unit != NULL); } SendUnits(&sendList); ReturnHandlers(&returnList); }
void RChannelFifoWriter:: StartSupplier(RChannelBufferPrefetchInfo* prefetchCookie) { ChannelUnitList unblockedList; { AutoCriticalSection acs(&m_baseDR); LogAssert(m_supplierState == SS_Stopped); LogAssert(m_writerState != WS_Closed); LogAssert(m_availableUnits == 0); LogAssert(m_outstandingUnits == 0); if (m_writerState == WS_Running) { m_availableUnits = m_fifoLength; } else { if (m_writerState == WS_Draining) { LogAssert(m_blockedList.IsEmpty() == false); m_availableUnits = m_fifoLength; } else { LogAssert(m_writerState == WS_Stopped); LogAssert(m_blockedList.IsEmpty()); } } BOOL bRet = ::ResetEvent(m_supplierDrainEvent); LogAssert(bRet != 0); m_supplierState = SS_Running; while (m_availableUnits > 0 && m_blockedList.IsEmpty() == false) { --m_availableUnits; ++m_outstandingUnits; RChannelFifoUnit* blockedUnit = m_blockedList.CastOut(m_blockedList.GetHead()); unblockedList.TransitionToTail(unblockedList. CastIn(blockedUnit)); } if (m_writerTerminationItem != NULL) { if (m_terminationUnit == NULL) { LogAssert(m_writerState == WS_Stopped); LogAssert(m_writerEpoch == m_supplierEpoch); } m_availableUnits = 0; } m_sendLatch.AcceptList(&unblockedList); } SendUnits(&unblockedList); }
void RChannelFifoNBWriter:: EnqueueItemArray(RChannelItemArrayRef& itemArrayIn, RChannelItemArrayWriterHandler* handler, SyncHandler* syncHandler) { ChannelUnitList sendList; ChannelFifoUnitList returnList; bool writerHasTerminated = false; RChannelFifoUnit* unit = new RChannelFifoUnit(this); RChannelItemArrayRef itemArray; /* ensure that the caller no longer holds a reference to this array */ itemArray.TransferFrom(itemArrayIn); LogAssert(itemArray->GetNumberOfItems() > 0); { AutoCriticalSection acs(&m_baseDR); unit->SetPayload(itemArray, handler, RChannelItem_MarshalError); LogAssert(m_writerState != WS_Closed); writerHasTerminated = CheckForTerminationItem(unit); if (writerHasTerminated) { /* some previous invocation (perhaps is another thread) has already sent a termination item so signal that we aren't accepting any more items by just returning the handler immediately with this status code */ unit->SetStatusCode(RChannelItem_EndOfStream); } else { LogAssert(m_writerState == WS_Running); if (m_supplierState == SS_Stopped) { if (m_supplierEpoch == m_writerEpoch) { /* the supplier hasn't started yet so return the handler to the user and queue up the data */ unit->SetStatusCode(RChannelItem_Data); RChannelFifoUnit* blockedUnit = DuplicateUnit(unit, itemArray); m_blockedList. InsertAsTail(m_blockedList.CastIn(blockedUnit)); } else { /* the supplier has already shut down so just return this immediately */ LogAssert(m_supplierEpoch == m_writerEpoch+1); LogAssert(m_readerTerminationItem != NULL); RChannelItemType drainType = m_readerTerminationItem->GetType(); LogAssert(drainType != RChannelItem_MarshalError); LogAssert(m_blockedList.IsEmpty()); unit->DiscardItems(); unit->SetStatusCode(drainType); } } else if (m_supplierState == SS_Draining) { /* the supplier has sent a drain item, so return the handler to the user with the appropriate code and throw the data away */ LogAssert(m_supplierEpoch == m_writerEpoch); LogAssert(m_readerTerminationItem != NULL); RChannelItemType drainType = m_readerTerminationItem->GetType(); LogAssert(drainType != RChannelItem_MarshalError); LogAssert(m_blockedList.IsEmpty()); unit->DiscardItems(); unit->SetStatusCode(drainType); } else if (m_supplierState == SS_Interrupted) { /* the supplier wants to drain but hasn't yet, so just return the handler to the user and throw the data away */ LogAssert(m_supplierEpoch == m_writerEpoch); LogAssert(m_readerTerminationItem == NULL); LogAssert(m_blockedList.IsEmpty()); unit->DiscardItems(); unit->SetStatusCode(RChannelItem_Data); } else { LogAssert(m_supplierState == SS_Running); unit->SetStatusCode(RChannelItem_Data); LogAssert(m_blockedList.IsEmpty()); /* return the handler to the user immediately while also forwarding the unit to the reader */ RChannelFifoUnit* sendUnit = DuplicateUnit(unit, itemArray); sendList.InsertAsTail(sendList.CastIn(sendUnit)); m_sendLatch.AcceptList(&sendList); ++m_outstandingUnits; } } LogAssert(unit->GetStatusCode() != RChannelItem_MarshalError); returnList.InsertAsTail(returnList.CastIn(unit)); m_returnLatch.AcceptList(&returnList); if (returnList.IsEmpty() && syncHandler != NULL) { /* another thread is returning the handler for us, so we need to wait for its event */ syncHandler->UseEvent(m_eventCache.GetEvent(true)); } } SendUnits(&sendList); ReturnHandlers(&returnList); }
void Event(SDL_Event* event) { int mousePosition[2], selected_unit; static int keytaps = 0; // Något slags fulhax if(drawconsole){ char legal[] = "abcdefghijklmnopqrstuvwxyzåäö1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZÅÄÖ,.-;:_*^~!¤%&/()=?+\\<>|øæ "; if(event->type == SDL_KEYUP){ if(event->key.keysym.sym == SDLK_RETURN){ if(strlen(console)>0){ char buff[PACKETSIZE]; strncpy(buff, console ,PACKETSIZE); cmdsend(1,0,client_id,console,NULL); } drawconsole = false; int i; for(i=0; i<MESSAGESIZE; i++) console[i] = '\0'; keytaps=0; if(DEBUG) fprintf(stderr,"Chat toggle = FALSE\n"); } } else if(event->type == SDL_KEYDOWN) { if(event->key.keysym.sym == SDLK_BACKSPACE){ int len = strlen(console); if(keytaps>0) keytaps--; console[len-1 > 0 ? len-1 : 0] = '\0'; } else { int i; if(strlen(console)+1 < MESSAGESIZE){ for(i=0; i<strlen(legal); i++){ if(legal[i] == event->key.keysym.unicode){ console[keytaps] = event->key.keysym.unicode; keytaps++; break; } } } } } } else if(mapmakerOpen) mmEvent(event); else if(menuOpen) menuEvent(event); else if(startMenuOpen) startMenuEvent(event); else //In-game { switch (event->type) { case SDL_QUIT: running = false; break; case SDL_KEYDOWN: switch (event->key.keysym.sym) { case SDLK_ESCAPE: running = false; break; case SDLK_q: running = false; break; case SDLK_F10: offsetflag[0] = 0; offsetflag[1] = 0; altDown = false; tabDown = false; menuOpen = true; break; case SDLK_CAPSLOCK: capsActive = true; break; case SDLK_LEFT: offsetflag[0]=-1; break; case SDLK_RIGHT: offsetflag[0]=1; break; case SDLK_DOWN: offsetflag[1]=1; break; case SDLK_UP: offsetflag[1]=-1; break; case SDLK_m: PlayGameSound(MUSIC); break; case SDLK_LSHIFT: case SDLK_RSHIFT: shiftDown = true; if(DEBUG) fprintf(stderr,"Shift Down\n"); break; case SDLK_LALT: altDown = true; if(DEBUG) fprintf(stderr,"Alt Down\n"); break; case SDLK_LCTRL: case SDLK_RCTRL: ctrlDown = true; if(DEBUG) fprintf(stderr,"Ctrl Down\n"); break; case SDLK_TAB: cmdsend(80,client_id,0," "," "); tabDown = true; if(DEBUG) fprintf(stderr,"TAB Down\n"); break; case SDLK_0: //Handles control groups case SDLK_1: case SDLK_2: case SDLK_3: case SDLK_4: case SDLK_5: case SDLK_6: case SDLK_7: case SDLK_8: case SDLK_9: if(ctrlDown) { SetControlGroup(event->key.keysym.sym-48); if(DEBUG)fprintf(stderr,"Setting control group: %i\n",event->key.keysym.sym-48); } else { GetControlGroup(event->key.keysym.sym-48); if(DEBUG)fprintf(stderr,"Getting control group: %i\n",event->key.keysym.sym-48); } break; default: break; } break; case SDL_KEYUP: switch (event->key.keysym.sym) { case SDLK_RETURN: drawconsole = true; fprintf(stderr, "Chat toggle = TRUE\n"); break; case SDLK_LEFT: if(offsetflag[0] == -1) offsetflag[0]=0; break; case SDLK_RIGHT: if(offsetflag[0] == 1) offsetflag[0]=0; break; case SDLK_DOWN: if(offsetflag[1] == 1) offsetflag[1]=0; break; case SDLK_UP: if(offsetflag[1] == -1) offsetflag[1]=0; break; case SDLK_LSHIFT: case SDLK_RSHIFT: shiftDown = false; if(DEBUG) fprintf(stderr,"Shift Up\n"); break; case SDLK_LALT: altDown = false; if(DEBUG) fprintf(stderr,"Alt Up\n"); break; case SDLK_LCTRL: case SDLK_RCTRL: ctrlDown = false; if(DEBUG) fprintf(stderr,"Ctrl Up\n"); break; case SDLK_TAB: tabDown = false; if(DEBUG) fprintf(stderr,"TAB Up\n"); break; case SDLK_CAPSLOCK: capsActive = false; break; default: break; } break; case SDL_MOUSEMOTION: SDL_GetMouseState(&mousePosition[0],&mousePosition[1]); if( mousePosition[0] < 5 || mousePosition[0] > WINDOWWIDTH-5 //Checks if mouse is close to the screen borders || mousePosition[1] < 5 || mousePosition[1] > WINDOWHEIGHT-5) { if(mousePosition[0] < 5) offsetflagmouse[0] = -1; //Sets offset flags according to mouse position if(mousePosition[0] > WINDOWWIDTH-5) offsetflagmouse[0] = 1; if(mousePosition[1] < 5) offsetflagmouse[1] = -1; if(mousePosition[1] > WINDOWHEIGHT-5) offsetflagmouse[1] = 1; } else //Sets offset flags to 0 if mouse is not close to the borders { offsetflagmouse[0] = 0; offsetflagmouse[1] = 0; } if(scrollDown) { SDL_GetMouseState(&mousePosition[0],&mousePosition[1]); if(mousePosition[0] > scrollDownStart[0] + 10) offsetflagscroll[0] = 1; if(mousePosition[0] < scrollDownStart[0] - 10) offsetflagscroll[0] = -1; if(mousePosition[1] > scrollDownStart[1] + 10) offsetflagscroll[1] = 1; if(mousePosition[1] < scrollDownStart[1] - 10) offsetflagscroll[1] = -1; } if(leftMouseDown) { boxEnd[0] = mousePosition[0]+offset[0]*TILEDIAGONAL; boxEnd[1] = mousePosition[1]+offset[1]*TILEDIAGONAL/2; } break; case SDL_MOUSEBUTTONDOWN: { SDL_GetMouseState(&mousePosition[0],&mousePosition[1]); switch (event->button.button) { case SDL_BUTTON_LEFT: if(showEndgameStatus) showEndgameStatus = false; lastSelectedGroup = -1; if(mousePosition[1] < WINDOWHEIGHT-HUD_HEIGHT) //If the mouse is within the game area { SetSelected(mousePosition); SDL_GetMouseState(&mousePosition[0],&mousePosition[1]); boxStart[0] = mousePosition[0]+offset[0]*TILEDIAGONAL; boxStart[1] = mousePosition[1]+offset[1]*TILEDIAGONAL/2; boxEnd[0] = boxStart[0]; //Prevents graphical errors boxEnd[1] = boxStart[1]; leftMouseDown = true; } else { hudClick = true; ClickHUDButton(mousePosition); } break; case SDL_BUTTON_RIGHT: if(mousePosition[1] < WINDOWHEIGHT-HUD_HEIGHT) { //If the mouse is within the game area //fprintf(stdout,"RIGHTCLICK\n"); selected_unit = SetTarget(mousePosition); SDL_GetMouseState(&mousePosition[0],&mousePosition[1]); //New mouse coordinates as SetTarget manipulates them SendUnits(mousePosition,selected_unit); /* if ( selected_unit == -1 )//Tries to set target { if ( SetDestination(mousePosition) == true ) //Only set destination if target set failed { if(DEBUG) fprintf(stdout,"Sending selected unit(s) to %i,%i\n",mousePosition[0],mousePosition[1]); } } else if (unit[selected_unit].owner == client_id) { fprintf(stdout,"Following unit %i\n",selected_unit); } else if (unit[selected_unit].owner != client_id) { fprintf(stdout,"Attacking unit %i\n",selected_unit); }*/ } break; case SDL_BUTTON_WHEELUP: zoomSchedueled += 1; break; case SDL_BUTTON_WHEELDOWN: zoomSchedueled -= 1; break; case SDL_BUTTON_MIDDLE: scrollDown = true; SDL_GetMouseState(&scrollDownStart[0],&scrollDownStart[1]); if(DEBUG) fprintf(stderr,"Middle mouse button Down\n"); break; } } break; case SDL_MOUSEBUTTONUP: { switch (event->button.button) { case SDL_BUTTON_LEFT: if(hudClick) { hudClick = false; break; } leftMouseDown = false; int temp; SDL_GetMouseState(&mousePosition[0],&mousePosition[1]); boxEnd[0] = mousePosition[0]+offset[0]*TILEDIAGONAL; boxEnd[1] = mousePosition[1]+offset[1]*TILEDIAGONAL/2; boxDiff[0] = boxStart[0] - boxEnd[0]; boxDiff[1] = boxStart[1] - boxEnd[1]; if(boxDiff[0] < 0) { boxDiff[0] *= -1; } else { temp = boxStart[0]; boxStart[0] = boxEnd[0]; boxEnd[0] = temp; } if(boxDiff[1] < 0) { boxDiff[1] *= -1; } else { temp = boxStart[1]; boxStart[1] = boxEnd[1]; boxEnd[1] = temp; } if(boxDiff[0] > BOX_LIMIT || boxDiff[1] > BOX_LIMIT) SetSelectedGroup(); //Only use the SetSelectedGroup function if the box is large enough break; case SDL_BUTTON_MIDDLE: scrollDown = false; offsetflagscroll[0] = 0; offsetflagscroll[1] = 0; if(DEBUG) fprintf(stderr,"Middle mouse button Up\n"); break; } } break; } } }