1. 29 Aug, 2019 19 commits
    • Kirill Smelkov's avatar
      libgolang: Add internal semaphores · 69db91bf
      Kirill Smelkov authored
      - Add semaphore alloc/free/acquire/release functionality to libgolang runtime;
      - Implement semaphores for thread and gevent runtimes.
      
        * Thread runtime uses PyThread_acquire_lock/PyThread_release_lock +
          PyThread_acquire_lock/PyThread_release_lock, which, if used
          carefully, do not depend on GIL and on e.g. POSIX are tiny wrappers
          around sem_init(process-private) + sem_post/sem_wait(*).
      
        * Gevent runtime uses geven't Semaphore in Pyx mode.
      
      - Add Sema and Mutex classes that use semaphores provided by a runtime
        in a RAII style.
      - Add with_lock(mu) that mimics `with mu` in Python.
      
      Sema and Mutex will be used in channels implementation in the followup
      patch.
      
      (*) during late testing a bug was found in CPython2 and PyPy semaphore
      implementations on Darwin (technically speaking on POSIX with
      _POSIX_SEMAPHORES undefined). Quoting the patch:
      
          FIXME On Darwin, even though this is considered as POSIX, Python uses
          mutex+condition variable to implement its lock, and, as of 20190828, Py2.7
          implementation, even though similar issue was fixed for Py3 in 2012, contains
          synchronization bug: the condition is signalled after mutex unlock while the
          correct protocol is to signal condition from under mutex:
      
            https://github.com/python/cpython/blob/v2.7.16-127-g0229b56d8c0/Python/thread_pthread.h#L486-L506
            https://github.com/python/cpython/commit/187aa545165d (py3 fix)
      
          PyPy has the same bug for both pypy2 and pypy3:
      
            https://bitbucket.org/pypy/pypy/src/578667b3fef9/rpython/translator/c/src/thread_pthread.c#lines-443:465
            https://bitbucket.org/pypy/pypy/src/5b42890d48c3/rpython/translator/c/src/thread_pthread.c#lines-443:465
      
          This way when Pygolang is used with buggy Python/darwin, the bug leads to
          frequently appearing deadlocks, while e.g. CPython3/darwin works ok.
      
          -> TODO maintain our own semaphore code.
      
      So eventually we'll have push down and maintain our own semaphores,
      at least for platforms we care, not to be beaten by CPython runtime bugs.
      69db91bf
    • Kirill Smelkov's avatar
      golang.pyx: pyselect: Small cosmetics · e4dddf15
      Kirill Smelkov authored
      Move `ch = py{send,recv}.__self__` to right after case __class__ check.
      For now both versions - old and new - can work, but when we'll move
      channel implementations to C the new version will be required to access
      pychan C-level attribute earlier than where ch is currently initialized.
      e4dddf15
    • Kirill Smelkov's avatar
    • Kirill Smelkov's avatar
      golang.pyx: pyselect: * -> py* in logic which analyzes cases · d5e74947
      Kirill Smelkov authored
      For clarity to denote that things work at Python level:
      
          - casev	-> pycasev
          - case	-> pycase
          - recv	-> pyrecv
          - send	-> pysend
      
      Channel object is still denoted as `ch` to reduce noise for when chan IO
      code will be move into libgolang. `ch` will be renamed to `pych` after
      that.
      d5e74947
    • Kirill Smelkov's avatar
      golang: tests: Rework verifying blockforever · b9333e00
      Kirill Smelkov authored
      - put the logic to test-tweak what happens inside _blockforever into
        context manager pypanicWhenBlocked;
      - place this manager in pyx code, where it can later be changed to tweak
        _blockforever at C level.
      b9333e00
    • Kirill Smelkov's avatar
      golang_test.pyx: ch -> pych for Py-level pychan objects · 4166dc65
      Kirill Smelkov authored
      For clarity to distinguish where an object is Python-level channel, or
      (later) a C-level channel.
      4166dc65
    • Kirill Smelkov's avatar
      golang_test.pyx: Switch to cimport pychan · ef076d3a
      Kirill Smelkov authored
      Change `from golang import chan` to `from golang cimport pychan`; add
      type annotations where pychan is used. Using pychan at C level will be
      needed when test code will need to access C-level pychan attributes.
      ef076d3a
    • Kirill Smelkov's avatar
      golang.pyx: Switch pychan from `class` to `cdef class` · 1bcb8297
      Kirill Smelkov authored
      We will need to add C-level attributes to pychan and this requires it to
      become cdef class. The class is exported because at least
      _golang_test.pyx will also need to have access to those attributes.
      
      If we just do `class pychan` -> `cdef class pychan` e.g. the following
      starts to break:
      
          1.venv/local/lib/python2.7/site-packages/py/_path/local.py:701: in pyimport
              __import__(modname)
          golang/__init__.py:174: in <module>
              from ._golang import    \
          golang/_golang.pyx:455: in init golang._golang
              _pychan_send  = _pychan_send.__func__
          E   AttributeError: 'method_descriptor' object has no attribute '__func__'
      
      and
      
          golang/_golang.pyx:513: in golang._golang.pyselect
              if im_class(recv) is not pychan:
          _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
          f = <built-in method recv of golang._golang.pychan object at 0x7f7055e57cc8>
      
              def im_class(f):
          >       return f.im_class
          E       AttributeError: 'builtin_function_or_method' object has no attribute 'im_class'
      
          golang/_pycompat.py:28: AttributeError
      
      This is probably because for `cdef class` methods Cython does not
      emulate full method bindings the same way as Python does.  Anyway we can
      check which method is passed to pyselect by chanop.__name__ or by
      inspecting PyCFunction directly. And not having method binding wrapper
      should only remove a bit of overhead.
      
      So we are ok with reworking send/recv chanop detection, and since
      this way im_class provided by golang._pycompat becomes unused, it is
      also removed.
      
      The timings are probably within noise:
      
       (on i7@2.6GHz)
      
      thread runtime:
      
          name             old time/op  new time/op  delta
          go               21.7µs ± 1%  20.0µs ± 1%  -7.60%  (p=0.000 n=10+10)
          chan             9.91µs ± 4%  9.37µs ± 4%  -5.39%  (p=0.000 n=10+10)
          select           19.2µs ± 4%  20.2µs ± 4%  +5.62%  (p=0.001 n=9+8)
          def              58.0ns ± 0%  58.0ns ± 0%    ~     (all equal)
          func_def         44.4µs ± 0%  43.8µs ± 1%  -1.22%  (p=0.000 n=10+10)
          call             63.0ns ± 0%  62.4ns ± 1%  -0.95%  (p=0.011 n=10+10)
          func_call        1.05µs ± 1%  1.06µs ± 1%    ~     (p=0.059 n=10+10)
          try_finally       135ns ± 0%   136ns ± 0%  +0.74%  (p=0.000 n=10+9)
          defer            2.36µs ± 1%  2.28µs ± 1%  -3.59%  (p=0.000 n=10+10)
          workgroup_empty  49.0µs ± 1%  48.2µs ± 1%  -1.63%  (p=0.000 n=10+9)
          workgroup_raise  62.6µs ± 1%  58.9µs ± 1%  -5.96%  (p=0.000 n=10+10)
      
      gevent runtime:
      
          name             old time/op  new time/op  delta
          go               21.7µs ± 1%  20.5µs ± 1%  -5.33%  (p=0.000 n=10+9)
          chan             9.91µs ± 4%  9.72µs ± 5%    ~     (p=0.190 n=10+10)
          select           19.2µs ± 4%  19.5µs ±14%    ~     (p=0.968 n=9+10)
          def              58.0ns ± 0%  58.0ns ± 0%    ~     (all equal)
          func_def         44.4µs ± 0%  45.4µs ± 1%  +2.23%  (p=0.000 n=10+10)
          call             63.0ns ± 0%  64.0ns ± 0%  +1.59%  (p=0.000 n=10+10)
          func_call        1.05µs ± 1%  1.06µs ± 0%  +0.65%  (p=0.002 n=10+10)
          try_finally       135ns ± 0%   137ns ± 0%  +1.48%  (p=0.000 n=10+10)
          defer            2.36µs ± 1%  2.38µs ± 1%  +0.72%  (p=0.006 n=10+10)
          workgroup_empty  49.0µs ± 1%  48.2µs ± 1%  -1.65%  (p=0.000 n=10+10)
          workgroup_raise  62.6µs ± 1%  60.3µs ± 1%  -3.69%  (p=0.000 n=10+10)
      1bcb8297
    • Kirill Smelkov's avatar
      golang_test.pyx: Rename moved channel utilities * -> py* · a0714b8e
      Kirill Smelkov authored
      For consistency to denote that this functions work at Python level:
      
          - len_sendq    -> pylen_sendq
          - len_recvq    -> pylen_recvq
          - waitBlocked  -> pywaitBlocked
      a0714b8e
    • Kirill Smelkov's avatar
      golang: tests: Move channel test utilities from golang_test.py -> _golang_test.pyx · a508be9a
      Kirill Smelkov authored
      Plain test code movement with s/panic/pypanic/ as in golang.pyx panic is
      already there and means semantically different thing. We need this code to
      live in pyx world, because when channels implementation will be moved to
      C, this utilities will need to be adjusted in a way that is not possible
      to do from Python.
      a508be9a
    • Kirill Smelkov's avatar
      golang.pyx: pychan: return cosmetics · 790189e3
      Kirill Smelkov authored
      Denote what a method returns via `# -> ...` suffix.
      790189e3
    • Kirill Smelkov's avatar
      golang.pyx: pychan: self -> ch · 7e55394d
      Kirill Smelkov authored
      Use `ch` instead of `self` for pychan methods. This aligns with how
      (py)chan objects are currently denoted in (py)select and will reduce the
      difference when chan code is moved into libgolang. We are sticking to Go
      convention here.
      
      After the code with channels implementation is moved into libgolang, the
      rest bits in golang.pyx will be changed to refer to pychan objects as
      pych for clarity.
      7e55394d
    • Kirill Smelkov's avatar
      golang.pyx: Rename moved channel bits * -> py* · 311df9f1
      Kirill Smelkov authored
      To denote that this function/classes work at Python level:
      
          - chan    -> pychan
          - select  -> pyselect
          - default -> pydefault
          - nilchan -> pynilchan
      311df9f1
    • Kirill Smelkov's avatar
      golang: Move channels implementation from golang.py to golang.pyx · 83259a1b
      Kirill Smelkov authored
      Plain code movement with just s/panic/pypanic/ as in golang.pyx panic is
      aleady there and means semantically different thing. Moved code, even
      though it lives in golang.pyx, is still Python code and requires Python
      runtime and GIL. We'll be splitting channels implementation into nogil
      world in the following patches.
      
      Just plain movement to Cython brings the following speedup:
      
       (on i7@2.6GHz)
      
      thread runtime:
      
          name             old time/op  new time/op  delta
          go               26.6µs ± 1%  21.7µs ± 1%  -18.54%  (p=0.000 n=10+10)
          chan             13.7µs ± 1%   9.9µs ± 4%  -27.80%  (p=0.000 n=10+10)
          select           29.3µs ± 2%  19.2µs ± 4%  -34.65%  (p=0.000 n=9+9)
          def              55.0ns ± 0%  58.0ns ± 0%   +5.45%  (p=0.000 n=10+10)
          func_def         44.0µs ± 1%  44.4µs ± 0%   +0.72%  (p=0.002 n=10+10)
          call             64.0ns ± 0%  63.0ns ± 0%   -1.56%  (p=0.002 n=8+10)
          func_call        1.09µs ± 1%  1.05µs ± 1%   -2.96%  (p=0.000 n=10+10)
          try_finally       139ns ± 2%   135ns ± 0%   -2.60%  (p=0.000 n=10+10)
          defer            2.36µs ± 1%  2.36µs ± 1%     ~     (p=0.617 n=10+10)
          workgroup_empty  58.1µs ± 1%  49.0µs ± 1%  -15.61%  (p=0.000 n=10+10)
          workgroup_raise  72.7µs ± 1%  62.6µs ± 1%  -13.88%  (p=0.000 n=10+10)
      
      gevent runtime:
      
          name             old time/op  new time/op  delta
          go               28.6µs ± 0%  25.4µs ± 0%  -11.20%  (p=0.000 n=8+9)
          chan             15.8µs ± 1%  12.2µs ± 1%  -22.62%  (p=0.000 n=10+10)
          select           33.1µs ± 1%  23.3µs ± 2%  -29.60%  (p=0.000 n=10+10)
          def              55.0ns ± 0%  56.0ns ± 0%   +1.82%  (p=0.000 n=10+10)
          func_def         44.4µs ± 2%  43.0µs ± 1%   -3.06%  (p=0.000 n=10+9)
          call             64.0ns ± 2%  69.0ns ± 0%   +7.81%  (p=0.000 n=10+10)
          func_call        1.06µs ± 0%  1.06µs ± 1%     ~     (p=0.913 n=8+9)
          try_finally       136ns ± 0%   139ns ± 0%   +2.21%  (p=0.000 n=9+10)
          defer            2.29µs ± 1%  2.38µs ± 2%   +3.58%  (p=0.000 n=10+10)
          workgroup_empty  73.8µs ± 1%  70.5µs ± 1%   -4.48%  (p=0.000 n=10+10)
          workgroup_raise  94.1µs ± 0%  90.6µs ± 0%   -3.69%  (p=0.000 n=10+10)
      83259a1b
    • Kirill Smelkov's avatar
      pyx api: Provide go · f971a2a8
      Kirill Smelkov authored
      - Add go functionality to libgolang runtime;
      - Implement go for thread and gevent runtimes.
      
        * Thread runtime uses PyThread_start_new_thread which, if used
          carefully, does not depend on Python GIL and on e.g. POSIX reduces to
          tiny wrapper around pthread_create.
      
        * Gevent runtime uses gevent's Greenlet in Pyx mode. This turns
          gevent to be a build-time dependency.
      
      - Provide low-level _taskgo in C client API;
      - Provide type-safe C++-level go wrapper over _taskgo;
      - Switch golang.go from py implementation into Pyx wrapper over
        Pyx/nogil API.
      
      This is the first patch that adds Pyx/C++/C-level unit tests and hooks
      them into golang_test.py .
      
      This patch brings the following speedup to Python-level interface:
      
       (on i7@2.6GHz)
      
      thread runtime:
      
          name             old time/op  new time/op  delta
          go               93.0µs ± 1%  26.6µs ± 1%  -71.41%  (p=0.000 n=10+10)
          chan             13.6µs ± 2%  13.7µs ± 1%     ~     (p=0.280 n=10+10)
          select           29.9µs ± 4%  29.3µs ± 2%   -1.89%  (p=0.017 n=10+9)
          def              61.0ns ± 0%  55.0ns ± 0%   -9.84%  (p=0.000 n=10+10)
          func_def         43.8µs ± 1%  44.0µs ± 1%   +0.66%  (p=0.006 n=10+10)
          call             62.5ns ± 1%  64.0ns ± 0%   +2.40%  (p=0.000 n=10+8)
          func_call        1.06µs ± 1%  1.09µs ± 1%   +2.72%  (p=0.000 n=10+10)
          try_finally       137ns ± 0%   139ns ± 2%   +1.17%  (p=0.033 n=10+10)
          defer            2.34µs ± 1%  2.36µs ± 1%   +0.84%  (p=0.015 n=10+10)
          workgroup_empty  96.1µs ± 1%  58.1µs ± 1%  -39.55%  (p=0.000 n=10+10)
          workgroup_raise   135µs ± 1%    73µs ± 1%  -45.97%  (p=0.000 n=10+10)
      
      gevent runtime:
      
          name             old time/op  new time/op  delta
          go               68.8µs ± 1%  28.6µs ± 0%  -58.47%  (p=0.000 n=10+8)
          chan             14.8µs ± 1%  15.8µs ± 1%   +6.19%  (p=0.000 n=10+10)
          select           32.0µs ± 0%  33.1µs ± 1%   +3.25%  (p=0.000 n=10+10)
          def              58.0ns ± 0%  55.0ns ± 0%   -5.17%  (p=0.000 n=10+10)
          func_def         43.9µs ± 1%  44.4µs ± 2%   +1.20%  (p=0.007 n=10+10)
          call             63.5ns ± 1%  64.0ns ± 2%     ~     (p=0.307 n=10+10)
          func_call        1.08µs ± 1%  1.06µs ± 0%   -2.55%  (p=0.000 n=10+8)
          try_finally       142ns ± 0%   136ns ± 0%   -4.23%  (p=0.000 n=10+9)
          defer            2.32µs ± 1%  2.29µs ± 1%   -0.96%  (p=0.000 n=10+10)
          workgroup_empty  90.3µs ± 0%  73.8µs ± 1%  -18.29%  (p=0.000 n=10+10)
          workgroup_raise   108µs ± 1%    94µs ± 0%  -13.29%  (p=0.000 n=10+10)
      
      (small changes are probably within noise; "go" and "workgroup_*" should be
      representative)
      f971a2a8
    • Kirill Smelkov's avatar
      pyx.build: Allow to combine C and C++ sources in one extension · 7ae8c4f3
      Kirill Smelkov authored
      The next patch will add `go` to Pyx API and correspondingly C, C++ and Pyx
      level tests for it that will go into _golang_test.pyx extension. For
      C-level test we'll use C source file - to verify that libgolang.h could
      be used by C projects with C compiler, while for C++ and Pyx-level tests
      the sources will be in C++. Thus _golang_test.so will be build from both
      C and C++ sources.
      
      This creates a problem: distutils / setuptools use the _same_ compiler
      to compile both C and C++ sources and only use C++ compiler at link
      stage. Thus, as it is not possible to tune compiler that is used only
      for C++ sources, and also as it is not possible to provide per-source
      flags, when compiling C-level test, the compiler will be invoked with
      `-std=c++11` option that we inject. Gcc tolerates that and only prints a
      warning, but Clang considers that an error and gives:
      
      	error: invalid argument '-std=c++11' not allowed with 'C'`
      
      A proper fix would be to change the build system from distutils to
      something more flexible that uses C++ compiler for C++ sources and C
      compiler for C sources and allows to tune per-unit flags. However it is
      not a small step at this stage.
      
      -> Use workaround and tweak options that are used when compiling sources
      depending on whether it is C or C++.
      7ae8c4f3
    • Kirill Smelkov's avatar
      pyx api: Provide sleep · ce8152a2
      Kirill Smelkov authored
      - Add sleep functionality to libgolang runtime;
      - Implement sleep for thread and gevent runtimes. Thread runtime
        implements sleep independently of GIL, but only for POSIX for now;
      - Switch golang.time py module into using golang.time pyx module.
      
      As we are adding sleep, related functionality to query system about
      "what is current time?" is also added.
      ce8152a2
    • Kirill Smelkov's avatar
      libgolang: Introduce runtimes · ad00be70
      Kirill Smelkov authored
      Libgolang will be generic library and it will adapt itself to particular
      execution environment by way of runtime plugin. This commit introduces
      stubs for two such runtimes - "thread" and "gevent" - and initializes
      libgolang with particular runtime depending on whether golang is
      imported with gevent preactivated or not.
      
      The runtimes themselves are empty at this step. We'll be adding runtime
      functionality in the following patches.
      ad00be70
    • Kirill Smelkov's avatar
      Start using Cython and providing Cython/nogil API · 8fa3c15b
      Kirill Smelkov authored
      Start transforming Pygolang from being pure Python project into project
      that uses both Python and Cython and provides both Python and Cython API
      to its users.
      
      For Cython API there is a goal for it to be usable independently of
      Python GIL - i.e. independently of Python runtime and limitations
      imposed by Python's global interpreter lock. The motivation for this
      work is wendelin.core v2, which, due to its design, would deadlock if it
      tries to take the GIL in its pinner thread.
      
      This commit brings bare minimum establishing libraries and build system.
      It:
      
      - Introduces C/C++ library libgolang. Libgolang will be serving most of
        nogil functionality and Pyx API will be a small wrapper over it. At
        this step Libgolang comes only with C-level panic;
      
      - Introduces Pyx package golang that is aliased to Pyx package
        golang._golang . Users can do `from golang cimport ...` similarly to how
        they do py-level `from golang import ...`. At this step golang.pyx
        only wraps panic and provides way to transform C-level panic into Python
        exception;
      
      - Introduces Py package golang.pyx.build . This package, similarly to
        golang.org/pkg/go/build, serves as the system to build Pyx packages -
        both external packages that use Pygolang in pyx mode, and to build
        Pygolang itself. The build, internally, is served by setuptools_dso
        and cython. An example how to use golang.pyx.build from external
        project comes in golang/pyx/testprog/golang_pyx_user/ and is used by
        tests to verify golang.pyx.build functionality;
      
      - Introduces Pygolang build dependency to cython and setuptools_dso.
      8fa3c15b
  2. 26 Aug, 2019 8 commits
  3. 23 Aug, 2019 13 commits
    • Kirill Smelkov's avatar
      golang: Add test for blocked select(send|recv) vs close · 02f6991f
      Kirill Smelkov authored
      This test passes, but the functionality was not tested before. In
      particular all tests were passing even with the following hand-edits:
      
          --- a/golang/__init__.py
          +++ b/golang/__init__.py
          @@ -627,7 +627,7 @@ def selected():
                   sel = g.which
                   if isinstance(sel, _SendWaiting):
                       if not sel.ok:
          -                panic("send on closed channel")
          +                panic("send on closed channel ZZZ")
                       return sel.sel_n, None
      
                   if isinstance(sel, _RecvWaiting):
      
      with added tests the bug is caught and reported:
      
          def test_select():
              N = 1000 # times to do repeated select/chan or select/select interactions
      
              # sync: close vs select(send)
              ch = chan()
              def _():
                  waitBlocked(ch.send)
                  ch.close()
              go(_)
      >       with panics("send on closed channel"): select((ch.send, 0))
      
      golang_test.py:353:
      _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
      
      self = <golang.golang_test.panics instance at 0x7fc1da66e5f0>, exc_type = <class 'golang._PanicError'>, exc_val = _PanicError('send on closed channel ZZZ',)
      exc_tb = <traceback object at 0x7fc1dabc33b0>
      
          def __exit__(self, exc_type, exc_val, exc_tb):
              ok = self.raises.__exit__(exc_type, exc_val, exc_tb)
              if not ok:
                  return ok
              # _PanicError raised - let's check panic argument
      >       assert self.exc_info.value.args == (self.arg,)
      E       AssertionError: assert ('send on clo...channel ZZZ',) == ('send on closed channel',)
      E         At index 0 diff: 'send on closed channel ZZZ' != 'send on closed channel'
      E         Use -v to get the full diff
      
      golang_test.py:1032: AssertionError
      02f6991f
    • Kirill Smelkov's avatar
      golang: Fix race in chan._tryrecv · c6bb9eb3
      Kirill Smelkov authored
      For buffered channel _tryrecv, on success, was unlocking ch._mu too
      early - before accessing ch._dataq with ch._dataq.append().
      
      Without the fix, newly added test breaks as e.g.
      
          golang/golang_test.py::test_chan_buf_recv_vs_tryrecv_race Exception in thread Thread-3:
          Traceback (most recent call last):
            File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
              self.run()
            File "/usr/lib/python2.7/threading.py", line 754, in run
              self.__target(*self.__args, **self.__kwargs)
            File "/home/kirr/src/tools/go/pygolang-master/golang/golang_test.py", line 317, in _
              assert (_, _rx) == (1, None), ('i%d' % i)
          AssertionError: i30
          assert (0, None) == (1, None)
            At index 0 diff: 0 != 1
            Full diff:
            - (0, None)
            ?  ^
            + (1, None)
            ?  ^
      c6bb9eb3
    • Kirill Smelkov's avatar
      golang: Fix race in chan._trysend · eb8a1fef
      Kirill Smelkov authored
      For buffered channel _trysend, on success, was unlocking ch._mu too
      early - before accessing ch._dataq with ch._dataq.popleft().
      
      Without the fix, newly added test breaks as e.g.
      
          golang/golang_test.py::test_chan_buf_send_vs_tryrecv_race Exception in thread Thread-3:
          Traceback (most recent call last):
            File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
              self.run()
            File "/usr/lib/python2.7/threading.py", line 754, in run
              self.__target(*self.__args, **self.__kwargs)
            File "/home/kirr/src/tools/go/pygolang-master/golang/golang_test.py", line 256, in _
              assert (_, _rx) == (1, None)
          AssertionError: assert (0, 209) == (1, None)
            At index 0 diff: 0 != 1
            Full diff:
            - (0, 209)
            + (1, None)
      
          Exception in thread Thread-2:
          Traceback (most recent call last):
            File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
              self.run()
            File "/usr/lib/python2.7/threading.py", line 754, in run
              self.__target(*self.__args, **self.__kwargs)
            File "/home/kirr/src/tools/go/pygolang-master/golang/golang_test.py", line 243, in _
              ch.send(i)
            File "/home/kirr/src/tools/go/pygolang-master/golang/__init__.py", line 340, in send
              ok = self._trysend(obj)
            File "/home/kirr/src/tools/go/pygolang-master/golang/__init__.py", line 417, in _trysend
              rx = self._dataq.popleft()
          IndexError: pop from an empty deque
      eb8a1fef
    • Kirill Smelkov's avatar
      golang: Test that buffered channel releases objects from buffer on chan GC · cb5bfdd2
      Kirill Smelkov authored
      Currently it behaves correctly, but this aspect will need to be
      explicitly cared about when channel implementation moves to C. Add test
      to make sure it won't regress.
      cb5bfdd2
    • Kirill Smelkov's avatar
      golang: Run all select tests "more thoroughly" · c5810987
      Kirill Smelkov authored
      Starting from b51b8d5d (select: Run tests more thoroughly) we are
      running select subtests in repeated mode with N=1000. However not all
      select subtests were run in repeated mode - for example e.g.
      "non-blocking try send: not ok" was being run only once.
      
      -> Rework all select subtests to be run in repeated mode to increase the
      probability of catching bugs.
      c5810987
    • Kirill Smelkov's avatar
      golang: tests: Use panic when testing "blocks forever" · fa667412
      Kirill Smelkov authored
      Channels implementation will soon be moved to C and will become
      independent from Python runtime. This way while pygolang will still be
      providing panic, hooking in and raising arbitrary Python-level exception
      will become problematic. -> Rework "blocks forever" tests to rely on
      just panic to prepare for that.
      fa667412
    • Kirill Smelkov's avatar
      golang: tests: Factor out retrieving len(ch._recvq) and len(ch._sendq) · 352628b5
      Kirill Smelkov authored
      Chan implementation is going to be moved into C, and this way direct
      access to chan internals won't be possible. C implementation will export
      dedicated functions for chan tests which will be used.
      
      Prepare for that and factor out retrieving len of chan recv/send queues
      into separate functions, which will be adapted at the time of C port.
      352628b5
    • Kirill Smelkov's avatar
      golang: Don't verify ._recvq and ._sendq of nil channel · d98e42e3
      Kirill Smelkov authored
      Nil channel will soon be changed to be represented by underlying NULL C
      pointer and there won't be channel object for nil and correspondingly
      recv/send queues won't be there. -> Prepare for that and don't check for
      recvq/sendq on nil channel.
      d98e42e3
    • Kirill Smelkov's avatar
      golang: Remove outdated TODO · 049ba6ff
      Kirill Smelkov authored
      We provide gpython since 32a21d5b (gpython: Python interpreter with
      support for lightweight threads), and golang module, since the
      beginning, automatically uses gevent if it was installed via monkey
      patching.
      049ba6ff
    • Kirill Smelkov's avatar
      time: Test for now · 7f2362dd
      Kirill Smelkov authored
      This currently pass trivially (since time.now = stdtime.now), but will
      be useful once we get time.now implementation into our hands and move it into Cython.
      7f2362dd
    • Kirill Smelkov's avatar
      *: Use golang.time universally · c3bd2c50
      Kirill Smelkov authored
      After 9c260fde (time: New package that mirrors Go's time) we have
      golang.time.now and golang.time.sleep and it makes it a more
      self-dependent system if timing facility is used through golang.time
      instead of outside std time module.
      
      For now this is only a "cleanness" change, but will become important once
      we start adding pyx-level nogil API to pygolang - there it will be
      important to use golang.time.* for correctness.
      c3bd2c50
    • Kirill Smelkov's avatar
      sync: threading.Event -> chan · 78d85cdc
      Kirill Smelkov authored
      Starting from e6bea2cf (sync: New package that mirrors Go's sync) there
      is sync.WaitGroup and it was using threading.Event to signal that
      waitgroup's counter dropped to zero. threading.Event is implemented in
      Python's stdlib via threading.Condition, which in turn uses
      threading.Lock and list of waiters to implement its functionality.
      Which in turn is very similar to what golang.chan does internally with
      semaphore and e.g. recv queue.
      
      I noticed this while debugging sync test deadlock (see previous patch)
      and suspecting bug in threading.Event for a moment. While it turned
      there is no bug in threading.Event, it is better to rely on the common
      functionality for similar tasks, and pygolang's channel perfectly
      matches here the need to signal an event. By using our own code instead
      of stdlib's threading we are likely becoming less bug-prone.
      
      This also brings a small speedup:
      
          (on i5@1.80GHz)
          name             old time/op  new time/op  delta
          workgroup_empty   239µs ± 1%   220µs ± 1%  -7.62%  (p=0.000 n=10+9)
          workgroup_raise   275µs ± 2%   264µs ± 2%  -3.85%  (p=0.000 n=10+10)
      78d85cdc
    • Kirill Smelkov's avatar
      sync.WorkGroup: Fix deadlock thinko in tests · b8b042c5
      Kirill Smelkov authored
      sync.WorkGroup test was doing ctx.done() wait from under test mutex,
      something like
      
          def _(ctx, i):
              with mu:
                  ...
                  if i == 0:
                      raise RuntimeError()    # to cause ctx cancel
                  ctx.done().recv()           # i=1 -> wait till ctx is canceled
      
      but it can be a deadlock if T(i=1) runs first and enters
      ctx.done().recv() before T(i=0) is run - then T(i=0) will block forever
      waiting to lock mu.
      
      This failure was not seen so far, probably because the time to go a new
      thread/goroutine is relatively high. However one of upcoming patches,
      where go is made faster, revealed this problem and, without the fix,
      sync.WorkGroup test was regularly deadlocking.
      
      The problem was there from sync.WorkGroup beginning - from
      9ee7ba91 (sync += WorkGroup).
      
      Fix the deadlock by waiting for ctx.done() outside of mu.
      b8b042c5