예제 #1
0
class Cache(object):

    __slots__ = ['__dev', '__info', 'lock', 'maxlen']

    DEFAULT_MAXLEN = 128

    def __init__(self, maxlen=DEFAULT_MAXLEN):
        self.__dev = {}
        self.__info = {}
        self.maxlen = int(maxlen)
        self.lock = RLock()

    def get(self, fileinfo):
        blockdevice = self.__dev.setdefault(
            fileinfo.dev,
            blkdevice(fileinfo.path))
        value = self.__info.setdefault(
            blockdevice,
            _CacheInfo(blockdevice, blksize(fileinfo.path)))
        return value

    def clear(self):
        if self.lock.locked():
            return False
        self.__dev.clear()
        self.__info.clear()
        return True

    def acquire(self):
        self.lock.acquire()

    def release(self):
        self.lock.release()
        if len(self.__dev) > self.maxlen:
            self.clear()
예제 #2
0
class Relax_lock:
    """A type of locking object for relax."""

    def __init__(self, name='unknown', fake_lock=False):
        """Set up the lock-like object.

        @keyword name:      The special name for the lock, used in debugging.
        @type name:         str
        @keyword fake_lock: A flag which is True will allow this object to be debugged as the locking mechanism is turned off.
        @type fake_lock:    bool
        """

        # Store the args.
        self.name = name
        self._fake_lock = fake_lock

        # Init a reentrant lock object.
        self._lock = RLock()

        # The status container.
        self._status = Status()

        # Fake lock.
        if self._fake_lock:
            # Track the number of acquires.
            self._lock_level = 0


    def acquire(self, acquirer='unknown'):
        """Simulate the RLock.acquire() mechanism.

        @keyword acquirer:  The optional name of the acquirer.
        @type acquirer:     str
        """

        # Debugging.
        if self._status.debug:
            sys.stdout.write("debug> Lock '%s':  Acquisition by '%s'.\n" % (self.name, acquirer))

        # Fake lock.
        if self._fake_lock:
            # Increment the lock level.
            self._lock_level += 1

            # Throw an error.
            if self._lock_level > 1:
                raise

            # Return to prevent real locking.
            return

        # Acquire the real lock.
        lock = self._lock.acquire()

        # Return the real lock.
        return lock


    def locked(self):
        """Simulate the RLock.locked() mechanism."""

        # Call the real method.
        return self._lock.locked()


    def release(self, acquirer='unknown'):
        """Simulate the RLock.release() mechanism.

        @keyword acquirer:  The optional name of the acquirer.
        @type acquirer:     str
        """

        # Debugging.
        if self._status.debug:
            sys.stdout.write("debug> Lock '%s':  Release by '%s'.\n" % (self.name, acquirer))

        # Fake lock.
        if self._fake_lock:
            # Decrement the lock level.
            self._lock_level -= 1

            # Return to prevent real lock release.
            return

        # Release the real lock.
        release = self._lock.release()

        # Return the status.
        return release
예제 #3
0
파일: status.py 프로젝트: tlinnet/relax
class Relax_lock:
    """A type of locking object for relax."""

    def __init__(self, name='unknown', fake_lock=False):
        """Set up the lock-like object.

        @keyword name:      The special name for the lock, used in debugging.
        @type name:         str
        @keyword fake_lock: A flag which is True will allow this object to be debugged as the locking mechanism is turned off.
        @type fake_lock:    bool
        """

        # Store the args.
        self.name = name
        self._fake_lock = fake_lock

        # Init a reentrant lock object.
        self._lock = RLock()

        # The status container.
        self._status = Status()

        # Fake lock.
        if self._fake_lock:
            # Track the number of acquires.
            self._lock_level = 0


    def acquire(self, acquirer='unknown'):
        """Simulate the RLock.acquire() mechanism.

        @keyword acquirer:  The optional name of the acquirer.
        @type acquirer:     str
        """

        # Debugging.
        if self._status.debug:
            sys.stdout.write("debug> Lock '%s':  Acquisition by '%s'.\n" % (self.name, acquirer))

        # Fake lock.
        if self._fake_lock:
            # Increment the lock level.
            self._lock_level += 1

            # Throw an error.
            if self._lock_level > 1:
                raise

            # Return to prevent real locking.
            return

        # Acquire the real lock.
        lock = self._lock.acquire()

        # Return the real lock.
        return lock


    def locked(self):
        """Simulate the RLock.locked() mechanism."""

        # Call the real method.
        return self._lock.locked()


    def release(self, acquirer='unknown'):
        """Simulate the RLock.release() mechanism.

        @keyword acquirer:  The optional name of the acquirer.
        @type acquirer:     str
        """

        # Debugging.
        if self._status.debug:
            sys.stdout.write("debug> Lock '%s':  Release by '%s'.\n" % (self.name, acquirer))

        # Fake lock.
        if self._fake_lock:
            # Decrement the lock level.
            self._lock_level -= 1

            # Return to prevent real lock release.
            return

        # Release the real lock.
        release = self._lock.release()

        # Return the status.
        return release
예제 #4
0
class GCSMessages(object):
    """Provide a GCS communication layer."""
    def __init__(self, interface):
        """Provide a GCS communication layer.
        @param interface : Instance of an object from pipython.interfaces.
        """
        debug('create an instance of GCSComm(interface=%s)', str(interface))
        self.__lock = RLock()
        self.__interface = interface
        self.__errcheck = True
        self.__embederr = False
        self.__timeout = 7000  # milliseconds
        self.__databuffer = {
            'size': 0,
            'index': 0,
            'lastindex': 0,
            'lastupdate': None,
            'data': [],
            'error': None
        }

    def __str__(self):
        return 'GCSMessages(interface=%s)' % str(self.__interface)

    @property
    def connectionid(self):
        """Get ID of current connection as integer."""
        return self.__interface.connectionid

    @property
    def errcheck(self):
        """Get current error check setting, i.e. if the devices error state is always queried."""
        return self.__errcheck

    @errcheck.setter
    def errcheck(self, value):
        """Set error check property.
        @param value : True means that after each command the error is queried.
        """
        self.__errcheck = bool(value)
        debug('GCSMessages.errcheck set to %s', self.__errcheck)

    @property
    def embederr(self):
        """Get current embed error setting, i.e. if "ERR?" is embedded into a set command."""
        return self.__embederr

    @embederr.setter
    def embederr(self, value):
        """Set embed error property.
        @param value : True means that "ERR?" is embedded into a set command.
        """
        self.__embederr = bool(value)
        debug('GCSMessages.embederr set to %s', self.__embederr)

    @property
    def timeout(self):
        """Get current timeout setting in milliseconds."""
        return self.__timeout

    @timeout.setter
    def timeout(self, value):
        """Set timeout.
        @param value : Timeout in milliseconds as integer.
        """
        self.__timeout = int(value)
        debug('GCSMessages.timeout set to %d milliseconds', self.__timeout)

    @property
    def bufstate(self):
        """False if no buffered data is available. True if buffered data is ready to use.
        Float value 0..1 indicates read progress. To wait, use "while bufstate is not True".
        """
        if self.__databuffer['error']:
            raise self.__databuffer['error']  # Raising NoneType pylint: disable=E0702
        if self.__databuffer['lastupdate'] is None:
            self.__databuffer['lastupdate'] = time()
        if self.__databuffer['index'] == self.__databuffer['lastindex']:
            if time() - float(
                    self.__databuffer['lastupdate']) > self.__timeout / 1000.:
                raise GCSError(gcserror.COM_TIMEOUT__7, 'bufstate timed out')
        else:
            self.__databuffer['lastupdate'] = time()
            self.__databuffer['lastindex'] = self.__databuffer['index']
        if not self.__databuffer['size']:
            return False
        if self.__databuffer['size'] is True:
            self.__databuffer['lastupdate'] = None
            return True
        return float(self.__databuffer['index']) / float(
            self.__databuffer['size'])

    @property
    def bufdata(self):
        """Get buffered data as 2-dimensional list of float values."""
        debug('GCSMessages.bufdata: %d datasets', self.__databuffer['index'])
        return self.__databuffer['data']

    @property
    def locked(self):
        """Return True if instance is locked, i.e. is communicating with the device."""
        debug('GCSMessages.locked: %s', self.__lock.locked())
        return self.__lock.locked()

    def send(self, tosend):
        """Send 'tosend' to device and check for error.
        @param tosend : String to send to device, with or without trailing linefeed.
        """
        if self.__embederr and self.__errcheck:
            if len(tosend) > 1 and not tosend.endswith('\n'):
                tosend += '\n'
            tosend += 'ERR?\n'
        with self.__lock:
            self.__send(tosend)
            self.__checkerror(senderr=not self.__embederr)

    def read(self, tosend, gcsdata=0):
        """Send 'tosend' to device, read answer and check for error.
        @param tosend : String to send to device.
        @param gcsdata : Number of lines, if != 0 then GCS data will be read in background task.
        @return : Device answer as string.
        """
        gcsdata = None if gcsdata < 0 else gcsdata
        stopon = None
        if 0 != gcsdata:
            stopon = '# END_HEADER'
            self.__databuffer['data'] = []
            self.__databuffer['index'] = 0
            self.__databuffer['error'] = None
        with self.__lock:
            while self.__interface.answersize:
                self.__interface.getanswer(
                    self.__interface.answersize)  # empty buffer
            self.__send(tosend)
            answer = self.__read(stopon)
            if 0 != gcsdata:
                splitpos = answer.upper().find(stopon)
                if splitpos < 0:
                    self.__send('ERR?\n')
                    err = int(self.__read(stopon=None).strip())
                    err = err or gcserror.E_1004_PI_UNEXPECTED_RESPONSE
                    raise GCSError(err, 'no stop string in %r' % answer)
                stopon += ' \n'
                splitpos += len(stopon)
                strbuf = answer[splitpos:]
                answer = answer[:splitpos]
                if stopon in answer.upper(
                ):  # "# END HEADER\n" will not start reading GCS data
                    self.__databuffer['size'] = gcsdata
                    self.__readgcsdata(strbuf)
                else:
                    self.__databuffer['size'] = True
            else:
                self.__checkerror()
        return answer

    def __send(self, tosend):
        """Send 'tosend' to device.
        @param tosend : String to send to device, with or without trailing linefeed.
        """
        if len(tosend) > 1 and not tosend.endswith('\n'):
            tosend += '\n'
        self.__interface.send(tosend)

    def __read(self, stopon):
        """Read answer from device until this ends with linefeed with no preceeding space.
        @param stopon: Addditional uppercase string that stops reading, too.
        @return : Received data as string.
        """
        timeout = time() + self.__timeout / 1000.
        chunks = []
        while True:
            if time() > timeout:
                raise GCSError(gcserror.E_7_COM_TIMEOUT)
            if self.__interface.answersize:
                timeout = time() + self.__timeout / 1000.
                received = self.__interface.getanswer(
                    self.__interface.answersize)
                chunks.append(received)
                if endofanswer(chunks[-1]):
                    break
                if stopon and stopon in chunks[-1].upper():
                    break
        try:
            answer = ''.join(chunks)
        except TypeError:
            answer = b''.join(chunks)
        self.__check_no_eol(answer)
        return answer

    @staticmethod
    def __check_no_eol(answer):
        """Check that 'answer' does not contain a LF without a preceeding SPACE except at the end.
        @param answer : Answer to verify as string.
        """
        for i, char in enumerate(answer[:-1]):
            if '\n' == char or '\r' == char:
                if i > 0 and ' ' != answer[i - 1]:
                    msg = 'LF/CR at %r' % answer[
                        max(0, i - 10):min(i + 10, len(answer))]
                    raise GCSError(gcserror.E_1004_PI_UNEXPECTED_RESPONSE, msg)

    def __readgcsdata(self, strbuf):
        """Start a background task to read out GCS data and save it in the instance.
        @param strbuf : String of already readout answer.
        """
        if not endofanswer(strbuf):
            strbuf += self.__read(stopon=' \n')
        numcolumns = len(strbuf.split('\n')[0].split())
        self.__databuffer['data'] = [[] for _ in range(numcolumns)]
        debug('GCSMessages: start background task to query GCS data')
        thread = Thread(target=self.__fillbuffer, args=(strbuf, ))
        thread.start()

    def __fillbuffer(self, answer):
        """Read answers and save them as float values into the data buffer.
        An answerline with invalid data (non-number, missing column) will be skipped and error flag is set.
        @param answer : String of already readout answer.
        """
        numcolumns = len(self.__databuffer['data'])
        with self.__lock:
            while True:
                lines = answer.splitlines(True)  # keep line endings
                answer = ''
                for line in lines:
                    if '\n' not in line:
                        answer = line
                        break
                    msg = 'cannot convert to float: %r' % line
                    try:
                        values = [float(x) for x in line.split()]
                        if numcolumns != len(values):
                            msg = 'expected %d, got %d columns: %r' % (
                                numcolumns, len(values), line)
                            raise ValueError()
                    except ValueError:
                        exc = GCSError(gcserror.E_1004_PI_UNEXPECTED_RESPONSE,
                                       msg)
                        self.__databuffer['error'] = exc
                        error('GCSMessages: GCSError: %s', exc)
                    else:
                        for i in range(numcolumns):
                            self.__databuffer['data'][i].append(values[i])
                    self.__databuffer['index'] += 1
                    if self.__endofdata(line):
                        debug(
                            'GCSMessages: end background task to query GCS data'
                        )
                        self.__databuffer['error'] = self.__checkerror(
                            doraise=False)
                        self.__databuffer['size'] = True
                        return
                try:
                    answer += self.__read(stopon=' \n')
                except:  # No exception type(s) specified pylint: disable=W0702
                    exc = GCSError(gcserror.E_1090_PI_GCS_DATA_READ_ERROR,
                                   sys.exc_info()[1])
                    self.__databuffer['error'] = exc
                    error('GCSMessages: end background task with GCSError: %s',
                          exc)
                    self.__databuffer['size'] = True
                    return

    def __endofdata(self, line):
        """Verify 'line' and return True if 'line' is last line of device answer.
        @param line : One answer line of device with trailing line feed character.
        @return : True if 'line' is last line of device answer.
        """
        if endofanswer(line) and self.__databuffer[
                'index'] < self.__databuffer['size']:
            msg = '%s expected, %d received' % (self.__databuffer['size'],
                                                self.__databuffer['index'])
            exc = GCSError(gcserror.E_1088_PI_TOO_FEW_GCS_DATA, msg)
            self.__databuffer['error'] = exc
            error('GCSMessages: GCSError: %s', exc)
        if self.__databuffer['size'] and self.__databuffer[
                'index'] > self.__databuffer['size']:
            msg = '%s expected, %d received' % (self.__databuffer['size'],
                                                self.__databuffer['index'])
            exc = GCSError(gcserror.E_1089_PI_TOO_MANY_GCS_DATA, msg)
            self.__databuffer['error'] = exc
            error('GCSMessages: GCSError: %s', exc)
        return endofanswer(line)

    def __checkerror(self, senderr=True, doraise=True):
        """Query error from device and raise GCSError exception.
        @param senderr : If True send "ERR?\n" to the device.
        @param doraise : If True an error is raised, else the GCS error number is returned.
        @return : If doraise is False the GCS exception if an error occured else None.
        """
        if not self.__errcheck:
            return 0
        if senderr:
            self.__send('ERR?\n')
        answer = self.__read(stopon=None)
        exc = None
        try:
            err = int(answer)
        except ValueError:
            exc = GCSError(gcserror.E_1004_PI_UNEXPECTED_RESPONSE,
                           'invalid answer on "ERR?": %r' % answer)
        else:
            if err:
                exc = GCSError(err)
        if exc and doraise:
            raise exc  # Raising NoneType while only classes or instances are allowed pylint: disable=E0702
        return exc