runtime/Worker.py
author Edouard Tisserant
Tue, 04 Dec 2018 11:31:58 +0100
changeset 2463 8742337a9fe3
parent 2429 15f18dc8b56a
child 2467 fce6ab7ae156
permissions -rw-r--r--
Chunk based transfer for PLC binary and extra files, and some collateral code refactoring.
2270
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
     1
#!/usr/bin/env python
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
     2
# -*- coding: utf-8 -*-
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
     3
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
     4
# This file is part of Beremiz runtime.
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
     5
#
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
     6
# Copyright (C) 2018: Edouard TISSERANT
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
     7
#
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
     8
# See COPYING.Runtime file for copyrights details.
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
     9
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    10
from __future__ import absolute_import
2307
c44692b53736 Show more exceptions on stdout, particularly those that are raised by AutoLoad (first item in Main Thread worker)
Edouard Tisserant
parents: 2271
diff changeset
    11
import sys
2463
8742337a9fe3 Chunk based transfer for PLC binary and extra files, and some collateral code refactoring.
Edouard Tisserant
parents: 2429
diff changeset
    12
import six
2270
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    13
import thread
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    14
from threading import Lock, Condition
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    15
2309
d8fb90a2e11f Please pylint and pep8
Edouard Tisserant <edouard.tisserant@gmail.com>
parents: 2307
diff changeset
    16
2270
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    17
class job(object):
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    18
    """
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    19
    job to be executed by a worker
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    20
    """
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    21
    def __init__(self, call, *args, **kwargs):
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    22
        self.job = (call, args, kwargs)
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    23
        self.result = None
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    24
        self.success = False
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    25
        self.exc_info = None
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    26
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    27
    def do(self):
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    28
        """
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    29
        do the job by executing the call, and deal with exceptions
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    30
        """
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    31
        try:
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    32
            call, args, kwargs = self.job
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    33
            self.result = call(*args, **kwargs)
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    34
            self.success = True
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    35
        except Exception:
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    36
            self.success = False
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    37
            self.exc_info = sys.exc_info()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    38
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    39
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    40
class worker(object):
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    41
    """
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    42
    serialize main thread load/unload of PLC shared objects
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    43
    """
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    44
    def __init__(self):
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    45
        # Only one job at a time
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    46
        self._finish = False
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    47
        self._threadID = None
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    48
        self.mutex = Lock()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    49
        self.todo = Condition(self.mutex)
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    50
        self.done = Condition(self.mutex)
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    51
        self.free = Condition(self.mutex)
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    52
        self.job = None
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    53
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    54
    def runloop(self, *args, **kwargs):
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    55
        """
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    56
        meant to be called by worker thread (blocking)
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    57
        """
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    58
        self._threadID = thread.get_ident()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    59
        if args or kwargs:
2307
c44692b53736 Show more exceptions on stdout, particularly those that are raised by AutoLoad (first item in Main Thread worker)
Edouard Tisserant
parents: 2271
diff changeset
    60
            _job = job(*args, **kwargs)
c44692b53736 Show more exceptions on stdout, particularly those that are raised by AutoLoad (first item in Main Thread worker)
Edouard Tisserant
parents: 2271
diff changeset
    61
            _job.do()
c44692b53736 Show more exceptions on stdout, particularly those that are raised by AutoLoad (first item in Main Thread worker)
Edouard Tisserant
parents: 2271
diff changeset
    62
            if _job.success:
c44692b53736 Show more exceptions on stdout, particularly those that are raised by AutoLoad (first item in Main Thread worker)
Edouard Tisserant
parents: 2271
diff changeset
    63
                # result is ignored
c44692b53736 Show more exceptions on stdout, particularly those that are raised by AutoLoad (first item in Main Thread worker)
Edouard Tisserant
parents: 2271
diff changeset
    64
                pass
c44692b53736 Show more exceptions on stdout, particularly those that are raised by AutoLoad (first item in Main Thread worker)
Edouard Tisserant
parents: 2271
diff changeset
    65
            else:
c44692b53736 Show more exceptions on stdout, particularly those that are raised by AutoLoad (first item in Main Thread worker)
Edouard Tisserant
parents: 2271
diff changeset
    66
                raise _job.exc_info[0], _job.exc_info[1], _job.exc_info[2]
2270
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    67
        self.mutex.acquire()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    68
        while not self._finish:
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    69
            self.todo.wait()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    70
            if self.job is not None:
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    71
                self.job.do()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    72
                self.done.notify()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    73
            else:
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    74
                self.free.notify()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    75
        self.mutex.release()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    76
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    77
    def call(self, *args, **kwargs):
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    78
        """
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    79
        creates a job, execute it in worker thread, and deliver result.
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    80
        if job execution raise exception, re-raise same exception
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    81
        meant to be called by non-worker threads, but this is accepted.
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    82
        blocking until job done
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    83
        """
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    84
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    85
        _job = job(*args, **kwargs)
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    86
2271
985973ed701b Removed useless condition in Worker.py that was allowing misfit non-serialized call when worker still not running its loop.
Edouard Tisserant
parents: 2270
diff changeset
    87
        if self._threadID == thread.get_ident():
2270
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    88
            # if caller is worker thread execute immediately
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    89
            _job.do()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    90
        else:
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    91
            # otherwise notify and wait for completion
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    92
            self.mutex.acquire()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    93
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    94
            while self.job is not None:
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    95
                self.free.wait()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    96
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    97
            self.job = _job
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    98
            self.todo.notify()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
    99
            self.done.wait()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   100
            _job = self.job
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   101
            self.job = None
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   102
            self.mutex.release()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   103
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   104
        if _job.success:
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   105
            return _job.result
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   106
        else:
2429
15f18dc8b56a Merge, with surprizingly little conflicts
Edouard Tisserant <edouard.tisserant@gmail.com>
parents: 2309
diff changeset
   107
            exc_type = _job.exc_info[0]
15f18dc8b56a Merge, with surprizingly little conflicts
Edouard Tisserant <edouard.tisserant@gmail.com>
parents: 2309
diff changeset
   108
            exc_value = _job.exc_info[1]
15f18dc8b56a Merge, with surprizingly little conflicts
Edouard Tisserant <edouard.tisserant@gmail.com>
parents: 2309
diff changeset
   109
            exc_traceback = _job.exc_info[2]
15f18dc8b56a Merge, with surprizingly little conflicts
Edouard Tisserant <edouard.tisserant@gmail.com>
parents: 2309
diff changeset
   110
            six.reraise(exc_type, exc_value, exc_traceback)
2270
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   111
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   112
    def quit(self):
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   113
        """
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   114
        unblocks main thread, and terminate execution of runloop()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   115
        """
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   116
        # mark queue
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   117
        self._finish = True
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   118
        self.mutex.acquire()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   119
        self.job = None
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   120
        self.todo.notify()
d9175daf6522 Refactoring. Separated PLC Object, PYRO Server and MainWorker :
Edouard Tisserant
parents:
diff changeset
   121
        self.mutex.release()