/* Copyright 2000 (c) by Reto Gaehler, Toni Kaufmann, Swiss Federal Institute of Technology, Computer Engineering and Networks Laboratory. TOPSY -- A Teachable Operating System. Implementation of a tiny and simple micro kernel for teaching purposes. For further information, please visit http://www.tik.ee.ethz.ch/~topsy This software is provided under the terms of the GNU General Public Licence. A full copy of the GNU GPL is provided in the file COPYING found in the development root of Topsy. */ /* File: $Source: /usr/drwho/vault/cvs/topsy/Topsy/Net/TCP/Ports.c,v $ Author(s): Affiliation: ETH Zuerich, TIK Version: $Revision: 1.2 $ Creation Date: Last Date of Change: $Date: 2000/04/03 17:45:30 $ by: $Author: gfa $ $Log: Ports.c,v $ Revision 1.2 2000/04/03 17:45:30 gfa *** empty log message *** Revision 1.1 2000/03/31 17:50:37 gfa Merged with /Net from several term projects */ #include "Ports.h" //************************************************************************************************** // ptInit // initializes a port //************************************************************************************************** int ptInit(PortPtr pPort,unsigned int uMaxNrOfMsg) { PortMsgPtr pNextMsg, pPrevMsg; int nCount; if (uMaxNrOfMsg>PORT_MAX_NUM_OF_MSG) return PORT_FAILED; pPort->pFree=&pPort->aryMsgBlock[0]; nCount=uMaxNrOfMsg; for ( pPrevMsg=pNextMsg=pPort->pFree ; --nCount > 0 ; pPrevMsg=pNextMsg ) { pPrevMsg->pNext = ++pNextMsg; } pPrevMsg->pNext = (PortMsgPtr)NULL; semInit(&pPort->recPortSem,1); semInit(&pPort->recTxSem,uMaxNrOfMsg); semInit(&pPort->recRxSem,0); pPort->pMsgHead = pPort->pMsgTail = (PortMsgPtr)NULL; pPort->nsSeqChg++; pPort->nsMaxMsg = uMaxNrOfMsg; return PORT_OK; } //************************************************************************************************** // ptClear //************************************************************************************************** void ptClear(PortPtr pPort, PortStateSet setNewState, void (*dispose)()); void ptClear(PortPtr pPort, PortStateSet setNewState, void (*dispose)()) { PortMsgPtr pMsg; if (pPort!=NULL) { /* put port in limbo until done freeing processes */ pPort->nsSeqChg++; pMsg=pPort->pMsgHead; if (pMsg != (PortMsgPtr)NULL) { if (dispose != PTNODISP) for(; pMsg != (PortMsgPtr) NULL ; pMsg=pMsg->pNext) (*dispose)( pMsg->pMsg); (*dispose)( pMsg->u32Msg); pPort->pMsgTail->pNext = pPort->pFree; pPort->pFree =pPort->pMsgHead; } if (setNewState == PORT_ALLOC) { pPort->pMsgTail = pPort->pMsgHead = (PortMsgPtr) NULL; semReset(&pPort->recTxSem, pPort->nsMaxMsg); semReset(&pPort->recRxSem, 0); } } } //************************************************************************************************** // ptReset // resets a port //************************************************************************************************** int ptReset(PortPtr pPort, void (*dispose)()) { if (pPort!=NULL) { semWait(&pPort->recPortSem); ptClear(pPort, PORT_ALLOC, dispose); semSignal(&pPort->recPortSem); return PORT_OK; } return PORT_FAILED; } //************************************************************************************************** // ptCount // returns the number of messages of this port //************************************************************************************************** int ptCount(PortPtr pPort) { int nsCount; int nsTxCount; if (pPort!=NULL) { semWait(&pPort->recPortSem); nsCount = semCount(&pPort->recRxSem); nsTxCount = semCount(&pPort->recTxSem); if (nsTxCount < 0 ) { nsCount -= nsTxCount; } semSignal(&pPort->recPortSem); return nsCount; } return PORT_FAILED; } //************************************************************************************************** // ptReceive // receives a Message from this port //************************************************************************************************** int ptReceive(PortPtr pPort, void **msg, unsigned long *u32Msg) { PortMsgPtr pMsg; int nsSeq; if (pPort!=NULL) { semWait(&pPort->recPortSem); /* wait for message and verify that the port is still allocated */ nsSeq = pPort->nsSeqChg; semSignal(&pPort->recPortSem); if (semWait(&pPort->recRxSem) == SEM_FAILED || pPort->nsSeqChg != nsSeq) { return PORT_FAILED; } semWait(&pPort->recPortSem); /* dequeue first message that is waiting in the port */ pMsg = pPort->pMsgHead; *msg = pMsg->pMsg; *u32Msg = pMsg->u32Msg; if (pPort->pMsgHead == pPort->pMsgTail) /* delete last item */ pPort->pMsgHead = pPort->pMsgTail = (PortMsgPtr)NULL; else pPort->pMsgHead = pMsg->pNext; pMsg->pNext = pPort->pFree; /* return to free list */ pPort->pFree = pMsg; semSignal(&pPort->recTxSem); semSignal(&pPort->recPortSem); return PORT_OK; } return PORT_FAILED; } //************************************************************************************************** // ptSend // sends a Message to this port //************************************************************************************************** int ptSend(PortPtr pPort,void *msg,unsigned long u32Msg) { int nsSeq; PortMsgPtr pFreeNode; if (pPort!=NULL) { semWait(&pPort->recPortSem); /* wait for space and verify port is still allocated */ nsSeq = pPort->nsSeqChg; semSignal(&pPort->recPortSem); if (semWait(&pPort->recTxSem) == SEM_FAILED || pPort->nsSeqChg != nsSeq) { return PORT_FAILED; } if (pPort->pFree == NULL) { return PORT_FAILED; } semWait(&pPort->recPortSem); pFreeNode = pPort->pFree; pPort->pFree = pFreeNode->pNext; pFreeNode->pNext = (PortMsgPtr) NULL; pFreeNode->pMsg = msg; pFreeNode->u32Msg = u32Msg; if (pPort->pMsgTail == (PortMsgPtr) NULL) /* empty queue */ pPort->pMsgTail = pPort->pMsgHead = pFreeNode; else { (pPort->pMsgTail)->pNext = pFreeNode; pPort->pMsgTail = pFreeNode; } semSignal(&pPort->recRxSem); semSignal(&pPort->recPortSem); return PORT_OK; } return PORT_FAILED; }