def __init__(self, name, bits, logger, sriCompare, newSriCallback, sriChangeCallback, maxsize): self.name = name self._portLog = logger self.queue = collections.deque() self._maxSize = maxsize self._breakBlock = False self.stats = InStats(name, bits=bits) self.blocking = False self.sri_cmp = sriCompare self.newSriCallback = newSriCallback self.sriChangeCallback = sriChangeCallback self.sriDict = {} # key=streamID, value=StreamSRI self._dataBufferLock = threading.Lock() self._dataAvailable = threading.Condition(self._dataBufferLock) self._queueAvailable = threading.Condition(self._dataBufferLock) # Backwards-compatibility self.port_lock = self._dataBufferLock # Synchronizes access to the SRIs self._sriUpdateLock = threading.Lock() # Streams that are currently active (map of streamID to stream objects) self._streams = {} self._streamsMutex = threading.Lock() # Streams that have the same stream ID as an active stream, when an # end-of-stream has been queued but not yet read (each entry in the map # is a list of stream objects) self._pendingStreams = {} if self._portLog is None: self._portLog = logging.getLogger("redhawk.bulkio.input." + name) _cmpMsg = "DEFAULT" _newSriMsg = "EMPTY" _sriChangeMsg = "EMPTY" if sriCompare != bulkio.sri.compare: _cmpMsg = "USER_DEFINED" if newSriCallback: _newSriMsg = "USER_DEFINED" if sriChangeCallback: _sriChangeMsg = "USER_DEFINED" if self._portLog: self._portLog.debug( "bulkio::InPort CTOR port:" + str(name) + " Blocking/MaxInputQueueSize " + str(self.blocking) + "/" + str(maxsize) + " SriCompare/NewSriCallback/SriChangeCallback " + _cmpMsg + "/" + _newSriMsg + "/" + _sriChangeMsg)
def __init__(self, name, logger=None, sriCompare=sri.compare, newSriCallback=None, sriChangeCallback=None, maxsize=100, PortTransferType=_TYPE_ ): self.name = name self.logger = logger self.queue = collections.deque() self._maxSize = maxsize self.port_lock = threading.Lock() self._not_full = threading.Condition(self.port_lock) self._not_empty = threading.Condition(self.port_lock) self._breakBlock = False self.stats = InStats(name, PortTransferType) self.blocking = False self.sri_cmp = sriCompare self.newSriCallback = newSriCallback self.sriChangeCallback = sriChangeCallback self.sriDict = {} # key=streamID, value=StreamSRI _cmpMsg = "DEFAULT" _newSriMsg = "EMPTY" _sriChangeMsg = "EMPTY" if sriCompare != sri.compare: _cmpMsg = "USER_DEFINED" if newSriCallback: _newSriMsg = "USER_DEFINED" if sriChangeCallback: _sriChangeMsg = "USER_DEFINED" if self.logger: self.logger.debug( "bulkio::InPort CTOR port:" + str(name) + " Blocking/MaxInputQueueSize " + str(self.blocking) + "/" + str(maxsize) + " SriCompare/NewSriCallback/SriChangeCallback " + _cmpMsg + "/" + _newSriMsg + "/" + _sriChangeMsg );
def __init__(self, name, logger=None, callback = None, sriCmp=None, timeCmp=None, PortType = _TYPE_ ): self.name = name self.logger = logger self.sri = None self.port_lock = threading.Lock() self._attachedStreams = {} # key=attach_id, value = (streamDef, userid) self.stats = InStats(name, PortType ) self.sriDict = {} # key=streamID, value=(StreamSRI, PrecisionUTCTime) self.callback = callback self.sri_cmp = sriCmp self.time_cmp = timeCmp self.sriChanged = False try: self._attach_cb = getattr(callback, "attach") if not callable(self._attach_cb): self._attach_cb = None except AttributeError: self._attach_cb = None try: self._detach_cb = getattr(callback, "detach") if not callable(self._detach_cb): self._attach_cb = None except AttributeError: self._detach_cb = None if self.logger: self.logger.debug("bulkio::InSDDSPort CTOR port:" + str(name) )
def __init__(self, name, logger=None, sriCompare=sri.compare, newSriCallback=None, sriChangeCallback=None, maxsize=100, PortTransferType=_TYPE_): self.name = name self.logger = logger self.queue = collections.deque() self._maxSize = maxsize self.port_lock = threading.Lock() self._not_full = threading.Condition(self.port_lock) self._not_empty = threading.Condition(self.port_lock) self._breakBlock = False self.stats = InStats(name, PortTransferType) self.blocking = False self.sri_cmp = sriCompare self.newSriCallback = newSriCallback self.sriChangeCallback = sriChangeCallback self.sriDict = {} # key=streamID, value=StreamSRI if logger == None: self.logger = logging.getLogger("redhawk.bulkio.input." + name) _cmpMsg = "DEFAULT" _newSriMsg = "EMPTY" _sriChangeMsg = "EMPTY" if sriCompare != sri.compare: _cmpMsg = "USER_DEFINED" if newSriCallback: _newSriMsg = "USER_DEFINED" if sriChangeCallback: _sriChangeMsg = "USER_DEFINED" if self.logger: self.logger.debug("bulkio::InPort CTOR port:" + str(name) + " Blocking/MaxInputQueueSize " + str(self.blocking) + "/" + str(maxsize) + " SriCompare/NewSriCallback/SriChangeCallback " + _cmpMsg + "/" + _newSriMsg + "/" + _sriChangeMsg)
def __init__(self, name, logger=None, attachDetachCallback=None, sriCmp=sri.compare, timeCmp=timestamp.compare, PortType=_TYPE_, newSriCallback=None, sriChangeCallback=None, interface=None): self.name = name self.logger = logger self.port_lock = threading.Lock() self.sri_query_lock = threading.Lock() self._attachedStreams = { } # key=attach_id, value = (streamDef, userid) self.stats = InStats(name, PortType) self.sriDict = {} # key=streamID, value=(StreamSRI, PrecisionUTCTime) self.attachDetachCallback = attachDetachCallback self.newSriCallback = newSriCallback self.sriChangeCallback = sriChangeCallback self.sri_cmp = sriCmp self.time_cmp = timeCmp self.sriChanged = False if not interface: if self.logger: self.logger.error( "InAttachablePort __init__ - an interface must be specified, set to BULKIO.dataSDDS or BULKIO.dataVITA49" ) raise Port.InvalidPort( 1, "InAttachablePort __init__ - an interface must be specified, set to BULKIO.dataSDDS or BULKIO.dataVITA49" ) self.interface = interface # BULKIO port interface (valid options are BULKIO.dataSDDS or BULKIO.dataVITA49) self.setNewAttachDetachListener(attachDetachCallback) if self.logger: self.logger.debug("bulkio::InAttachablePort CTOR port:" + str(self.name) + " using interface " + str(self.interface))
def __init__(self, name, logger=None, attachDetachCallback=None, sriCmp=sri.compare, timeCmp=timestamp.compare, PortType = _TYPE_, newSriCallback=None, sriChangeCallback=None,interface=None): self.name = name self.logger = logger self.port_lock = threading.Lock() self.sri_query_lock = threading.Lock() self._attachedStreams = {} # key=attach_id, value = (streamDef, userid) self.stats = InStats(name, PortType ) self.sriDict = {} # key=streamID, value=(StreamSRI, PrecisionUTCTime) self.attachDetachCallback = attachDetachCallback self.newSriCallback = newSriCallback self.sriChangeCallback = sriChangeCallback self.sri_cmp = sriCmp self.time_cmp = timeCmp self.sriChanged = False if not interface: if self.logger: self.logger.error("InAttachablePort __init__ - an interface must be specified, set to BULKIO.dataSDDS or BULKIO.dataVITA49") raise Port.InvalidPort(1, "InAttachablePort __init__ - an interface must be specified, set to BULKIO.dataSDDS or BULKIO.dataVITA49") self.interface=interface # BULKIO port interface (valid options are BULKIO.dataSDDS or BULKIO.dataVITA49) self.setNewAttachDetachListener(attachDetachCallback) if self.logger: self.logger.debug("bulkio::InAttachablePort CTOR port:" + str(self.name) + " using interface " + str(self.interface))
class InAttachablePort: _TYPE_ = 'b' def __init__(self, name, logger=None, attachDetachCallback=None, sriCmp=sri.compare, timeCmp=timestamp.compare, PortType=_TYPE_, newSriCallback=None, sriChangeCallback=None, interface=None): self.name = name self.logger = logger self.port_lock = threading.Lock() self.sri_query_lock = threading.Lock() self._attachedStreams = { } # key=attach_id, value = (streamDef, userid) self.stats = InStats(name, PortType) self.sriDict = {} # key=streamID, value=(StreamSRI, PrecisionUTCTime) self.attachDetachCallback = attachDetachCallback self.newSriCallback = newSriCallback self.sriChangeCallback = sriChangeCallback self.sri_cmp = sriCmp self.time_cmp = timeCmp self.sriChanged = False if not interface: if self.logger: self.logger.error( "InAttachablePort __init__ - an interface must be specified, set to BULKIO.dataSDDS or BULKIO.dataVITA49" ) raise Port.InvalidPort( 1, "InAttachablePort __init__ - an interface must be specified, set to BULKIO.dataSDDS or BULKIO.dataVITA49" ) self.interface = interface # BULKIO port interface (valid options are BULKIO.dataSDDS or BULKIO.dataVITA49) self.setNewAttachDetachListener(attachDetachCallback) if self.logger: self.logger.debug("bulkio::InAttachablePort CTOR port:" + str(self.name) + " using interface " + str(self.interface)) def setNewAttachDetachListener(self, attachDetachCallback): self.port_lock.acquire() try: self.attachDetachCallback = attachDetachCallback # Set _attach_cb try: self._attach_cb = getattr(attachDetachCallback, "attach") if not callable(self._attach_cb): self._attach_cb = None except AttributeError: self._attach_cb = None # Set _detach_cb try: self._detach_cb = getattr(attachDetachCallback, "detach") if not callable(self._detach_cb): self._detach_cb = None except AttributeError: self._detach_cb = None finally: self.port_lock.release() def setNewSriListener(self, newSriCallback): self.port_lock.acquire() try: self.newSriCallback = newSriCallback finally: self.port_lock.release() def setSriChangeListener(self, sriChangeCallback): self.port_lock.acquire() try: self.sriChangeCallback = sriChangeCallback finally: self.port_lock.release() def setBitSize(self, bitSize): self.stats.setBitSize(bitSize) def enableStats(self, enabled): self.stats.setEnabled(enabled) def updateStats(self, elementsReceived, queueSize, streamID): self.port_lock.acquire() try: self.stats.update(elementsReceived, queueSize, streamID) finally: self.port_lock.release() def _get_statistics(self): self.port_lock.acquire() try: recStat = self.stats.retrieve() finally: self.port_lock.release() return recStat def _get_state(self): self.port_lock.acquire() try: numAttachedStreams = len(self._attachedStreams.values()) finally: self.port_lock.release() if numAttachedStreams == 0: return BULKIO.IDLE # default behavior is to limit to one connection elif numAttachedStreams == 1: return BULKIO.BUSY else: return BULKIO.ACTIVE def _get_attachedSRIs(self): sris = [] self.sri_query_lock.acquire() try: for entry in self.sriDict: # First value of sriDict entry is the StreamSRI object sris.append(copy.deepcopy(self.sriDict[entry][0])) finally: self.sri_query_lock.release() return sris def _get_usageState(self): self.port_lock.acquire() try: numAttachedStreams = len(self._attachedStreams.values()) finally: self.port_lock.release() if numAttachedStreams == 0: return self.interface.IDLE # default behavior is to limit to one connection elif numAttachedStreams == 1: return self.interface.BUSY else: return self.interface.ACTIVE def _get_attachedStreams(self): return [x[0] for x in self._attachedStreams.values()] def _get_attachmentIds(self): return self._attachedStreams.keys() def attach(self, streamDef, userid): if self.logger: self.logger.trace("bulkio::InAttachablePort attach ENTER (port=" + str(self.name) + ")") self.logger.debug( "InAttachablePort.attach() - ATTACH REQUEST, STREAM/USER" + str(streamDef) + '/' + str(userid)) attachId = None self.port_lock.acquire() try: try: if self.logger: self.logger.debug( "InAttachablePort.attach() - CALLING ATTACH CALLBACK, STREAM/USER" + str(streamDef) + '/' + str(userid)) if self._attach_cb != None: attachId = self._attach_cb(streamDef, userid) except Exception, e: if self.logger: self.logger.error( "InAttachablePort.attach() - ATTACH CALLBACK EXCEPTION : " + str(e) + " STREAM/USER" + str(streamDef) + '/' + str(userid)) raise self.interface.AttachError(str(e)) if attachId == None: attachId = str(uuid.uuid4()) self._attachedStreams[attachId] = (streamDef, userid) finally:
class InPort: DATA_BUFFER = 0 TIME_STAMP = 1 END_OF_STREAM = 2 STREAM_ID = 3 SRI = 4 SRI_CHG = 5 QUEUE_FLUSH = 6 _TYPE_ = 'c' # Backwards-compatible DataTransfer type can still be unpacked like a tuple # but also supports named fields DataTransfer = collections.namedtuple( 'DataTransfer', 'dataBuffer T EOS streamID SRI sriChanged inputQueueFlushed') def __init__(self, name, logger=None, sriCompare=sri.compare, newSriCallback=None, sriChangeCallback=None, maxsize=100, PortTransferType=_TYPE_): self.name = name self.logger = logger self.queue = collections.deque() self._maxSize = maxsize self.port_lock = threading.Lock() self._not_full = threading.Condition(self.port_lock) self._not_empty = threading.Condition(self.port_lock) self._breakBlock = False self.stats = InStats(name, PortTransferType) self.blocking = False self.sri_cmp = sriCompare self.newSriCallback = newSriCallback self.sriChangeCallback = sriChangeCallback self.sriDict = {} # key=streamID, value=StreamSRI if logger == None: self.logger = logging.getLogger("redhawk.bulkio.input." + name) _cmpMsg = "DEFAULT" _newSriMsg = "EMPTY" _sriChangeMsg = "EMPTY" if sriCompare != sri.compare: _cmpMsg = "USER_DEFINED" if newSriCallback: _newSriMsg = "USER_DEFINED" if sriChangeCallback: _sriChangeMsg = "USER_DEFINED" if self.logger: self.logger.debug("bulkio::InPort CTOR port:" + str(name) + " Blocking/MaxInputQueueSize " + str(self.blocking) + "/" + str(maxsize) + " SriCompare/NewSriCallback/SriChangeCallback " + _cmpMsg + "/" + _newSriMsg + "/" + _sriChangeMsg) def setNewSriListener(self, newSriCallback): self.port_lock.acquire() try: self.newSriCallback = newSriCallback finally: self.port_lock.release() def setSriChangeListener(self, sriChangeCallback): self.port_lock.acquire() try: self.sriChangeCallback = sriChangeCallback finally: self.port_lock.release() def enableStats(self, enabled): self.stats.setEnabled(enabled) def _get_statistics(self): self.port_lock.acquire() try: return self.stats.retrieve() finally: self.port_lock.release() def _get_state(self): self.port_lock.acquire() try: if len(self.queue) == 0: return BULKIO.IDLE elif len(self.queue) == self._maxSize: return BULKIO.BUSY else: return BULKIO.ACTIVE finally: self.port_lock.release() def _get_activeSRIs(self): self.port_lock.acquire() try: return [self.sriDict[entry][0] for entry in self.sriDict] finally: self.port_lock.release() def getCurrentQueueDepth(self): self.port_lock.acquire() try: return len(self.queue) finally: self.port_lock.release() def getMaxQueueDepth(self): self.port_lock.acquire() try: return self._maxSize finally: self.port_lock.release() #set to -1 for infinite queue def setMaxQueueDepth(self, newDepth): self.port_lock.acquire() try: self._maxSize = int(newDepth) finally: self.port_lock.release() def unblock(self): self.port_lock.acquire() try: self._breakBlock = False finally: self.port_lock.release() def block(self): self.port_lock.acquire() try: self._breakBlock = True self._not_empty.notifyAll() finally: self.port_lock.release() # Provide standard interface for start/stop startPort = unblock stopPort = block def pushSRI(self, H): if self.logger: self.logger.trace("bulkio::InPort pushSRI ENTER (port=" + str(self.name) + ")") self.port_lock.acquire() try: if H.streamID not in self.sriDict: sriChanged = True if self.logger: self.logger.debug("pushSRI PORT:" + str(self.name) + " NEW SRI:" + str(H.streamID)) if self.newSriCallback: self.newSriCallback(H) self.sriDict[H.streamID] = (copy.deepcopy(H), True) if H.blocking: self.blocking = True else: sri, sriChanged = self.sriDict[H.streamID] if self.sri_cmp: if not self.sri_cmp(sri, H): self.sriDict[H.streamID] = (copy.deepcopy(H), True) if H.blocking: self.blocking = True if self.sriChangeCallback: self.sriChangeCallback(H) finally: self.port_lock.release() if self.logger: self.logger.trace("bulkio::InPort pushSRI EXIT (port=" + str(self.name) + ")") def pushPacket(self, data, T, EOS, streamID): if self.logger: self.logger.trace("bulkio::InPort pushPacket ENTER (port=" + str(self.name) + ")") self.port_lock.acquire() try: if self._maxSize == 0: if self.logger: self.logger.trace("bulkio::InPort pushPacket EXIT (port=" + str(self.name) + ")") return if self.sriDict.has_key(streamID): sri, sriChanged = self.sriDict[streamID] if EOS: self.sriDict[streamID] = (sri, True) else: self.sriDict[streamID] = (sri, False) else: # Create a default SRI for the stream ID if self.logger: self.logger.warn( "bulkio::InPort pushPacket received data for stream '%s' with no SRI", streamID) sri = BULKIO.StreamSRI(1, 0.0, 1.0, 1, 0, 0.0, 0.0, 0, 0, streamID, False, []) if self.newSriCallback: self.newSriCallback(sri) self.sriDict[streamID] = (sri, False) sriChanged = True queueFlushed = False flagEOS = False if self.blocking: while len(self.queue) >= self._maxSize: self._not_full.wait() else: # Flush the queue if not using infinite queue (maxSize == -1), blocking is not on, and # current length of queue is >= maxSize if len(self.queue) >= self._maxSize and self._maxSize > -1: queueFlushed = True if self.logger: self.logger.debug( "bulkio::InPort pushPacket PURGE INPUT QUEUE (SIZE=%d)", len(self.queue)) foundSRIChanged = False for data, T, EOS, streamID, sri, sriChangeHappened, inputQueueFlushed in self.queue: if foundSRIChanged and flagEOS: break if sriChangeHappened: sriChanged = True foundSRIChanged = True if EOS: flagEOS = True self.queue.clear() if flagEOS: EOS = True packet = (data, T, EOS, streamID, copy.deepcopy(sri), sriChanged, queueFlushed) self.stats.update(self._packetSize(data), float(len(self.queue)) / float(self._maxSize), EOS, streamID, queueFlushed) if self.logger: self.logger.trace( "bulkio::InPort pushPacket NEW Packet (QUEUE=%d)", len(self.queue)) self.queue.append(packet) # Let one waiting getPacket call know there is a packet available self._not_empty.notify() finally: self.port_lock.release() if self.logger: self.logger.trace("bulkio::InPort pushPacket EXIT (port=" + str(self.name) + ")") def getPacket(self, timeout=const.NON_BLOCKING): if self.logger: self.logger.trace("bulkio::InPort getPacket ENTER (port=" + str(self.name) + ")") self.port_lock.acquire() try: if timeout < 0.0: while not self.queue and not self._breakBlock: self._not_empty.wait() elif timeout > 0.0: # Determine the absolute time at which the timeout expires end = time.time() + timeout while not self.queue and not self._breakBlock: # Calculate remaining timeout remain = end - time.time() if remain <= 0.0: break self._not_empty.wait(remain) if not self.queue: return InPort.DataTransfer(None, None, None, None, None, None, None) data, T, EOS, streamID, sri, sriChanged, inputQueueFlushed = self.queue.popleft( ) # Let one waiting pushPacket call know there is space available self._not_full.notify() if EOS: if self.sriDict.has_key(streamID): (a, b) = self.sriDict.pop(streamID) if sri.blocking: stillBlock = False for _sri, _sriChanged in self.sriDict.values(): if _sri.blocking: stillBlock = True break if not stillBlock: self.blocking = False return InPort.DataTransfer(data, T, EOS, streamID, sri, sriChanged, inputQueueFlushed) finally: self.port_lock.release() if self.logger: self.logger.trace("bulkio::InPort getPacket EXIT (port=" + str(self.name) + ")") def _packetSize(self, data): return len(data)
class InPort(object): DATA_BUFFER = 0 TIME_STAMP = 1 END_OF_STREAM = 2 STREAM_ID = 3 SRI = 4 SRI_CHG = 5 QUEUE_FLUSH = 6 # Backwards-compatible DataTransfer type can still be unpacked like a tuple # but also supports named fields DataTransfer = collections.namedtuple( 'DataTransfer', 'dataBuffer T EOS streamID SRI sriChanged inputQueueFlushed') class Packet(object): __slots__ = ('buffer', 'T', 'EOS', 'SRI', 'sriChanged', 'inputQueueFlushed') def __init__(self, data, T, EOS, SRI, sriChanged, inputQueueFlushed): self.buffer = data self.T = T self.EOS = EOS self.SRI = SRI self.sriChanged = sriChanged self.inputQueueFlushed = inputQueueFlushed @property def streamID(self): return self.SRI.streamID def __init__(self, name, bits, logger, sriCompare, newSriCallback, sriChangeCallback, maxsize): self.name = name self._portLog = logger self.queue = collections.deque() self._maxSize = maxsize self._breakBlock = False self.stats = InStats(name, bits=bits) self.blocking = False self.sri_cmp = sriCompare self.newSriCallback = newSriCallback self.sriChangeCallback = sriChangeCallback self.sriDict = {} # key=streamID, value=StreamSRI self._dataBufferLock = threading.Lock() self._dataAvailable = threading.Condition(self._dataBufferLock) self._queueAvailable = threading.Condition(self._dataBufferLock) # Backwards-compatibility self.port_lock = self._dataBufferLock # Synchronizes access to the SRIs self._sriUpdateLock = threading.Lock() # Streams that are currently active (map of streamID to stream objects) self._streams = {} self._streamsMutex = threading.Lock() # Streams that have the same stream ID as an active stream, when an # end-of-stream has been queued but not yet read (each entry in the map # is a list of stream objects) self._pendingStreams = {} if self._portLog is None: self._portLog = logging.getLogger("redhawk.bulkio.input." + name) _cmpMsg = "DEFAULT" _newSriMsg = "EMPTY" _sriChangeMsg = "EMPTY" if sriCompare != bulkio.sri.compare: _cmpMsg = "USER_DEFINED" if newSriCallback: _newSriMsg = "USER_DEFINED" if sriChangeCallback: _sriChangeMsg = "USER_DEFINED" if self._portLog: self._portLog.debug( "bulkio::InPort CTOR port:" + str(name) + " Blocking/MaxInputQueueSize " + str(self.blocking) + "/" + str(maxsize) + " SriCompare/NewSriCallback/SriChangeCallback " + _cmpMsg + "/" + _newSriMsg + "/" + _sriChangeMsg) @notification def streamAdded(self, stream): """ A new input stream was received. Args: stream: New input stream. """ pass def addStreamListener(self, callback): """ Registers a callback for new streams. When a new input stream is created, `callback` is called with the new input stream as its argument. Args: callback: Callable object that takes one argument. """ self.streamAdded.addListener(callback) def removeStreamListener(self, callback): """ Unregisters a callback for new streams. Args: callback: Previous registered callable object. """ self.streamAdded.removeListener(callback) def setNewSriListener(self, newSriCallback): with self._sriUpdateLock: self.newSriCallback = newSriCallback def setSriChangeListener(self, sriChangeCallback): with self._sriUpdateLock: self.sriChangeCallback = sriChangeCallback def getLogger(self): return self._portLog def setLogger(self, logger): self._portLog = logger def enableStats(self, enabled): self.stats.setEnabled(enabled) def _get_statistics(self): with self._dataBufferLock: return self.stats.retrieve() def _get_state(self): with self._dataBufferLock: if len(self.queue) == 0: return BULKIO.IDLE elif len(self.queue) == self._maxSize: return BULKIO.BUSY else: return BULKIO.ACTIVE def _get_activeSRIs(self): with self._sriUpdateLock: return [self.sriDict[entry][0] for entry in self.sriDict] def getCurrentQueueDepth(self): with self._dataBufferLock: return len(self.queue) def getMaxQueueDepth(self): with self._dataBufferLock: return self._maxSize #set to -1 for infinite queue def setMaxQueueDepth(self, newDepth): with self._dataBufferLock: self._maxSize = int(newDepth) def unblock(self): with self._dataBufferLock: self._breakBlock = False def block(self): # Interrupt packet queue operations with self._dataBufferLock: self._breakBlock = True self._dataAvailable.notifyAll() self._queueAvailable.notifyAll() # Provide standard interface for start/stop startPort = unblock stopPort = block def pushSRI(self, H): if self._portLog: self._portLog.trace("bulkio::InPort pushSRI ENTER (port=" + str(self.name) + ")") # If the updated SRI is blocking, ensure port blocking mode is set if H.blocking: with self._dataBufferLock: self.blocking = True with self._sriUpdateLock: if H.streamID not in self.sriDict: new_stream = True sri_changed = True if self._portLog: self._portLog.debug("pushSRI PORT:" + str(self.name) + " NEW SRI:" + str(H.streamID)) if self.newSriCallback: self.newSriCallback(H) else: new_stream = False sri, sri_changed = self.sriDict[H.streamID] if self.sri_cmp and not self.sri_cmp(sri, H): sri_changed = True if self.sriChangeCallback: self.sriChangeCallback(H) if sri_changed: self.sriDict[H.streamID] = (copy.deepcopy(H), True) if new_stream: self._createStream(H) if self._portLog: self._portLog.trace("bulkio::InPort pushSRI EXIT (port=" + str(self.name) + ")") def getPacket(self, timeout=NON_BLOCKING): if self._portLog: self._portLog.trace("bulkio::InPort getPacket ENTER (port=" + str(self.name) + ")") packet = self._nextPacket(timeout) if not packet: # Return an empty packet instead of None for backwards # compatibility packet = InPort.DataTransfer(None, None, None, None, None, None, None) else: packet = InPort.DataTransfer(packet.buffer, packet.T, packet.EOS, packet.streamID, packet.SRI, packet.sriChanged, packet.inputQueueFlushed) if self._portLog: self._portLog.trace("bulkio::InPort getPacket EXIT (port=" + str(self.name) + ")") return packet def getCurrentStream(self, timeout=BLOCKING): """ Gets the stream that should be used for the next basic read. Args: timeout: Seconds to wait for a stream; a negative value waits indefinitely. Returns: InputStream ready for reading on success. None if timeout expires or port is stopped. """ # Prefer a stream that already has buffered data with self._streamsMutex: for stream in self._streams.itervalues(): if stream._hasBufferedData(): return stream # Otherwise, return the stream that owns the next packet on the queue, # potentially waiting for one to be received with self._dataBufferLock: packet = self._peekPacket(timeout) if packet: return self.getStream(packet.streamID) else: return None def getStream(self, streamID): """ Gets the active stream with the given stream ID. Args: streamID: Stream identifier. Returns: Input stream for `streamID` if it exists. None if no such stream ID exits. """ with self._streamsMutex: return self._streams.get(streamID, None) def getStreams(self): """ Gets the current set of active streams. Returns: List of input streams. """ with self._streamsMutex: return self._streams.values() def pushPacket(self, data, T, EOS, streamID): self._portLog.trace("pushPacket ENTER") self._queuePacket(data, T, EOS, streamID) self._portLog.trace("pushPacket EXIT") def _queuePacket(self, data, T, EOS, streamID): # Discard packets for disabled streams if not self._acceptPacket(streamID, EOS): if EOS and self._disableBlockingOnEOS(streamID): # If this was the only blocking stream, turn off blocking with self._dataBufferLock: self.blocking = False return # Discard empty packets if EOS is not set, as there is no useful data or # metadata to be had--since T applies to the 1st sample (which does not # exist), all we have is a stream ID if not data and not EOS: return if self._maxSize == 0: return new_stream = False with self._sriUpdateLock: sri, sri_changed = self.sriDict.get(streamID, (None, True)) if not sri: # Unknown stream ID, register a new default SRI following the # logic in pushSRI self._portLog.warn("received data for stream '%s' with no SRI", streamID) new_stream = True sri = bulkio.sri.create(streamID) if self.newSriCallback: self.newSriCallback(sri) # Acknowledge SRI change was received; in the unknown stream case, # this also records it in the map self.sriDict[streamID] = (sri, False) # If a new stream needs to be created for an unrecognized stream ID, do # it here after the lock is released if new_stream: self._createStream(sri) with self._dataBufferLock: queue_flushed = False if self.blocking: while self._maxSize >= 0 and len(self.queue) >= self._maxSize: self._queueAvailable.wait() else: # Flush the queue if not using infinite queue (maxSize < 0), # blocking is not on, and queue is currently full if len(self.queue) >= self._maxSize and self._maxSize > -1: queue_flushed = True self._portLog.debug( "bulkio::InPort pushPacket PURGE INPUT QUEUE (SIZE=%d)", len(self.queue)) # Need to hold the SRI mutex while flushing the queue # because it may update SRI change state with self._sriUpdateLock: self._flushQueue() # Update the SRI change flag for this stream, which may # have been modified during the queue flush sri, sri_changed = self.sriDict[streamID] self.sriDict[streamID] = (sri, False) self._portLog.trace( "bulkio::InPort pushPacket NEW Packet (QUEUE=%d)", len(self.queue)) self.stats.update(self._packetSize(data), float(len(self.queue)) / float(self._maxSize), EOS, streamID, queue_flushed) packet = InPort.Packet(data, T, EOS, sri, sri_changed, False) self.queue.append(packet) with self._sriUpdateLock: if EOS: sri, _ = self.sriDict.pop(streamID, (None, None)) # If a flush occurred, always set the flag on the first packet; # this may not be the packet that was just inserted if there were # any EOS packets on the queue if queue_flushed: self.queue[0].inputQueueFlushed = True # Let one waiting getPacket call know there is a packet available self._dataAvailable.notify() def _flushQueue(self): # Prerequisite: caller holds self._dataBufferLock and # self._sriUpdateLock sri_changed = set() saved_packets = collections.deque() for packet in self.queue: if packet.EOS: # Remove the SRI change flag for this stream, as further SRI # changes apply to a different stream; set the SRI change flag # for the EOS packet if there was one for this stream earlier # in the queue if packet.streamID in sri_changed: packet.sriChanged = True sri_changed.discard(packet.streamID) # Discard data (using a 0-length slice works with any sequence) # and preserve the EOS packet packet.buffer = packet.buffer[:0] packet.inputQueueFlushed = False saved_packets.append(packet) elif packet.sriChanged: sri_changed.add(packet.streamID) self.queue = saved_packets for stream_id in sri_changed: # It should be safe to assume that an entry exists for the stream # ID, but just in case, use get instead of operator[] sri, _ = self.sriDict.get(stream_id, (None, None)) if sri is not None: self.sriDict[stream_id] = (sri, True) def _acceptPacket(self, streamID, EOS): # Acquire streamsMutex for the duration of this call to ensure that # end-of-stream is handled atomically for disabled streams with self._streamsMutex: # Find the current stream for the stream ID and check whether it's # enabled stream = self._streams.get(streamID, None) if not stream or stream.enabled: return True # If there's a pending stream, the packet is designated for that pending_streams = self._pendingStreams.get(streamID, []) if pending_streams: return True new_stream = None if EOS: # Acknowledge the end-of-stream by removing the disabled stream # before discarding the packet self._portLog.debug("Removing stream '%s'", streamID) stream._close() del self._streams[streamID] if pending_streams: self._portLog.debug("Moving pending stream '%s' to active", streamID) new_stream = pending_streams.pop(0) self._streams[streamID] = new_stream # If a pending stream became active, notify listeners if new_stream: self.streamAdded(new_stream) return False def _peekPacket(self, timeout): # Requires self._dataBufferLock to_time = time.time() + timeout while not self._breakBlock and not self.queue: if timeout == 0.0: break elif timeout > 0: wait_time = to_time - time.time() if wait_time <= 0.0: break self._dataAvailable.wait(wait_time) else: self._dataAvailable.wait() if self._breakBlock or not self.queue: return None else: return self.queue[0] def _nextPacket(self, timeout, streamID=None): if self._breakBlock: return None to_time = time.time() + timeout with self._dataBufferLock: packet = self._fetchPacket(streamID) while not packet: if timeout == 0.0: return None elif timeout > 0.0: wait_time = to_time - time.time() if wait_time <= 0.0: return None self._dataAvailable.wait(wait_time) else: self._dataAvailable.wait() if self._breakBlock: return None packet = self._fetchPacket(streamID) #LOG_TRACE(logger, "InPort::nextPacket PORT:" << name << " (QUEUE="<< packetQueue.size() << ")"); self._queueAvailable.notify() if packet and packet.EOS and self._disableBlockingOnEOS( packet.streamID): with self._dataBufferLock: self.blocking = False return packet def _fetchPacket(self, streamID): # Prerequisite: caller holds self._dataBufferLock if not streamID: if not self.queue: return None return self.queue.popleft() for index in xrange(len(self.queue)): if self.queue[index].streamID == streamID: packet = self.queue[index] del self.queue[index] return packet return None def _disableBlockingOnEOS(self, streamID): with self._sriUpdateLock: for hdr, _ in self.sriDict.itervalues(): if hdr.blocking: return False return True def _createStream(self, sri): with self._streamsMutex: if sri.streamID in self._streams: # An active stream has the same stream ID; add this new stream # to the pending list self._portLog.debug("Creating pending stream '%s'", sri.streamID) if not sri.streamID in self._pendingStreams: self._pendingStreams[sri.streamID] = [] self._pendingStreams[sri.streamID].append( self._streamType(sri, self)) stream = None else: # New stream self._portLog.debug("Creating new stream '%s'", sri.streamID) stream = self._streamType(sri, self) self._streams[sri.streamID] = stream # Notify stream listeners (without the mutex held) if stream: self.streamAdded(stream) def _removeStream(self, streamID): self._portLog.debug("Removing stream '%s'", streamID) new_stream = None with self._streamsMutex: # Remove the current stream, and if there's a pending stream with # the same stream ID, move it to the active list self._streams.pop(streamID, None) pending_streams = self._pendingStreams.get(streamID, []) if pending_streams: self._portLog.debug("Moving pending stream '%s' active", streamID) new_stream = pending_streams.pop(0) self._streams[streamID] = new_stream if new_stream: self.streamAdded(new_stream) def _discardPacketsForStream(self, streamID): with self._dataBufferLock: self.queue = [ pkt for pkt in self.queue if pkt.streamID != streamID ] def _streamType(self, sri, port): return InputStream(sri, port) def _packetSize(self, data): return len(data) def _reformat(self, data): # Default behavior: no data reformatting is required return data
class InSDDSPort(BULKIO__POA.dataSDDS): _TYPE_='b' def __init__(self, name, logger=None, callback = None, sriCmp=None, timeCmp=None, PortType = _TYPE_ ): self.name = name self.logger = logger self.sri = None self.port_lock = threading.Lock() self._attachedStreams = {} # key=attach_id, value = (streamDef, userid) self.stats = InStats(name, PortType ) self.sriDict = {} # key=streamID, value=(StreamSRI, PrecisionUTCTime) self.callback = callback self.sri_cmp = sriCmp self.time_cmp = timeCmp self.sriChanged = False try: self._attach_cb = getattr(callback, "attach") if not callable(self._attach_cb): self._attach_cb = None except AttributeError: self._attach_cb = None try: self._detach_cb = getattr(callback, "detach") if not callable(self._detach_cb): self._attach_cb = None except AttributeError: self._detach_cb = None if self.logger: self.logger.debug("bulkio::InSDDSPort CTOR port:" + str(name) ) def setBitSize(self, bitSize): self.stats.setBitSize(bitSize) def enableStats(self, enabled): self.stats.setEnabled(enabled) def updateStats(self, elementsReceived, queueSize, streamID): self.port_lock.acquire() self.stats.update(elementsReceived, queueSize, streamID) self.port_lock.release() def _get_statistics(self): self.port_lock.acquire() recStat = self.stats.retrieve() self.port_lock.release() return recStat def _get_state(self): if len(self._attachedStreams.values()) == 0: return BULKIO.IDLE # default behavior is to limit to one connection elif len(self._attachedStreams.values()) == 1: return BULKIO.BUSY else: return BULKIO.ACTIVE def _get_attachedSRIs(self): sris = [] for entry in self.sriDict: sris.append(copy.deepcopy(self.sriDict[entry])) self.port_lock.release() return sris def _get_usageState(self): if len(self._attachedStreams.values()) == 0: return BULKIO.dataSDDS.IDLE # default behavior is to limit to one connection elif len(self._attachedStreams.values()) == 1: return BULKIO.dataSDDS.BUSY else: return BULKIO.dataSDDS.ACTIVE def _get_attachedStreams(self): return [x[0] for x in self._attachedStreams.values()] def _get_attachmentIds(self): return self._attachedStreams.keys() def attach(self, streamDef, userid): if self.logger: self.logger.trace("bulkio::InSDDSPort attach ENTER (port=" + str(name) +")" ) self.logger.debug("SDDS PORT, ATTACH REQUEST, STREAM/USER" + str(streamDef) + '/' + str(userid)) if self._get_usageState() == BULKIO.dataSDDS.BUSY: if self.logger: self.logger.error("SDDS PORT, No Capacity to satisfy request. STREAM/USER" + str(streamDef) + '/' + str(userid)) raise BULKIO.dataSDDS.AttachError("No capacity") # # Allocate capacities here if applicable # # The attachment succeeded so generate a attachId attachId = None try: if self.logger: self.logger.debug("SDDS PORT: CALLING ATTACH CALLBACK, STREAM/USER" + str(streamDef) + '/' + str(userid) ) if self._attach_cb != None: attachId = self._attach_cb(streamDef, userid) except Exception, e: if self.logger: self.logger.error("SDDS PORT: ATTACH CALLBACK EXCEPTION : " + str(e) + " STREAM/USER" + str(streamDef) + '/' + str(userid) ) raise BULKIO.dataSDDS.AttachError(str(e)) if attachId == None: attachId = str(uuid.uuid4()) self._attachedStreams[attachId] = (streamDef, userid) if self.logger: self.logger.debug("SDDS PORT, ATTACH COMPLETED, ID:" + str(attachId) + " STREAM/USER: "******"bulkio::InSDDSPort attach EXIT (port=" + str(name) +")" ) return attachId
class InPort: DATA_BUFFER=0 TIME_STAMP=1 END_OF_STREAM=2 STREAM_ID=3 SRI=4 SRI_CHG=5 QUEUE_FLUSH=6 _TYPE_ = 'c' def __init__(self, name, logger=None, sriCompare=sri.compare, newStreamCallback=None, maxsize=100, PortTransferType=_TYPE_ ): self.name = name self.logger = logger self.queue = Queue.Queue(maxsize) self.port_lock = threading.Lock() self.stats = InStats(name, PortTransferType) self.blocking = False self.sri_cmp = sriCompare self.newStreamCallback = newStreamCallback self.sriDict = {} # key=streamID, value=StreamSRI _cmpMsg = "DEFAULT" _sriMsg = "EMPTY" if sriCompare != sri.compare: _cmpMsg = "USER_DEFINED" if newStreamCallback: _sriMsg = "USER_DEFINED" if self.logger: self.logger.debug( "bulkio::InPort CTOR port:" + str(name) + " Blocking/MaxInputQueueSize " + str(self.blocking) + "/" + str(maxsize) + " SriCompare/NewStreamCallback " + _cmpMsg + "/" + _sriMsg ); def setNewStreamListener(self, newStreamCallback): self.port_lock.acquire() self.newStreamCallback = newStreamCallback self.port_lock.release() def enableStats(self, enabled): self.stats.setEnabled(enabled) def _get_statistics(self): self.port_lock.acquire() recStat = self.stats.retrieve() self.port_lock.release() return recStat def _get_state(self): self.port_lock.acquire() if self.queue.full(): self.port_lock.release() return BULKIO.BUSY elif self.queue.empty(): self.port_lock.release() return BULKIO.IDLE else: self.port_lock.release() return BULKIO.ACTIVE self.port_lock.release() return BULKIO.BUSY def _get_activeSRIs(self): self.port_lock.acquire() activeSRIs = [self.sriDict[entry][0] for entry in self.sriDict] self.port_lock.release() return activeSRIs def getCurrentQueueDepth(self): self.port_lock.acquire() depth = self.queue.qsize() self.port_lock.release() return depth def getMaxQueueDepth(self): self.port_lock.acquire() depth = self.queue.maxsize self.port_lock.release() return depth #set to -1 for infinite queue def setMaxQueueDepth(self, newDepth): self.port_lock.acquire() self.queue.maxsize = int(newDepth) self.port_lock.release() def pushSRI(self, H): if self.logger: self.logger.trace( "bulkio::InPort pushSRI ENTER (port=" + str(name) +")" ) self.port_lock.acquire() if H.streamID not in self.sriDict: if self.logger: self.logger.debug( "pushSRI PORT:" + str(name) + " NEW SRI:" + str(H.streamID) ) if self.newStreamCallback: self.newStreamCallback( H ) self.sriDict[H.streamID] = (copy.deepcopy(H), True) if H.blocking: self.blocking = True else: sri, sriChanged = self.sriDict[H.streamID] if self.sri_cmp: if not self.sri_cmp(sri, H): self.sriDict[H.streamID] = (copy.deepcopy(H), True) if H.blocking: self.blocking = True self.port_lock.release() if self.logger: self.logger.trace( "bulkio::InPort pushSRI EXIT (port=" + str(name) +")" ) def pushPacket(self, data, T, EOS, streamID): if self.logger: self.logger.trace( "bulkio::InPort pushPacket ENTER (port=" + str(name) +")" ) self.port_lock.acquire() if self.queue.maxsize == 0: self.port_lock.release() if self.logger: self.logger.trace( "bulkio::InPort pushPacket EXIT (port=" + str(name) +")" ) return packet = None try: sri = BULKIO.StreamSRI(1, 0.0, 1.0, 1, 0, 0.0, 0.0, 0, 0, streamID, False, []) sriChanged = False if self.sriDict.has_key(streamID): sri, sriChanged = self.sriDict[streamID] self.sriDict[streamID] = (sri, False) if self.blocking: packet = (data, T, EOS, streamID, copy.deepcopy(sri), sriChanged, False) self.stats.update(len(data), float(self.queue.qsize()) / float(self.queue.maxsize), streamID, False) self.queue.put(packet) else: sriChangedHappened = False if self.queue.full(): try: if self.logger: self.logger.debug( "bulkio::InPort pushPacket PURGE INPUT QUEUE (SIZE=" + str(len(self.queue.queue)) + ")" ) self.queue.mutex.acquire() while len(self.queue.queue) != 0: data, T, EOS, streamID, sri, sriChanged, inputQueueFlushed = self.queue.queue.pop() if sriChanged: sriChangedHappened = True self.queue.queue.clear() self.queue.mutex.release() except Queue.Empty: self.queue.mutex.release() if sriChangedHappened: sriChanged = True packet = (data, T, EOS, streamID, copy.deepcopy(sri), sriChanged, True) self.stats.update(len(data), float(self.queue.qsize()) / float(self.queue.maxsize), EOS, streamID, True) else: packet = (data, T, EOS, streamID, copy.deepcopy(sri), sriChanged, False) self.stats.update(len(data), float(self.queue.qsize()) / float(self.queue.maxsize), EOS, streamID, False) if self.logger: self.logger.trace( "bulkio::InPort pushPacket NEW Packet (QUEUE=" + str(len(self.queue.queue)) + ")" ) self.queue.put(packet) finally: self.port_lock.release() if self.logger: self.logger.trace( "bulkio::InPort pushPacket EXIT (port=" + str(name) +")" ) def getPacket(self): if self.logger: self.logger.trace( "bulkio::InPort getPacket ENTER (port=" + str(name) +")" ) try: data, T, EOS, streamID, sri, sriChanged, inputQueueFlushed = self.queue.get(block=False) if EOS: if self.sriDict.has_key(streamID): (a,b) = self.sriDict.pop(streamID) if sri.blocking: stillBlock = False for _sri, _sriChanged in self.sriDict.values(): if _sri.blocking: stillBlock = True break if not stillBlock: self.blocking = False return (data, T, EOS, streamID, sri, sriChanged, inputQueueFlushed) except Queue.Empty: return None, None, None, None, None, None, None if self.logger: self.logger.trace( "bulkio::InPort getPacket EXIT (port=" + str(name) +")" )
class InAttachablePort: _TYPE_='b' def __init__(self, name, logger=None, attachDetachCallback=None, sriCmp=sri.compare, timeCmp=timestamp.compare, PortType = _TYPE_, newSriCallback=None, sriChangeCallback=None,interface=None): self.name = name self.logger = logger self.port_lock = threading.Lock() self.sri_query_lock = threading.Lock() self._attachedStreams = {} # key=attach_id, value = (streamDef, userid) self.stats = InStats(name, PortType ) self.sriDict = {} # key=streamID, value=(StreamSRI, PrecisionUTCTime) self.attachDetachCallback = attachDetachCallback self.newSriCallback = newSriCallback self.sriChangeCallback = sriChangeCallback self.sri_cmp = sriCmp self.time_cmp = timeCmp self.sriChanged = False if not interface: if self.logger: self.logger.error("InAttachablePort __init__ - an interface must be specified, set to BULKIO.dataSDDS or BULKIO.dataVITA49") raise Port.InvalidPort(1, "InAttachablePort __init__ - an interface must be specified, set to BULKIO.dataSDDS or BULKIO.dataVITA49") self.interface=interface # BULKIO port interface (valid options are BULKIO.dataSDDS or BULKIO.dataVITA49) self.setNewAttachDetachListener(attachDetachCallback) if self.logger: self.logger.debug("bulkio::InAttachablePort CTOR port:" + str(self.name) + " using interface " + str(self.interface)) def setNewAttachDetachListener(self, attachDetachCallback ): self.port_lock.acquire() try: self.attachDetachCallback = attachDetachCallback # Set _attach_cb try: self._attach_cb = getattr(attachDetachCallback, "attach") if not callable(self._attach_cb): self._attach_cb = None except AttributeError: self._attach_cb = None # Set _detach_cb try: self._detach_cb = getattr(attachDetachCallback, "detach") if not callable(self._detach_cb): self._detach_cb = None except AttributeError: self._detach_cb = None finally: self.port_lock.release() def setNewSriListener(self, newSriCallback): self.port_lock.acquire() try: self.newSriCallback = newSriCallback finally: self.port_lock.release() def setSriChangeListener(self, sriChangeCallback): self.port_lock.acquire() try: self.sriChangeCallback = sriChangeCallback finally: self.port_lock.release() def setBitSize(self, bitSize): self.stats.setBitSize(bitSize) def enableStats(self, enabled): self.stats.setEnabled(enabled) def updateStats(self, elementsReceived, queueSize, streamID): self.port_lock.acquire() try: self.stats.update(elementsReceived, queueSize, streamID) finally: self.port_lock.release() def _get_statistics(self): self.port_lock.acquire() try: recStat = self.stats.retrieve() finally: self.port_lock.release() return recStat def _get_state(self): self.port_lock.acquire() try: numAttachedStreams = len(self._attachedStreams.values()) finally: self.port_lock.release() if numAttachedStreams == 0: return BULKIO.IDLE # default behavior is to limit to one connection elif numAttachedStreams == 1: return BULKIO.BUSY else: return BULKIO.ACTIVE def _get_attachedSRIs(self): sris = [] self.sri_query_lock.acquire() try: for entry in self.sriDict: # First value of sriDict entry is the StreamSRI object sris.append(copy.deepcopy(self.sriDict[entry][0])) finally: self.sri_query_lock.release() return sris def _get_usageState(self): self.port_lock.acquire() try: numAttachedStreams = len(self._attachedStreams.values()) finally: self.port_lock.release() if numAttachedStreams == 0: return self.interface.IDLE # default behavior is to limit to one connection elif numAttachedStreams == 1: return self.interface.BUSY else: return self.interface.ACTIVE def _get_attachedStreams(self): return [x[0] for x in self._attachedStreams.values()] def _get_attachmentIds(self): return self._attachedStreams.keys() def attach(self, streamDef, userid): if self.logger: self.logger.trace("bulkio::InAttachablePort attach ENTER (port=" + str(self.name) +")" ) self.logger.debug("InAttachablePort.attach() - ATTACH REQUEST, STREAM/USER" + str(streamDef) + '/' + str(userid)) attachId = None self.port_lock.acquire() try: try: if self.logger: self.logger.debug("InAttachablePort.attach() - CALLING ATTACH CALLBACK, STREAM/USER" + str(streamDef) + '/' + str(userid) ) if self._attach_cb != None: attachId = self._attach_cb(streamDef, userid) except Exception, e: if self.logger: self.logger.error("InAttachablePort.attach() - ATTACH CALLBACK EXCEPTION : " + str(e) + " STREAM/USER" + str(streamDef) + '/' + str(userid) ) raise self.interface.AttachError(str(e)) if attachId == None: attachId = str(uuid.uuid4()) self._attachedStreams[attachId] = (streamDef, userid) finally:
class InPort: DATA_BUFFER=0 TIME_STAMP=1 END_OF_STREAM=2 STREAM_ID=3 SRI=4 SRI_CHG=5 QUEUE_FLUSH=6 _TYPE_ = 'c' # Backwards-compatible DataTransfer type can still be unpacked like a tuple # but also supports named fields DataTransfer = collections.namedtuple('DataTransfer', 'dataBuffer T EOS streamID SRI sriChanged inputQueueFlushed') def __init__(self, name, logger=None, sriCompare=sri.compare, newSriCallback=None, sriChangeCallback=None, maxsize=100, PortTransferType=_TYPE_ ): self.name = name self.logger = logger self.queue = collections.deque() self._maxSize = maxsize self.port_lock = threading.Lock() self._not_full = threading.Condition(self.port_lock) self._not_empty = threading.Condition(self.port_lock) self._breakBlock = False self.stats = InStats(name, PortTransferType) self.blocking = False self.sri_cmp = sriCompare self.newSriCallback = newSriCallback self.sriChangeCallback = sriChangeCallback self.sriDict = {} # key=streamID, value=StreamSRI _cmpMsg = "DEFAULT" _newSriMsg = "EMPTY" _sriChangeMsg = "EMPTY" if sriCompare != sri.compare: _cmpMsg = "USER_DEFINED" if newSriCallback: _newSriMsg = "USER_DEFINED" if sriChangeCallback: _sriChangeMsg = "USER_DEFINED" if self.logger: self.logger.debug( "bulkio::InPort CTOR port:" + str(name) + " Blocking/MaxInputQueueSize " + str(self.blocking) + "/" + str(maxsize) + " SriCompare/NewSriCallback/SriChangeCallback " + _cmpMsg + "/" + _newSriMsg + "/" + _sriChangeMsg ); def setNewSriListener(self, newSriCallback): self.port_lock.acquire() try: self.newSriCallback = newSriCallback finally: self.port_lock.release() def setSriChangeListener(self, sriChangeCallback): self.port_lock.acquire() try: self.sriChangeCallback = sriChangeCallback finally: self.port_lock.release() def enableStats(self, enabled): self.stats.setEnabled(enabled) def _get_statistics(self): self.port_lock.acquire() try: return self.stats.retrieve() finally: self.port_lock.release() def _get_state(self): self.port_lock.acquire() try: if len(self.queue) == 0: return BULKIO.IDLE elif len(self.queue) == self._maxSize: return BULKIO.BUSY else: return BULKIO.ACTIVE finally: self.port_lock.release() def _get_activeSRIs(self): self.port_lock.acquire() try: return [self.sriDict[entry][0] for entry in self.sriDict] finally: self.port_lock.release() def getCurrentQueueDepth(self): self.port_lock.acquire() try: return len(self.queue) finally: self.port_lock.release() def getMaxQueueDepth(self): self.port_lock.acquire() try: return self._maxSize finally: self.port_lock.release() #set to -1 for infinite queue def setMaxQueueDepth(self, newDepth): self.port_lock.acquire() try: self._maxSize = int(newDepth) finally: self.port_lock.release() def unblock(self): self.port_lock.acquire() try: self._breakBlock = False finally: self.port_lock.release() def block(self): self.port_lock.acquire() try: self._breakBlock = True self._not_empty.notifyAll() finally: self.port_lock.release() # Provide standard interface for start/stop startPort = unblock stopPort = block def pushSRI(self, H): if self.logger: self.logger.trace( "bulkio::InPort pushSRI ENTER (port=" + str(self.name) +")" ) self.port_lock.acquire() try: if H.streamID not in self.sriDict: sriChanged = True if self.logger: self.logger.debug( "pushSRI PORT:" + str(self.name) + " NEW SRI:" + str(H.streamID) ) if self.newSriCallback: self.newSriCallback( H ) self.sriDict[H.streamID] = (copy.deepcopy(H), True) if H.blocking: self.blocking = True else: sri, sriChanged = self.sriDict[H.streamID] if self.sri_cmp: if not self.sri_cmp(sri, H): self.sriDict[H.streamID] = (copy.deepcopy(H), True) if H.blocking: self.blocking = True if self.sriChangeCallback: self.sriChangeCallback( H ) finally: self.port_lock.release() if self.logger: self.logger.trace( "bulkio::InPort pushSRI EXIT (port=" + str(self.name) +")" ) def pushPacket(self, data, T, EOS, streamID): if self.logger: self.logger.trace( "bulkio::InPort pushPacket ENTER (port=" + str(self.name) +")" ) self.port_lock.acquire() try: if self._maxSize == 0: if self.logger: self.logger.trace( "bulkio::InPort pushPacket EXIT (port=" + str(self.name) +")" ) return if self.sriDict.has_key(streamID): sri, sriChanged = self.sriDict[streamID] if EOS: self.sriDict[streamID] = (sri, True) else: self.sriDict[streamID] = (sri, False) else: # Create a default SRI for the stream ID if self.logger: self.logger.warn("bulkio::InPort pushPacket received data for stream '%s' with no SRI", streamID) sri = BULKIO.StreamSRI(1, 0.0, 1.0, 1, 0, 0.0, 0.0, 0, 0, streamID, False, []) if self.newSriCallback: self.newSriCallback(sri) self.sriDict[streamID] = (sri, False) sriChanged = True queueFlushed = False flagEOS = False if self.blocking: while len(self.queue) >= self._maxSize: self._not_full.wait() else: # Flush the queue if not using infinite queue (maxSize == -1), blocking is not on, and # current length of queue is >= maxSize if len(self.queue) >= self._maxSize and self._maxSize > -1: queueFlushed = True if self.logger: self.logger.debug("bulkio::InPort pushPacket PURGE INPUT QUEUE (SIZE=%d)", len(self.queue)) foundSRIChanged = False for data, T, EOS, streamID, sri, sriChangeHappened, inputQueueFlushed in self.queue: if foundSRIChanged and flagEOS: break if sriChangeHappened: sriChanged = True foundSRIChanged = True if EOS: flagEOS = True self.queue.clear() if flagEOS: EOS = True packet = (data, T, EOS, streamID, copy.deepcopy(sri), sriChanged, queueFlushed) self.stats.update(self._packetSize(data), float(len(self.queue))/float(self._maxSize), EOS, streamID, queueFlushed) if self.logger: self.logger.trace("bulkio::InPort pushPacket NEW Packet (QUEUE=%d)", len(self.queue)) self.queue.append(packet) # Let one waiting getPacket call know there is a packet available self._not_empty.notify() finally: self.port_lock.release() if self.logger: self.logger.trace( "bulkio::InPort pushPacket EXIT (port=" + str(self.name) +")" ) def getPacket(self, timeout=const.NON_BLOCKING): if self.logger: self.logger.trace( "bulkio::InPort getPacket ENTER (port=" + str(self.name) +")" ) self.port_lock.acquire() try: if timeout < 0.0: while not self.queue and not self._breakBlock: self._not_empty.wait() elif timeout > 0.0: # Determine the absolute time at which the timeout expires end = time.time() + timeout while not self.queue and not self._breakBlock: # Calculate remaining timeout remain = end - time.time() if remain <= 0.0: break self._not_empty.wait(remain) if not self.queue: return InPort.DataTransfer(None, None, None, None, None, None, None) data, T, EOS, streamID, sri, sriChanged, inputQueueFlushed = self.queue.popleft() # Let one waiting pushPacket call know there is space available self._not_full.notify() if EOS: if self.sriDict.has_key(streamID): (a,b) = self.sriDict.pop(streamID) if sri.blocking: stillBlock = False for _sri, _sriChanged in self.sriDict.values(): if _sri.blocking: stillBlock = True break if not stillBlock: self.blocking = False return InPort.DataTransfer(data, T, EOS, streamID, sri, sriChanged, inputQueueFlushed) finally: self.port_lock.release() if self.logger: self.logger.trace( "bulkio::InPort getPacket EXIT (port=" + str(self.name) +")" ) def _packetSize(self, data): return len(data)