static void *rpc_func(int fid, void *buf, int bufsize) { int *res = &rpc_result; int thid = -1; switch (fid) { case RPCF_GetBufAddr: *res = (u32)dma_buffer; break; case RPCF_DmaRead: thid = read_thid; WakeupThread(thid); break; case RPCF_DmaWrite: thid = write_thid; WakeupThread(thid); break; default: *res = -1; } if (thid >= 0) { cur_thid = thid; *res = 0; } return res; }
int NetManRpcNetIFSendPacket(const void *packet, unsigned int length){ struct PacketTag *PacketTag; WaitSema(NetManTxSemaID); NetmanTxWaitingThread=GetThreadId(); WaitSema(TxBankAccessSema); //Check is there is space in the current Tx FIFO. If not, wait for the Tx thread to empty out the other FIFO. */ while(CurrentTxFIFOData->PacketReqs.NumPackets>=NETMAN_RPC_BLOCK_SIZE){ SignalSema(TxBankAccessSema); WakeupThread(TxThreadID); SleepThread(); WaitSema(TxBankAccessSema); } memcpy(&CurrentTxFIFOData->FrameBuffer[CurrentTxFIFOData->PacketReqs.TotalLength], packet, length); PacketTag=&CurrentTxFIFOData->PacketReqs.tags[CurrentTxFIFOData->PacketReqs.NumPackets]; PacketTag->offset=CurrentTxFIFOData->PacketReqs.TotalLength; PacketTag->length=length; CurrentTxFIFOData->PacketReqs.TotalLength+=(length+3)&~3; CurrentTxFIFOData->PacketReqs.NumPackets++; WakeupThread(TxThreadID); SignalSema(TxBankAccessSema); NetmanTxWaitingThread=-1; SignalSema(NetManTxSemaID); return 0; }
void ioEnd(void) { // termination requested flag gIOTerminate = 1; // wake up and wait for end WakeupThread(gIOThreadId); WakeupThread(gDispatcherThreadID); // Cancel the thread dispatcher alarm (TODO: Is this correct?) ReleaseAlarm(alarmID); }
bool Connection::IsActive() { // Good opportunity to check g_ServerShutdown if (g_ServerShutdown) WakeupThread(); return m_ConnectionActive; }
static void topThread(void *arg) { int index; while(1) { WaitSema(topSema); index = topArg.requestOut & 0x1FF; topArg.requestOut = index + 1; switch(topArg.request[index].mode) { case TOP_REQ_WAKEUP: WakeupThread(topArg.request[index].data); break; case TOP_REQ_ROTATE: RotateThreadReadyQueue(topArg.request[index].data); break; case TOP_REQ_SUSPEND: SuspendThread(topArg.request[index].data); break; /* default: Kprintf("## internal error in libkernel!\n"); */ } } }
static void TxThread(void *arg) { int ThreadToWakeUp; while(1) { SleepThread(); if(PacketReqs.count > 0) { while(PacketReqs.count > 0) { WaitSema(NetManIOSemaID); while(SifCallRpc(&NETMAN_rpc_cd, NETMAN_IOP_RPC_FUNC_SEND_PACKETS, 0, &PacketReqs, sizeof(PacketReqs), &ReceiveBuffer, sizeof(ReceiveBuffer.result), &TxEndCallback, NULL) < 0){}; SignalSema(NetManIOSemaID); } } else { if(NetmanTxWaitingThread >= 0) { DI(); ThreadToWakeUp=NetmanTxWaitingThread; NetmanTxWaitingThread=-1; EI(); WakeupThread(ThreadToWakeUp); } } } }
void ioEnd(void) { // termination requested flag gIOTerminate = 1; // wake up and wait for end WakeupThread(gIOThreadId); }
int ioPutRequest(int type, void* data) { if (isIOBlocked) return IO_ERR_IO_BLOCKED; // check the type before queueing if (!ioGetHandler(type)) return IO_ERR_INVALID_HANDLER; WaitSema(gEndSemaId); // We don't have to lock the tip of the queue... // If it exists, it won't be touched, if it does not exist, it is not being processed struct io_request_t* req = gReqEnd; if (!req) { gReqList = (struct io_request_t*)malloc(sizeof(struct io_request_t)); req = gReqList; gReqEnd = gReqList; } else { req->next = (struct io_request_t*)malloc(sizeof(struct io_request_t)); req = req->next; gReqEnd = req; } req->next = NULL; req->type = type; req->data = data; SignalSema(gEndSemaId); WakeupThread(gIOThreadId); return IO_OK; }
//Only one thread can enter this critical section! static void EnQFrame(const void *frame, unsigned int length) { SifDmaTransfer_t dmat; int dmat_id; //Write back D-cache, before performing a DMA transfer. SifWriteBackDCache((void*)frame, length); //Wait for a spot to be freed up. while(PacketReqs.count + 1 >= NETMAN_RPC_BLOCK_SIZE) { NetmanTxWaitingThread = GetThreadId(); WakeupThread(TxThreadID); SleepThread(); } //Transfer to IOP RAM dmat.src = (void*)frame; dmat.dest = &IOPFrameBuffer[IOPFrameBufferWrPtr * NETMAN_MAX_FRAME_SIZE]; dmat.size = length; dmat.attr = 0; while((dmat_id = SifSetDma(&dmat, 1))==0){}; //Record the frame length. PacketReqs.length[IOPFrameBufferWrPtr] = length; DI(); //Update the frame count. PacketReqs.count++; EI(); //Increase write pointer by one position. IOPFrameBufferWrPtr = (IOPFrameBufferWrPtr + 1) % NETMAN_RPC_BLOCK_SIZE; //Signal the transmission thread that there are more frames to transmit. WakeupThread(TxThreadID); //Ensure that the frame is copied over before returning (so that the buffer can be freed). while(SifDmaStat(dmat_id) >= 0){}; }
static void TxThread(void *arg){ struct TxFIFOData *TxFIFODataToTransmit; SifDmaTransfer_t dmat; int dmat_id, ThreadToWakeUp; while(1){ SleepThread(); WaitSema(TxBankAccessSema); if(CurrentTxFIFOData->PacketReqs.NumPackets>0){ // Switch banks TxFIFODataToTransmit=CurrentTxFIFOData; if(TxActiveBankID==0){ CurrentTxFIFOData=&TxFIFOData2; TxActiveBankID=1; } else{ CurrentTxFIFOData=&TxFIFOData1; TxActiveBankID=0; } SignalSema(TxBankAccessSema); SifWriteBackDCache(&TxFIFODataToTransmit->PacketReqs, sizeof(TxFIFODataToTransmit->PacketReqs)); dmat.src=&TxFIFODataToTransmit->PacketReqs; dmat.dest=TxFrameTagBuffer; dmat.size=8+sizeof(struct PacketTag)*TxFIFODataToTransmit->PacketReqs.NumPackets; dmat.attr=0; while((dmat_id=SifSetDma(&dmat, 1))==0){}; WaitSema(NetManIOSemaID); SifCallRpc(&NETMAN_rpc_cd, NETMAN_IOP_RPC_FUNC_SEND_PACKETS, 0, TxFIFODataToTransmit->FrameBuffer, TxFIFODataToTransmit->PacketReqs.TotalLength, NULL, 0, NULL, NULL); SignalSema(NetManIOSemaID); TxFIFODataToTransmit->PacketReqs.NumPackets=0; TxFIFODataToTransmit->PacketReqs.TotalLength=0; } else SignalSema(TxBankAccessSema); if(NetmanTxWaitingThread>=0){ ThreadToWakeUp=NetmanTxWaitingThread; NetmanTxWaitingThread=-1; //To prevent a race condition from occurring, invalidate NetmanTxWaitingThread before invoking WakeupThread. WakeupThread(ThreadToWakeUp); } } }
Connection::~Connection() { LogMessage("[%d] Connection Destroyed\n", m_RecvThreadHandle); KillConnection(); // Let thread know it is terminated. if (!m_TcpThreadTerminated) { m_TcpThreadTerminated = true; WakeupThread(); m_Mutex.Lock(); Sleep(1); m_Mutex.Unlock(); } delete m_SendQueue; }
Connection * Connection::ReSetConnection(SOCKET s, ServerManager &server_mgr, short port, int server_type, unsigned long* ip_addr) { if (!m_RecvThreadHandle) // This should never be needed, but it's in here just in case. { LogMessage("!Restarting TCP Connection receive thread\n"); #ifdef WIN32 UINT uiThreadId = 0; m_RecvThreadHandle = (HANDLE)_beginthreadex(NULL, 1024, SocketRecvThread, this, 0, &uiThreadId); #else pthread_mutex_init(&m_RecvThreadMtx, NULL); pthread_cond_init(&m_RecvThreadCond, NULL); pthread_create(&m_RecvThreadHandle, NULL, SocketRecvThread, this); #endif } m_Mutex.Lock(); m_ConnectionActive = true; // Mark this as an active connection m_PacketLoggingEnabled = false; // Disable packet logging m_KeysExchanged = false; m_LoginHandoff = false; m_InactivityTimer = 0; // Temporarily set the AvatarID to 1, otherwise it might get killed off // too soon with a heavy load (lots of connections) m_AvatarID = 1; m_Socket = s; m_TcpPort = port; m_ServerType = server_type; if (ip_addr) m_IPaddr = *ip_addr; m_Mutex.Unlock(); m_SendQueue->ResetQueue(); LogMessage("[%d] Reanimating TCP Connection receive thread\n", m_RecvThreadHandle); WakeupThread(); return this; }