Преглед изворни кода

HUE-7860 [core] Update greenlet from 0.4.12 to 0.4.15

Ying Chen пре 7 година
родитељ
комит
6bdb3ac
66 измењених фајлова са 1830 додато и 29 уклоњено
  1. 1 0
      desktop/core/ext-py/greenlet-0.4.15/.travis.yml
  2. 5 0
      desktop/core/ext-py/greenlet-0.4.15/AUTHORS
  3. 0 0
      desktop/core/ext-py/greenlet-0.4.15/LICENSE
  4. 0 0
      desktop/core/ext-py/greenlet-0.4.15/LICENSE.PSF
  5. 2 0
      desktop/core/ext-py/greenlet-0.4.15/MANIFEST.in
  6. 16 0
      desktop/core/ext-py/greenlet-0.4.15/NEWS
  7. 2 1
      desktop/core/ext-py/greenlet-0.4.15/PKG-INFO
  8. 0 0
      desktop/core/ext-py/greenlet-0.4.15/README.rst
  9. 10 10
      desktop/core/ext-py/greenlet-0.4.15/appveyor.yml
  10. 0 0
      desktop/core/ext-py/greenlet-0.4.15/appveyor/run_pip.py
  11. 0 0
      desktop/core/ext-py/greenlet-0.4.15/appveyor/run_with_env.cmd
  12. 0 0
      desktop/core/ext-py/greenlet-0.4.15/benchmarks/chain.py
  13. 0 0
      desktop/core/ext-py/greenlet-0.4.15/conftest.py
  14. 0 0
      desktop/core/ext-py/greenlet-0.4.15/dev-requirements.txt
  15. 0 0
      desktop/core/ext-py/greenlet-0.4.15/doc/Makefile
  16. 0 0
      desktop/core/ext-py/greenlet-0.4.15/doc/conf.py
  17. 7 7
      desktop/core/ext-py/greenlet-0.4.15/doc/greenlet.txt
  18. 0 0
      desktop/core/ext-py/greenlet-0.4.15/doc/index.txt
  19. 0 0
      desktop/core/ext-py/greenlet-0.4.15/doc/make.bat
  20. 49 6
      desktop/core/ext-py/greenlet-0.4.15/greenlet.c
  21. 10 1
      desktop/core/ext-py/greenlet-0.4.15/greenlet.h
  22. 0 0
      desktop/core/ext-py/greenlet-0.4.15/make-manylinux
  23. 0 0
      desktop/core/ext-py/greenlet-0.4.15/make-win-release
  24. 0 0
      desktop/core/ext-py/greenlet-0.4.15/my_build_ext.py
  25. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_aarch64_gcc.h
  26. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_amd64_unix.h
  27. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_arm32_gcc.h
  28. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_arm32_ios.h
  29. 48 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_csky_gcc.h
  30. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_m68k_gcc.h
  31. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_mips_unix.h
  32. 17 2
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_ppc64_linux.h
  33. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_ppc_aix.h
  34. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_ppc_linux.h
  35. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_ppc_macosx.h
  36. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_ppc_unix.h
  37. 32 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_riscv_unix.h
  38. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_s390_unix.h
  39. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_sparc_sun_gcc.h
  40. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_x32_unix.h
  41. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_x64_masm.asm
  42. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_x64_masm.obj
  43. 3 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_x64_msvc.h
  44. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_x86_msvc.h
  45. 0 0
      desktop/core/ext-py/greenlet-0.4.15/platform/switch_x86_unix.h
  46. 0 0
      desktop/core/ext-py/greenlet-0.4.15/run-tests.py
  47. 0 0
      desktop/core/ext-py/greenlet-0.4.15/setup.cfg
  48. 2 1
      desktop/core/ext-py/greenlet-0.4.15/setup.py
  49. 0 0
      desktop/core/ext-py/greenlet-0.4.15/setup_switch_x64_masm.cmd
  50. 5 1
      desktop/core/ext-py/greenlet-0.4.15/slp_platformselect.h
  51. 56 0
      desktop/core/ext-py/greenlet-0.4.15/tests/__init__.py
  52. 208 0
      desktop/core/ext-py/greenlet-0.4.15/tests/_test_extension.c
  53. 118 0
      desktop/core/ext-py/greenlet-0.4.15/tests/_test_extension_cpp.cpp
  54. 15 0
      desktop/core/ext-py/greenlet-0.4.15/tests/test_cpp.py
  55. 71 0
      desktop/core/ext-py/greenlet-0.4.15/tests/test_extension_interface.py
  56. 77 0
      desktop/core/ext-py/greenlet-0.4.15/tests/test_gc.py
  57. 59 0
      desktop/core/ext-py/greenlet-0.4.15/tests/test_generator.py
  58. 165 0
      desktop/core/ext-py/greenlet-0.4.15/tests/test_generator_nested.py
  59. 542 0
      desktop/core/ext-py/greenlet-0.4.15/tests/test_greenlet.py
  60. 85 0
      desktop/core/ext-py/greenlet-0.4.15/tests/test_leaks.py
  61. 19 0
      desktop/core/ext-py/greenlet-0.4.15/tests/test_stack_saved.py
  62. 100 0
      desktop/core/ext-py/greenlet-0.4.15/tests/test_throw.py
  63. 52 0
      desktop/core/ext-py/greenlet-0.4.15/tests/test_tracing.py
  64. 20 0
      desktop/core/ext-py/greenlet-0.4.15/tests/test_version.py
  65. 34 0
      desktop/core/ext-py/greenlet-0.4.15/tests/test_weakref.py
  66. 0 0
      desktop/core/ext-py/greenlet-0.4.15/tox.ini

+ 1 - 0
desktop/core/ext-py/greenlet-0.4.12/.travis.yml → desktop/core/ext-py/greenlet-0.4.15/.travis.yml

@@ -9,6 +9,7 @@ python:
   - 3.4
   - 3.5
   - 3.6
+  - 3.7-dev
 
 install: python setup.py build_ext -i
 

+ 5 - 0
desktop/core/ext-py/greenlet-0.4.12/AUTHORS → desktop/core/ext-py/greenlet-0.4.15/AUTHORS

@@ -22,12 +22,15 @@ Contributors
 * Fredrik Fornwall
 * Gerd Woetzel
 * Giel van Schijndel
+* Gökhan Karabulut
 * Gustavo Niemeyer
 * Guy Rozendorn
 * Hye-Shik Chang
 * Jared Kuolt
 * Jason Madden
 * Kyle Ambroff
+* Laszlo Boszormenyi
+* Mao Han
 * Marc Abramowitz
 * Marc Schlaich
 * Marcin Bachry
@@ -41,4 +44,6 @@ Contributors
 * Tony Bowles
 * Tony Breeds
 * Trevor Bowen
+* Tulio Magno Quites Machado Filho
 * Ulrich Weigand
+* Victor Stinner

+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/LICENSE → desktop/core/ext-py/greenlet-0.4.15/LICENSE


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/LICENSE.PSF → desktop/core/ext-py/greenlet-0.4.15/LICENSE.PSF


+ 2 - 0
desktop/core/ext-py/greenlet-0.4.12/MANIFEST.in → desktop/core/ext-py/greenlet-0.4.15/MANIFEST.in

@@ -25,6 +25,7 @@ include platform/switch_aarch64_gcc.h
 include platform/switch_amd64_unix.h
 include platform/switch_arm32_gcc.h
 include platform/switch_arm32_ios.h
+include platform/switch_csky_gcc.h
 include platform/switch_m68k_gcc.h
 include platform/switch_mips_unix.h
 include platform/switch_ppc64_linux.h
@@ -32,6 +33,7 @@ include platform/switch_ppc_aix.h
 include platform/switch_ppc_linux.h
 include platform/switch_ppc_macosx.h
 include platform/switch_ppc_unix.h
+include platform/switch_riscv_unix.h
 include platform/switch_s390_unix.h
 include platform/switch_sparc_sun_gcc.h
 include platform/switch_x32_unix.h

+ 16 - 0
desktop/core/ext-py/greenlet-0.4.12/NEWS → desktop/core/ext-py/greenlet-0.4.15/NEWS

@@ -1,3 +1,19 @@
+0.4.15
+===========
+- Support for RISC-V architecture
+- Workaround a gcc bug on ppc64
+
+0.4.14
+======
+- Support for C-SKY architecture
+- Fixed support for ppc64 ABI
+- Fixed support for Python 3.7
+
+0.4.13
+======
+- Support for Python 3.7
+- Support for MinGW x64
+
 0.4.12
 ======
 - Stop using trashcan api

+ 2 - 1
desktop/core/ext-py/greenlet-0.4.12/PKG-INFO → desktop/core/ext-py/greenlet-0.4.15/PKG-INFO

@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: greenlet
-Version: 0.4.12
+Version: 0.4.15
 Summary: Lightweight in-process concurrent programming
 Home-page: https://github.com/python-greenlet/greenlet
 Author: Alexey Borzenkov
@@ -83,5 +83,6 @@ Classifier: Programming Language :: Python :: 3.3
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
 Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
 Classifier: Operating System :: OS Independent
 Classifier: Topic :: Software Development :: Libraries :: Python Modules

+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/README.rst → desktop/core/ext-py/greenlet-0.4.15/README.rst


+ 10 - 10
desktop/core/ext-py/greenlet-0.4.12/appveyor.yml → desktop/core/ext-py/greenlet-0.4.15/appveyor.yml

@@ -1,4 +1,4 @@
-version: 0.4.12.{build}
+version: 0.4.15.{build}
 environment:
   global:
     # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the
@@ -8,14 +8,6 @@ environment:
 
   matrix:
     # http://www.appveyor.com/docs/installed-software#python
-    - PYTHON_ROOT: "C:\\Python26"
-      PYTHON_ARCH: "32"
-      PYTHON_VERSION: "2.6.x"
-
-    - PYTHON_ROOT: "C:\\Python26-x64"
-      PYTHON_ARCH: "64"
-      PYTHON_VERSION: "2.6.x"
-
     - PYTHON_ROOT: "C:\\Python27"
       PYTHON_ARCH: "32"
       PYTHON_VERSION: "2.7.x"
@@ -56,13 +48,21 @@ environment:
       PYTHON_ARCH: "64"
       PYTHON_VERSION: "3.6.x"
 
+    - PYTHON_ROOT: "C:\\Python37"
+      PYTHON_ARCH: "32"
+      PYTHON_VERSION: "3.7.x"
+
+    - PYTHON_ROOT: "C:\\Python37-x64"
+      PYTHON_ARCH: "64"
+      PYTHON_VERSION: "3.7.x"
+
 install:
   - "SET PATH=%PYTHON_ROOT%;%PYTHON_ROOT%\\Scripts;%PATH%"
   - "python --version"
   - "python -c \"import struct; print(struct.calcsize('P') * 8)\""
 
   # Upgrade pip to the latest version
-  - "python appveyor\\run_pip.py install --disable-pip-version-check --upgrade pip"
+  #- "python appveyor\\run_pip.py install --disable-pip-version-check --upgrade pip"
 
   # Install requirements for running tests and building artifacts
   - "%CMD_IN_ENV% pip install --upgrade -r dev-requirements.txt"

+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/appveyor/run_pip.py → desktop/core/ext-py/greenlet-0.4.15/appveyor/run_pip.py


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/appveyor/run_with_env.cmd → desktop/core/ext-py/greenlet-0.4.15/appveyor/run_with_env.cmd


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/benchmarks/chain.py → desktop/core/ext-py/greenlet-0.4.15/benchmarks/chain.py


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/conftest.py → desktop/core/ext-py/greenlet-0.4.15/conftest.py


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/dev-requirements.txt → desktop/core/ext-py/greenlet-0.4.15/dev-requirements.txt


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/doc/Makefile → desktop/core/ext-py/greenlet-0.4.15/doc/Makefile


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/doc/conf.py → desktop/core/ext-py/greenlet-0.4.15/doc/conf.py


+ 7 - 7
desktop/core/ext-py/greenlet-0.4.12/doc/greenlet.txt → desktop/core/ext-py/greenlet-0.4.15/doc/greenlet.txt

@@ -41,7 +41,7 @@ a system, there will typically be a loop like the following one::
             while not line.endswith('\n'):
                 line += read_next_char()
             if line == 'quit\n':
-                print "are you sure?"
+                print("are you sure?")
                 if read_next_char() != 'y':
                     continue    # ignore the command
             process_command(line)
@@ -124,14 +124,14 @@ For example::
     from greenlet import greenlet
 
     def test1():
-        print 12
+        print(12)
         gr2.switch()
-        print 34
+        print(34)
 
     def test2():
-        print 56
+        print(56)
         gr1.switch()
-        print 78
+        print(78)
 
     gr1 = greenlet(test1)
     gr2 = greenlet(test2)
@@ -199,10 +199,10 @@ information between greenlets.  For example::
 
     def test1(x, y):
         z = gr2.switch(x+y)
-        print z
+        print(z)
 
     def test2(u):
-        print u
+        print(u)
         gr1.switch(42)
 
     gr1 = greenlet(test1)

+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/doc/index.txt → desktop/core/ext-py/greenlet-0.4.15/doc/index.txt


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/doc/make.bat → desktop/core/ext-py/greenlet-0.4.15/doc/make.bat


+ 49 - 6
desktop/core/ext-py/greenlet-0.4.12/greenlet.c → desktop/core/ext-py/greenlet-0.4.15/greenlet.c

@@ -153,6 +153,21 @@ static PyObject* ts_empty_dict;
 #define GREENLET_tp_is_gc 0
 #endif /* !GREENLET_USE_GC */
 
+static void green_clear_exc(PyGreenlet* g)
+{
+#ifdef GREENLET_USE_EXC_INFO
+	g->exc_info = NULL;
+	g->exc_state.exc_type = NULL;
+	g->exc_state.exc_value = NULL;
+	g->exc_state.exc_traceback = NULL;
+	g->exc_state.previous_item = NULL;
+#else
+	g->exc_type = NULL;
+	g->exc_value = NULL;
+	g->exc_traceback = NULL;
+#endif
+}
+
 static PyGreenlet* green_create_main(void)
 {
 	PyGreenlet* gmain;
@@ -460,17 +475,26 @@ static int g_switchstack(void)
 		PyThreadState* tstate = PyThreadState_GET();
 		current->recursion_depth = tstate->recursion_depth;
 		current->top_frame = tstate->frame;
+#ifdef GREENLET_USE_EXC_INFO
+		current->exc_info = tstate->exc_info;
+		current->exc_state = tstate->exc_state;
+#else
 		current->exc_type = tstate->exc_type;
 		current->exc_value = tstate->exc_value;
 		current->exc_traceback = tstate->exc_traceback;
+#endif
 	}
 	err = slp_switch();
 	if (err < 0) {   /* error */
 		PyGreenlet* current = ts_current;
 		current->top_frame = NULL;
+#ifdef GREENLET_USE_EXC_INFO
+		green_clear_exc(current);
+#else
 		current->exc_type = NULL;
 		current->exc_value = NULL;
 		current->exc_traceback = NULL;
+#endif
 
 		assert(ts_origin == NULL);
 		ts_target = NULL;
@@ -482,12 +506,15 @@ static int g_switchstack(void)
 		tstate->recursion_depth = target->recursion_depth;
 		tstate->frame = target->top_frame;
 		target->top_frame = NULL;
+#ifdef GREENLET_USE_EXC_INFO
+		tstate->exc_state = target->exc_state;
+		tstate->exc_info = target->exc_info ? target->exc_info : &tstate->exc_state;
+#else
 		tstate->exc_type = target->exc_type;
-		target->exc_type = NULL;
 		tstate->exc_value = target->exc_value;
-		target->exc_value = NULL;
 		tstate->exc_traceback = target->exc_traceback;
-		target->exc_traceback = NULL;
+#endif
+		green_clear_exc(target);
 
 		assert(ts_origin == NULL);
 		Py_INCREF(target);
@@ -740,9 +767,7 @@ static int GREENLET_NOINLINE(g_initialstub)(void* mark)
 		self->stack_prev = ts_current;
 	}
 	self->top_frame = NULL;
-	self->exc_type = NULL;
-	self->exc_value = NULL;
-	self->exc_traceback = NULL;
+	green_clear_exc(self);
 	self->recursion_depth = PyThreadState_GET()->recursion_depth;
 
 	/* restore arguments in case they are clobbered */
@@ -923,9 +948,15 @@ green_traverse(PyGreenlet *self, visitproc visit, void *arg)
 	   - frames are not visited: alive greenlets are not garbage collected anyway */
 	Py_VISIT((PyObject*)self->parent);
 	Py_VISIT(self->run_info);
+#ifdef GREENLET_USE_EXC_INFO
+	Py_VISIT(self->exc_state.exc_type);
+	Py_VISIT(self->exc_state.exc_value);
+	Py_VISIT(self->exc_state.exc_traceback);
+#else
 	Py_VISIT(self->exc_type);
 	Py_VISIT(self->exc_value);
 	Py_VISIT(self->exc_traceback);
+#endif
 	Py_VISIT(self->dict);
 	return 0;
 }
@@ -949,9 +980,15 @@ static int green_clear(PyGreenlet* self)
 	   so even if it switches we are relatively safe. */
 	Py_CLEAR(self->parent);
 	Py_CLEAR(self->run_info);
+#ifdef GREENLET_USE_EXC_INFO
+	Py_CLEAR(self->exc_state.exc_type);
+	Py_CLEAR(self->exc_state.exc_value);
+	Py_CLEAR(self->exc_state.exc_traceback);
+#else
 	Py_CLEAR(self->exc_type);
 	Py_CLEAR(self->exc_value);
 	Py_CLEAR(self->exc_traceback);
+#endif
 	Py_CLEAR(self->dict);
 	return 0;
 }
@@ -1018,9 +1055,15 @@ static void green_dealloc(PyGreenlet* self)
 		PyObject_ClearWeakRefs((PyObject *) self);
 	Py_CLEAR(self->parent);
 	Py_CLEAR(self->run_info);
+#ifdef GREENLET_USE_EXC_INFO
+	Py_CLEAR(self->exc_state.exc_type);
+	Py_CLEAR(self->exc_state.exc_value);
+	Py_CLEAR(self->exc_state.exc_traceback);
+#else
 	Py_CLEAR(self->exc_type);
 	Py_CLEAR(self->exc_value);
 	Py_CLEAR(self->exc_traceback);
+#endif
 	Py_CLEAR(self->dict);
 	Py_TYPE(self)->tp_free((PyObject*) self);
 }

+ 10 - 1
desktop/core/ext-py/greenlet-0.4.12/greenlet.h → desktop/core/ext-py/greenlet-0.4.15/greenlet.h

@@ -11,7 +11,11 @@
 extern "C" {
 #endif
 
-#define GREENLET_VERSION "0.4.12"
+#define GREENLET_VERSION "0.4.15"
+
+#if PY_VERSION_HEX >= 0x030700A3
+#  define GREENLET_USE_EXC_INFO
+#endif
 
 typedef struct _greenlet {
 	PyObject_HEAD
@@ -25,9 +29,14 @@ typedef struct _greenlet {
 	struct _frame* top_frame;
 	int recursion_depth;
 	PyObject* weakreflist;
+#ifdef GREENLET_USE_EXC_INFO
+	_PyErr_StackItem* exc_info;
+	_PyErr_StackItem exc_state;
+#else
 	PyObject* exc_type;
 	PyObject* exc_value;
 	PyObject* exc_traceback;
+#endif
 	PyObject* dict;
 } PyGreenlet;
 

+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/make-manylinux → desktop/core/ext-py/greenlet-0.4.15/make-manylinux


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/make-win-release → desktop/core/ext-py/greenlet-0.4.15/make-win-release


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/my_build_ext.py → desktop/core/ext-py/greenlet-0.4.15/my_build_ext.py


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_aarch64_gcc.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_aarch64_gcc.h


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_amd64_unix.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_amd64_unix.h


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_arm32_gcc.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_arm32_gcc.h


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_arm32_ios.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_arm32_ios.h


+ 48 - 0
desktop/core/ext-py/greenlet-0.4.15/platform/switch_csky_gcc.h

@@ -0,0 +1,48 @@
+#ifdef SLP_EVAL
+#define STACK_MAGIC 0
+#define REG_FP "r8"
+#ifdef __CSKYABIV2__
+#define REGS_TO_SAVE_GENERAL "r4", "r5", "r6", "r7", "r9", "r10", "r11", "r15",\
+                             "r16", "r17", "r18", "r19", "r20", "r21", "r22",\
+                             "r23", "r24", "r25"
+
+#if defined (__CSKY_HARD_FLOAT__) || (__CSKY_VDSP__)
+#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL, "vr8", "vr9", "vr10", "vr11", "vr12",\
+                                           "vr13", "vr14", "vr15"
+#else
+#define REGS_TO_SAVE REGS_TO_SAVE_GENERAL
+#endif
+#else
+#define REGS_TO_SAVE "r9", "r10", "r11", "r12", "r13", "r15"
+#endif
+
+
+static int
+#ifdef __GNUC__
+__attribute__((optimize("no-omit-frame-pointer")))
+#endif
+slp_switch(void)
+{
+        register int *stackref, stsizediff;
+        int result;
+
+        __asm__ volatile ("" : : : REGS_TO_SAVE);
+        __asm__ ("mov %0, sp" : "=r" (stackref));
+        {
+                SLP_SAVE_STATE(stackref, stsizediff);
+                __asm__ volatile (
+                    "addu sp,%0\n"
+                    "addu "REG_FP",%0\n"
+                    :
+                    : "r" (stsizediff)
+                    );
+		
+                SLP_RESTORE_STATE();
+        }
+        __asm__ volatile ("movi %0, 0" : "=r" (result));
+        __asm__ volatile ("" : : : REGS_TO_SAVE);
+
+        return result;
+}
+
+#endif

+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_m68k_gcc.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_m68k_gcc.h


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_mips_unix.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_mips_unix.h


+ 17 - 2
desktop/core/ext-py/greenlet-0.4.12/platform/switch_ppc64_linux.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_ppc64_linux.h

@@ -2,6 +2,14 @@
  * this is the internal transfer function.
  *
  * HISTORY
+ * 04-Sep-18  Alexey Borzenkov  <snaury@gmail.com>
+ *      Workaround a gcc bug using manual save/restore of r30
+ * 21-Mar-18  Tulio Magno Quites Machado Filho  <tuliom@linux.vnet.ibm.com>
+ *      Added r30 to the list of saved registers in order to fully comply with
+ *      both ppc64 ELFv1 ABI and the ppc64le ELFv2 ABI, that classify this
+ *      register as a nonvolatile register used for local variables.
+ * 21-Mar-18  Laszlo Boszormenyi  <gcs@debian.org>
+ *      Save r2 (TOC pointer) manually.
  * 10-Dec-13  Ulrich Weigand  <uweigand@de.ibm.com>
  *	Support ELFv2 ABI.  Save float/vector registers.
  * 09-Mar-12 Michael Ellerman <michael@ellerman.id.au>
@@ -56,8 +64,9 @@
 #define ALTIVEC_REGS
 #endif
 
-#define REGS_TO_SAVE "r2", "r14", "r15", "r16", "r17", "r18", "r19", "r20", \
-       "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r31", \
+#define REGS_TO_SAVE "r14", "r15", "r16", "r17", "r18", "r19", "r20",  \
+       "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29",  \
+       "r31",                                                    \
        "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", \
        "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", \
        "fr30", "fr31", \
@@ -69,7 +78,11 @@ slp_switch(void)
 {
     register int err;
     register long *stackref, stsizediff;
+    void * toc;
+    void * r30;
     __asm__ volatile ("" : : : REGS_TO_SAVE);
+    __asm__ volatile ("std 2, %0" : "=m" (toc));
+    __asm__ volatile ("std 30, %0" : "=m" (r30));
     __asm__ ("mr %0, 1" : "=r" (stackref) : );
     {
         SLP_SAVE_STATE(stackref, stsizediff);
@@ -82,6 +95,8 @@ slp_switch(void)
             );
         SLP_RESTORE_STATE();
     }
+    __asm__ volatile ("ld 30, %0" : : "m" (r30));
+    __asm__ volatile ("ld 2, %0" : : "m" (toc));
     __asm__ volatile ("" : : : REGS_TO_SAVE);
     __asm__ volatile ("li %0, 0" : "=r" (err));
     return err;

+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_ppc_aix.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_ppc_aix.h


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_ppc_linux.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_ppc_linux.h


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_ppc_macosx.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_ppc_macosx.h


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_ppc_unix.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_ppc_unix.h


+ 32 - 0
desktop/core/ext-py/greenlet-0.4.15/platform/switch_riscv_unix.h

@@ -0,0 +1,32 @@
+#define STACK_REFPLUS 1
+
+#ifdef SLP_EVAL
+#define STACK_MAGIC 0
+
+#define REGS_TO_SAVE "s0", "s1", "s2", "s3", "s4", "s5", \
+		     "s6", "s7", "s8", "s9", "s10", "s11", "fs0", "fs1", \
+		     "fs2", "fs3", "fs4", "fs5", "fs6", "fs7", "fs8", "fs9", \
+		     "fs10", "fs11"
+
+static int
+slp_switch(void)
+{
+  register int ret;
+  register long *stackref, stsizediff;
+  __asm__ volatile ("" : : : REGS_TO_SAVE);
+  __asm__ volatile ("mv %0, sp" : "=r" (stackref) : );
+  {
+      SLP_SAVE_STATE(stackref, stsizediff);
+      __asm__ volatile (
+	  "add sp, sp, %0\n\t"
+	  : /* no outputs */
+	  : "r" (stsizediff)
+	  );
+      SLP_RESTORE_STATE();
+  }
+  __asm__ volatile ("" : : : REGS_TO_SAVE);
+  __asm__ volatile ("mv %0, zero" : "=r" (ret) : );
+  return ret;
+}
+
+#endif

+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_s390_unix.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_s390_unix.h


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_sparc_sun_gcc.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_sparc_sun_gcc.h


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_x32_unix.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_x32_unix.h


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_x64_masm.asm → desktop/core/ext-py/greenlet-0.4.15/platform/switch_x64_masm.asm


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_x64_masm.obj → desktop/core/ext-py/greenlet-0.4.15/platform/switch_x64_masm.obj


+ 3 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_x64_msvc.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_x64_msvc.h

@@ -22,7 +22,10 @@
  *      Initial final version after lots of iterations for i386.
  */
 
+/* Avoid alloca redefined warning on mingw64 */
+#ifndef alloca
 #define alloca _alloca
+#endif
 
 #define STACK_REFPLUS 1
 #define STACK_MAGIC 0

+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_x86_msvc.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_x86_msvc.h


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/platform/switch_x86_unix.h → desktop/core/ext-py/greenlet-0.4.15/platform/switch_x86_unix.h


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/run-tests.py → desktop/core/ext-py/greenlet-0.4.15/run-tests.py


+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/setup.cfg → desktop/core/ext-py/greenlet-0.4.15/setup.cfg


+ 2 - 1
desktop/core/ext-py/greenlet-0.4.12/setup.py → desktop/core/ext-py/greenlet-0.4.15/setup.py

@@ -70,7 +70,7 @@ from my_build_ext import build_ext
 
 setup(
     name="greenlet",
-    version='0.4.12',
+    version='0.4.15',
     description='Lightweight in-process concurrent programming',
     long_description=readfile("README.rst"),
     maintainer="Alexey Borzenkov",
@@ -100,6 +100,7 @@ setup(
         'Programming Language :: Python :: 3.4',
         'Programming Language :: Python :: 3.5',
         'Programming Language :: Python :: 3.6',
+        'Programming Language :: Python :: 3.7',
         'Operating System :: OS Independent',
         'Topic :: Software Development :: Libraries :: Python Modules'],
     **setuptools_args)

+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/setup_switch_x64_masm.cmd → desktop/core/ext-py/greenlet-0.4.15/setup_switch_x64_masm.cmd


+ 5 - 1
desktop/core/ext-py/greenlet-0.4.12/slp_platformselect.h → desktop/core/ext-py/greenlet-0.4.15/slp_platformselect.h

@@ -4,7 +4,7 @@
 
 #if   defined(MS_WIN32) && !defined(MS_WIN64) && defined(_M_IX86) && defined(_MSC_VER)
 #include "platform/switch_x86_msvc.h" /* MS Visual Studio on X86 */
-#elif defined(MS_WIN64) && defined(_M_X64) && defined(_MSC_VER)
+#elif defined(MS_WIN64) && defined(_M_X64) && defined(_MSC_VER) || defined(__MINGW64__)
 #include "platform/switch_x64_msvc.h" /* MS Visual Studio on X64 */
 #elif defined(__GNUC__) && defined(__amd64__) && defined(__ILP32__)
 #include "platform/switch_x32_unix.h" /* gcc on amd64 with x32 ABI */
@@ -47,4 +47,8 @@
 #include "platform/switch_aarch64_gcc.h" /* Aarch64 ABI */
 #elif defined(__GNUC__) && defined(__mc68000__)
 #include "platform/switch_m68k_gcc.h" /* gcc on m68k */
+#elif defined(__GNUC__) && defined(__csky__)
+#include "platform/switch_csky_gcc.h" /* gcc on csky */
+#elif defined(__GNUC__) && defined(__riscv)
+#include "platform/switch_riscv_unix.h" /* gcc on RISC-V */
 #endif

+ 56 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/__init__.py

@@ -0,0 +1,56 @@
+import os
+import glob
+import unittest
+from distutils.core import setup, Extension
+
+TEST_EXTENSIONS = [
+    Extension('_test_extension',
+              [os.path.join('tests', '_test_extension.c')],
+              include_dirs=[os.path.curdir]),
+]
+
+if os.environ.get('GREENLET_TEST_CPP', 'yes').lower() not in ('0', 'no', 'false'):
+    TEST_EXTENSIONS_CPP = [
+        Extension('_test_extension_cpp',
+                  [os.path.join('tests', '_test_extension_cpp.cpp')],
+                  language="c++",
+                  include_dirs=[os.path.curdir]),
+    ]
+else:
+    TEST_EXTENSIONS_CPP = []
+
+
+def test_collector(build_base=None):
+    """Collect all tests under the tests directory and return a
+    unittest.TestSuite
+    """
+    build_test_extensions(build_base)
+    tests_dir = os.path.realpath(os.path.dirname(__file__))
+    test_module_list = [
+        'tests.%s' % os.path.splitext(os.path.basename(t))[0]
+        for t in glob.glob(os.path.join(tests_dir, 'test_*.py'))]
+    if not TEST_EXTENSIONS_CPP:
+        test_module_list.remove('tests.test_cpp')
+    return unittest.TestLoader().loadTestsFromNames(test_module_list)
+
+
+def build_test_extensions(build_base=None):
+    """Because distutils sucks, it just copies the entire contents of the build
+    results dir (e.g. build/lib.linux-i686-2.6) during installation. That means
+    that we can't put any files there that we don't want to distribute.
+
+    To deal with it, this code will compile test extensions in a separate
+    directory, prepending it to sys.path afterwards. This way testing with
+    multiple Python release and pydebug versions works and test extensions
+    are not distributed.
+    """
+    if build_base is None:
+        build_base = os.path.join('build', 'tests')
+    from my_build_ext import build_ext
+    setup(
+        options={
+            'build': {'build_base': build_base},
+        },
+        cmdclass=dict(build_ext=build_ext),
+        script_args=['-q', 'build_ext', '-q'],
+        ext_modules=TEST_EXTENSIONS + TEST_EXTENSIONS_CPP)

+ 208 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/_test_extension.c

@@ -0,0 +1,208 @@
+/* This is a set of functions used by test_extension_interface.py to test the
+ * Greenlet C API.
+ */
+
+#include "../greenlet.h"
+
+#ifndef Py_RETURN_NONE
+#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
+#endif
+
+#define TEST_MODULE_NAME "_test_extension"
+
+static PyObject *
+test_switch(PyObject *self, PyObject *greenlet)
+{
+	PyObject *result = NULL;
+
+	if (greenlet == NULL || !PyGreenlet_Check(greenlet)) {
+		PyErr_BadArgument();
+		return NULL;
+	}
+
+	result = PyGreenlet_Switch((PyGreenlet *) greenlet, NULL, NULL);
+	if (result == NULL) {
+		if (!PyErr_Occurred()) {
+			PyErr_SetString(
+				PyExc_AssertionError,
+				"greenlet.switch() failed for some reason.");
+		}
+		return NULL;
+	}
+	Py_INCREF(result);
+	return result;
+}
+
+static PyObject *
+test_switch_kwargs(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+	PyGreenlet *g = NULL;
+	PyObject *result = NULL;
+
+	PyArg_ParseTuple(args, "O!", &PyGreenlet_Type, &g);
+
+	if (g == NULL || !PyGreenlet_Check(g)) {
+		PyErr_BadArgument();
+		return NULL;
+	}
+
+	result = PyGreenlet_Switch(g, NULL, kwargs);
+	if (result == NULL) {
+		if (!PyErr_Occurred()) {
+			PyErr_SetString(
+				PyExc_AssertionError,
+				"greenlet.switch() failed for some reason.");
+		}
+		return NULL;
+	}
+	Py_XINCREF(result);
+	return result;
+}
+
+static PyObject *
+test_getcurrent(PyObject *self)
+{
+	PyGreenlet *g = PyGreenlet_GetCurrent();
+	if (g == NULL || !PyGreenlet_Check(g) || !PyGreenlet_ACTIVE(g)) {
+		PyErr_SetString(
+			PyExc_AssertionError,
+			"getcurrent() returned an invalid greenlet");
+		Py_XDECREF(g);
+		return NULL;
+	}
+	Py_DECREF(g);
+	Py_RETURN_NONE;
+}
+
+static PyObject *
+test_setparent(PyObject *self, PyObject *arg)
+{
+	PyGreenlet *current;
+	PyGreenlet *greenlet = NULL;
+
+	if (arg == NULL || !PyGreenlet_Check(arg))
+	{
+		PyErr_BadArgument();
+		return NULL;
+	}
+	if ((current = PyGreenlet_GetCurrent()) == NULL) {
+		return NULL;
+	}
+	greenlet = (PyGreenlet *) arg;
+	if (PyGreenlet_SetParent(greenlet, current)) {
+		Py_DECREF(current);
+		return NULL;
+	}
+	Py_DECREF(current);
+	if (PyGreenlet_Switch(greenlet, NULL, NULL) == NULL) {
+		return NULL;
+	}
+	Py_RETURN_NONE;
+}
+
+static PyObject *
+test_new_greenlet(PyObject *self, PyObject *callable)
+{
+	PyObject *result = NULL;
+	PyGreenlet *greenlet = PyGreenlet_New(callable, NULL);
+
+	if (!greenlet) {
+		return NULL;
+	}
+
+	result = PyGreenlet_Switch(greenlet, NULL, NULL);
+	if (result == NULL) {
+		return NULL;
+	}
+
+	Py_INCREF(result);
+	return result;
+}
+
+static PyObject *
+test_raise_dead_greenlet(PyObject *self)
+{
+	PyErr_SetString(PyExc_GreenletExit, "test GreenletExit exception.");
+	return NULL;
+}
+
+static PyObject *
+test_raise_greenlet_error(PyObject *self)
+{
+	PyErr_SetString(PyExc_GreenletError, "test greenlet.error exception");
+	return NULL;
+}
+
+static PyObject *
+test_throw(PyObject *self, PyGreenlet *g)
+{
+	const char msg[] = "take that sucka!";
+	PyObject *msg_obj = Py_BuildValue("s", msg);
+	PyGreenlet_Throw(g, PyExc_ValueError, msg_obj, NULL);
+	Py_DECREF(msg_obj);
+	Py_RETURN_NONE;
+}
+
+static PyMethodDef test_methods[] = {
+	{"test_switch", (PyCFunction) test_switch, METH_O,
+	 "Switch to the provided greenlet sending provided arguments, and \n"
+	 "return the results."},
+	{"test_switch_kwargs", (PyCFunction) test_switch_kwargs,
+	 METH_VARARGS | METH_KEYWORDS,
+	 "Switch to the provided greenlet sending the provided keyword args."},
+	{"test_getcurrent", (PyCFunction) test_getcurrent, METH_NOARGS,
+	 "Test PyGreenlet_GetCurrent()"},
+	{"test_setparent", (PyCFunction) test_setparent, METH_O,
+	 "Se the parent of the provided greenlet and switch to it."},
+	{"test_new_greenlet", (PyCFunction) test_new_greenlet, METH_O,
+	 "Test PyGreenlet_New()"},
+	{"test_raise_dead_greenlet", (PyCFunction) test_raise_dead_greenlet,
+	 METH_NOARGS, "Just raise greenlet.GreenletExit"},
+	{"test_raise_greenlet_error", (PyCFunction) test_raise_greenlet_error,
+	 METH_NOARGS, "Just raise greenlet.error"},
+	{"test_throw", (PyCFunction) test_throw, METH_O,
+	 "Throw a ValueError at the provided greenlet"},
+	{NULL, NULL, 0, NULL}
+};
+
+#if PY_MAJOR_VERSION >= 3
+#define INITERROR return NULL
+
+static struct PyModuleDef moduledef = {
+	PyModuleDef_HEAD_INIT,
+	TEST_MODULE_NAME,
+	NULL,
+	0,
+	test_methods,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+PyMODINIT_FUNC
+PyInit__test_extension(void)
+#else
+#define INITERROR return
+PyMODINIT_FUNC
+init_test_extension(void)
+#endif
+{
+	PyObject *module = NULL;
+
+#if PY_MAJOR_VERSION >= 3
+	module = PyModule_Create(&moduledef);
+#else
+	module = Py_InitModule(TEST_MODULE_NAME, test_methods);
+#endif
+
+	if (module == NULL) {
+		INITERROR;
+	}
+
+	PyGreenlet_Import();
+
+#if PY_MAJOR_VERSION >= 3
+	return module;
+#endif
+}

+ 118 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/_test_extension_cpp.cpp

@@ -0,0 +1,118 @@
+/* This is a set of functions used to test C++ exceptions are not
+ * broken during greenlet switches
+ */
+
+#include "../greenlet.h"
+
+struct exception_t
+{
+	int depth;
+	exception_t(int depth) : depth(depth) { }
+};
+
+/* Functions are called via pointers to prevent inlining */
+static void (*p_test_exception_throw)(int depth);
+static PyObject* (*p_test_exception_switch_recurse)(int depth, int left);
+
+static void test_exception_throw(int depth)
+{
+	throw exception_t(depth);
+}
+
+static PyObject* test_exception_switch_recurse(int depth, int left)
+{
+	if (left > 0) {
+		return p_test_exception_switch_recurse(depth, left - 1);
+	}
+
+	PyObject* result = NULL;
+	PyGreenlet* self = PyGreenlet_GetCurrent();
+	if (self == NULL)
+		return NULL;
+
+	try {
+		PyGreenlet_Switch(self->parent, NULL, NULL);
+		p_test_exception_throw(depth);
+		PyErr_SetString(PyExc_RuntimeError, "throwing C++ exception didn't work");
+	} catch(exception_t& e) {
+		if (e.depth != depth)
+			PyErr_SetString(PyExc_AssertionError, "depth mismatch");
+		else
+			result = PyLong_FromLong(depth);
+	} catch(...) {
+		PyErr_SetString(PyExc_RuntimeError, "unexpected C++ exception");
+	}
+
+	Py_DECREF(self);
+	return result;
+}
+
+/* test_exception_switch(int depth)
+ * - recurses depth times
+ * - switches to parent inside try/catch block
+ * - throws an exception that (expected to be caught in the same function)
+ * - verifies depth matches (exceptions shouldn't be caught in other greenlets)
+ */
+static PyObject *
+test_exception_switch(PyObject *self, PyObject *args)
+{
+	int depth;
+	if (!PyArg_ParseTuple(args, "i", &depth))
+		return NULL;
+	return p_test_exception_switch_recurse(depth, depth);
+}
+
+static PyMethodDef test_methods[] = {
+	{"test_exception_switch", (PyCFunction)&test_exception_switch, METH_VARARGS,
+	 "Switches to parent twice, to test exception handling and greenlet switching."},
+	{NULL, NULL, 0, NULL}
+};
+
+
+#if PY_MAJOR_VERSION >= 3
+#define INITERROR return NULL
+
+static struct PyModuleDef moduledef = {
+	PyModuleDef_HEAD_INIT,
+	"_test_extension_cpp",
+	NULL,
+	0,
+	test_methods,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+
+PyMODINIT_FUNC
+PyInit__test_extension_cpp(void)
+#else
+#define INITERROR return
+PyMODINIT_FUNC
+init_test_extension_cpp(void)
+#endif
+{
+	PyObject *module = NULL;
+
+#if PY_MAJOR_VERSION >= 3
+	module = PyModule_Create(&moduledef);
+#else
+	module = Py_InitModule("_test_extension_cpp", test_methods);
+#endif
+
+	if (module == NULL) {
+		INITERROR;
+	}
+
+	PyGreenlet_Import();
+	if (_PyGreenlet_API == NULL) {
+		INITERROR;
+	}
+
+	p_test_exception_throw = test_exception_throw;
+	p_test_exception_switch_recurse = test_exception_switch_recurse;
+
+#if PY_MAJOR_VERSION >= 3
+	return module;
+#endif
+}

+ 15 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/test_cpp.py

@@ -0,0 +1,15 @@
+import unittest
+
+import greenlet
+import _test_extension_cpp
+
+
+class CPPTests(unittest.TestCase):
+    def test_exception_switch(self):
+        greenlets = []
+        for i in range(4):
+            g = greenlet.greenlet(_test_extension_cpp.test_exception_switch)
+            g.switch(i)
+            greenlets.append(g)
+        for i, g in enumerate(greenlets):
+            self.assertEqual(g.switch(), i)

+ 71 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/test_extension_interface.py

@@ -0,0 +1,71 @@
+import sys
+import unittest
+
+import greenlet
+import _test_extension
+
+
+class CAPITests(unittest.TestCase):
+    def test_switch(self):
+        self.assertEqual(
+            50, _test_extension.test_switch(greenlet.greenlet(lambda: 50)))
+
+    def test_switch_kwargs(self):
+        def foo(x, y):
+            return x * y
+        g = greenlet.greenlet(foo)
+        self.assertEqual(6, _test_extension.test_switch_kwargs(g, x=3, y=2))
+
+    def test_setparent(self):
+        def foo():
+            def bar():
+                greenlet.getcurrent().parent.switch()
+
+                # This final switch should go back to the main greenlet, since
+                # the test_setparent() function in the C extension should have
+                # reparented this greenlet.
+                greenlet.getcurrent().parent.switch()
+                raise AssertionError("Should never have reached this code")
+            child = greenlet.greenlet(bar)
+            child.switch()
+            greenlet.getcurrent().parent.switch(child)
+            greenlet.getcurrent().parent.throw(
+                AssertionError("Should never reach this code"))
+        foo_child = greenlet.greenlet(foo).switch()
+        self.assertEqual(None, _test_extension.test_setparent(foo_child))
+
+    def test_getcurrent(self):
+        _test_extension.test_getcurrent()
+
+    def test_new_greenlet(self):
+        self.assertEqual(-15, _test_extension.test_new_greenlet(lambda: -15))
+
+    def test_raise_greenlet_dead(self):
+        self.assertRaises(
+            greenlet.GreenletExit, _test_extension.test_raise_dead_greenlet)
+
+    def test_raise_greenlet_error(self):
+        self.assertRaises(
+            greenlet.error, _test_extension.test_raise_greenlet_error)
+
+    def test_throw(self):
+        seen = []
+
+        def foo():
+            try:
+                greenlet.getcurrent().parent.switch()
+            except ValueError:
+                seen.append(sys.exc_info()[1])
+            except greenlet.GreenletExit:
+                raise AssertionError
+        g = greenlet.greenlet(foo)
+        g.switch()
+        _test_extension.test_throw(g)
+        self.assertEqual(len(seen), 1)
+        self.assertTrue(
+            isinstance(seen[0], ValueError),
+            "ValueError was not raised in foo()")
+        self.assertEqual(
+            str(seen[0]),
+            'take that sucka!',
+            "message doesn't match")

+ 77 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/test_gc.py

@@ -0,0 +1,77 @@
+import gc
+import sys
+import unittest
+import weakref
+
+import greenlet
+
+
+class GCTests(unittest.TestCase):
+    def test_dead_circular_ref(self):
+        o = weakref.ref(greenlet.greenlet(greenlet.getcurrent).switch())
+        gc.collect()
+        self.assertTrue(o() is None)
+        self.assertFalse(gc.garbage, gc.garbage)
+
+    if greenlet.GREENLET_USE_GC:
+        # These only work with greenlet gc support
+
+        def test_circular_greenlet(self):
+            class circular_greenlet(greenlet.greenlet):
+                pass
+            o = circular_greenlet()
+            o.self = o
+            o = weakref.ref(o)
+            gc.collect()
+            self.assertTrue(o() is None)
+            self.assertFalse(gc.garbage, gc.garbage)
+
+        def test_inactive_ref(self):
+            class inactive_greenlet(greenlet.greenlet):
+                def __init__(self):
+                    greenlet.greenlet.__init__(self, run=self.run)
+
+                def run(self):
+                    pass
+            o = inactive_greenlet()
+            o = weakref.ref(o)
+            gc.collect()
+            self.assertTrue(o() is None)
+            self.assertFalse(gc.garbage, gc.garbage)
+
+        def test_finalizer_crash(self):
+            # This test is designed to crash when active greenlets
+            # are made garbage collectable, until the underlying
+            # problem is resolved. How does it work:
+            # - order of object creation is important
+            # - array is created first, so it is moved to unreachable first
+            # - we create a cycle between a greenlet and this array
+            # - we create an object that participates in gc, is only
+            #   referenced by a greenlet, and would corrupt gc lists
+            #   on destruction, the easiest is to use an object with
+            #   a finalizer
+            # - because array is the first object in unreachable it is
+            #   cleared first, which causes all references to greenlet
+            #   to disappear and causes greenlet to be destroyed, but since
+            #   it is still live it causes a switch during gc, which causes
+            #   an object with finalizer to be destroyed, which causes stack
+            #   corruption and then a crash
+            class object_with_finalizer(object):
+                def __del__(self):
+                    pass
+            array = []
+            parent = greenlet.getcurrent()
+            def greenlet_body():
+                greenlet.getcurrent().object = object_with_finalizer()
+                try:
+                    parent.switch()
+                finally:
+                    del greenlet.getcurrent().object
+            g = greenlet.greenlet(greenlet_body)
+            g.array = array
+            array.append(g)
+            g.switch()
+            del array
+            del g
+            greenlet.getcurrent()
+            gc.collect()

+ 59 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/test_generator.py

@@ -0,0 +1,59 @@
+import unittest
+from greenlet import greenlet
+
+
+class genlet(greenlet):
+
+    def __init__(self, *args, **kwds):
+        self.args = args
+        self.kwds = kwds
+
+    def run(self):
+        fn, = self.fn
+        fn(*self.args, **self.kwds)
+
+    def __iter__(self):
+        return self
+
+    def __next__(self):
+        self.parent = greenlet.getcurrent()
+        result = self.switch()
+        if self:
+            return result
+        else:
+            raise StopIteration
+
+    # Hack: Python < 2.6 compatibility
+    next = __next__
+
+
+def Yield(value):
+    g = greenlet.getcurrent()
+    while not isinstance(g, genlet):
+        if g is None:
+            raise RuntimeError('yield outside a genlet')
+        g = g.parent
+    g.parent.switch(value)
+
+
+def generator(func):
+    class generator(genlet):
+        fn = (func,)
+    return generator
+
+# ____________________________________________________________
+
+
+class GeneratorTests(unittest.TestCase):
+    def test_generator(self):
+        seen = []
+
+        def g(n):
+            for i in range(n):
+                seen.append(i)
+                Yield(i)
+        g = generator(g)
+        for k in range(3):
+            for j in g(5):
+                seen.append(j)
+        self.assertEqual(seen, 3 * [0, 0, 1, 1, 2, 2, 3, 3, 4, 4])

+ 165 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/test_generator_nested.py

@@ -0,0 +1,165 @@
+import unittest
+from greenlet import greenlet
+
+
+class genlet(greenlet):
+
+    def __init__(self, *args, **kwds):
+        self.args = args
+        self.kwds = kwds
+        self.child = None
+
+    def run(self):
+        fn, = self.fn
+        fn(*self.args, **self.kwds)
+
+    def __iter__(self):
+        return self
+
+    def set_child(self, child):
+        self.child = child
+
+    def __next__(self):
+        if self.child:
+            child = self.child
+            while child.child:
+                tmp = child
+                child = child.child
+                tmp.child = None
+
+            result = child.switch()
+        else:
+            self.parent = greenlet.getcurrent()
+            result = self.switch()
+
+        if self:
+            return result
+        else:
+            raise StopIteration
+
+    # Hack: Python < 2.6 compatibility
+    next = __next__
+
+
+def Yield(value, level=1):
+    g = greenlet.getcurrent()
+
+    while level != 0:
+        if not isinstance(g, genlet):
+            raise RuntimeError('yield outside a genlet')
+        if level > 1:
+            g.parent.set_child(g)
+        g = g.parent
+        level -= 1
+
+    g.switch(value)
+
+
+def Genlet(func):
+    class Genlet(genlet):
+        fn = (func,)
+    return Genlet
+
+# ____________________________________________________________
+
+
+def g1(n, seen):
+    for i in range(n):
+        seen.append(i + 1)
+        yield i
+
+
+def g2(n, seen):
+    for i in range(n):
+        seen.append(i + 1)
+        Yield(i)
+
+g2 = Genlet(g2)
+
+
+def nested(i):
+    Yield(i)
+
+
+def g3(n, seen):
+    for i in range(n):
+        seen.append(i + 1)
+        nested(i)
+g3 = Genlet(g3)
+
+
+def a(n):
+    if n == 0:
+        return
+    for ii in ax(n - 1):
+        Yield(ii)
+    Yield(n)
+ax = Genlet(a)
+
+
+def perms(l):
+    if len(l) > 1:
+        for e in l:
+            # No syntactical sugar for generator expressions
+            [Yield([e] + p) for p in perms([x for x in l if x != e])]
+    else:
+        Yield(l)
+perms = Genlet(perms)
+
+
+def gr1(n):
+    for ii in range(1, n):
+        Yield(ii)
+        Yield(ii * ii, 2)
+
+gr1 = Genlet(gr1)
+
+
+def gr2(n, seen):
+    for ii in gr1(n):
+        seen.append(ii)
+
+gr2 = Genlet(gr2)
+
+
+class NestedGeneratorTests(unittest.TestCase):
+    def test_layered_genlets(self):
+        seen = []
+        for ii in gr2(5, seen):
+            seen.append(ii)
+        self.assertEqual(seen, [1, 1, 2, 4, 3, 9, 4, 16])
+
+    def test_permutations(self):
+        gen_perms = perms(list(range(4)))
+        permutations = list(gen_perms)
+        self.assertEqual(len(permutations), 4 * 3 * 2 * 1)
+        self.assertTrue([0, 1, 2, 3] in permutations)
+        self.assertTrue([3, 2, 1, 0] in permutations)
+        res = []
+        for ii in zip(perms(list(range(4))), perms(list(range(3)))):
+            res.append(ii)
+        self.assertEqual(
+            res,
+            [([0, 1, 2, 3], [0, 1, 2]), ([0, 1, 3, 2], [0, 2, 1]),
+             ([0, 2, 1, 3], [1, 0, 2]), ([0, 2, 3, 1], [1, 2, 0]),
+             ([0, 3, 1, 2], [2, 0, 1]), ([0, 3, 2, 1], [2, 1, 0])])
+        # XXX Test to make sure we are working as a generator expression
+
+    def test_genlet_simple(self):
+        for g in [g1, g2, g3]:
+            seen = []
+            for k in range(3):
+                for j in g(5, seen):
+                    seen.append(j)
+            self.assertEqual(seen, 3 * [1, 0, 2, 1, 3, 2, 4, 3, 5, 4])
+
+    def test_genlet_bad(self):
+        try:
+            Yield(10)
+        except RuntimeError:
+            pass
+
+    def test_nested_genlets(self):
+        seen = []
+        for ii in ax(5):
+            seen.append(ii)

+ 542 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/test_greenlet.py

@@ -0,0 +1,542 @@
+import gc
+import sys
+import time
+import threading
+import unittest
+
+from greenlet import greenlet
+
+try:
+    from abc import ABCMeta, abstractmethod
+except ImportError:
+    ABCMeta = None
+    abstractmethod = None
+
+
+class SomeError(Exception):
+    pass
+
+
+def fmain(seen):
+    try:
+        greenlet.getcurrent().parent.switch()
+    except:
+        seen.append(sys.exc_info()[0])
+        raise
+    raise SomeError
+
+
+def send_exception(g, exc):
+    # note: send_exception(g, exc)  can be now done with  g.throw(exc).
+    # the purpose of this test is to explicitely check the propagation rules.
+    def crasher(exc):
+        raise exc
+    g1 = greenlet(crasher, parent=g)
+    g1.switch(exc)
+
+
+class GreenletTests(unittest.TestCase):
+    def test_simple(self):
+        lst = []
+
+        def f():
+            lst.append(1)
+            greenlet.getcurrent().parent.switch()
+            lst.append(3)
+        g = greenlet(f)
+        lst.append(0)
+        g.switch()
+        lst.append(2)
+        g.switch()
+        lst.append(4)
+        self.assertEqual(lst, list(range(5)))
+
+    def test_parent_equals_None(self):
+        g = greenlet(parent=None)
+
+    def test_run_equals_None(self):
+        g = greenlet(run=None)
+
+    def test_two_children(self):
+        lst = []
+
+        def f():
+            lst.append(1)
+            greenlet.getcurrent().parent.switch()
+            lst.extend([1, 1])
+        g = greenlet(f)
+        h = greenlet(f)
+        g.switch()
+        self.assertEqual(len(lst), 1)
+        h.switch()
+        self.assertEqual(len(lst), 2)
+        h.switch()
+        self.assertEqual(len(lst), 4)
+        self.assertEqual(h.dead, True)
+        g.switch()
+        self.assertEqual(len(lst), 6)
+        self.assertEqual(g.dead, True)
+
+    def test_two_recursive_children(self):
+        lst = []
+
+        def f():
+            lst.append(1)
+            greenlet.getcurrent().parent.switch()
+
+        def g():
+            lst.append(1)
+            g = greenlet(f)
+            g.switch()
+            lst.append(1)
+        g = greenlet(g)
+        g.switch()
+        self.assertEqual(len(lst), 3)
+        self.assertEqual(sys.getrefcount(g), 2)
+
+    def test_threads(self):
+        success = []
+
+        def f():
+            self.test_simple()
+            success.append(True)
+        ths = [threading.Thread(target=f) for i in range(10)]
+        for th in ths:
+            th.start()
+        for th in ths:
+            th.join()
+        self.assertEqual(len(success), len(ths))
+
+    def test_exception(self):
+        seen = []
+        g1 = greenlet(fmain)
+        g2 = greenlet(fmain)
+        g1.switch(seen)
+        g2.switch(seen)
+        g2.parent = g1
+        self.assertEqual(seen, [])
+        self.assertRaises(SomeError, g2.switch)
+        self.assertEqual(seen, [SomeError])
+        g2.switch()
+        self.assertEqual(seen, [SomeError])
+
+    def test_send_exception(self):
+        seen = []
+        g1 = greenlet(fmain)
+        g1.switch(seen)
+        self.assertRaises(KeyError, send_exception, g1, KeyError)
+        self.assertEqual(seen, [KeyError])
+
+    def test_dealloc(self):
+        seen = []
+        g1 = greenlet(fmain)
+        g2 = greenlet(fmain)
+        g1.switch(seen)
+        g2.switch(seen)
+        self.assertEqual(seen, [])
+        del g1
+        gc.collect()
+        self.assertEqual(seen, [greenlet.GreenletExit])
+        del g2
+        gc.collect()
+        self.assertEqual(seen, [greenlet.GreenletExit, greenlet.GreenletExit])
+
+    def test_dealloc_other_thread(self):
+        seen = []
+        someref = []
+        lock = threading.Lock()
+        lock.acquire()
+        lock2 = threading.Lock()
+        lock2.acquire()
+
+        def f():
+            g1 = greenlet(fmain)
+            g1.switch(seen)
+            someref.append(g1)
+            del g1
+            gc.collect()
+            lock.release()
+            lock2.acquire()
+            greenlet()   # trigger release
+            lock.release()
+            lock2.acquire()
+        t = threading.Thread(target=f)
+        t.start()
+        lock.acquire()
+        self.assertEqual(seen, [])
+        self.assertEqual(len(someref), 1)
+        del someref[:]
+        gc.collect()
+        # g1 is not released immediately because it's from another thread
+        self.assertEqual(seen, [])
+        lock2.release()
+        lock.acquire()
+        self.assertEqual(seen, [greenlet.GreenletExit])
+        lock2.release()
+        t.join()
+
+    def test_frame(self):
+        def f1():
+            f = sys._getframe(0)
+            self.assertEqual(f.f_back, None)
+            greenlet.getcurrent().parent.switch(f)
+            return "meaning of life"
+        g = greenlet(f1)
+        frame = g.switch()
+        self.assertTrue(frame is g.gr_frame)
+        self.assertTrue(g)
+        next = g.switch()
+        self.assertFalse(g)
+        self.assertEqual(next, 'meaning of life')
+        self.assertEqual(g.gr_frame, None)
+
+    def test_thread_bug(self):
+        def runner(x):
+            g = greenlet(lambda: time.sleep(x))
+            g.switch()
+        t1 = threading.Thread(target=runner, args=(0.2,))
+        t2 = threading.Thread(target=runner, args=(0.3,))
+        t1.start()
+        t2.start()
+        t1.join()
+        t2.join()
+
+    def test_switch_kwargs(self):
+        def foo(a, b):
+            self.assertEqual(a, 4)
+            self.assertEqual(b, 2)
+        greenlet(foo).switch(a=4, b=2)
+
+    def test_switch_kwargs_to_parent(self):
+        def foo(x):
+            greenlet.getcurrent().parent.switch(x=x)
+            greenlet.getcurrent().parent.switch(2, x=3)
+            return x, x ** 2
+        g = greenlet(foo)
+        self.assertEqual({'x': 3}, g.switch(3))
+        self.assertEqual(((2,), {'x': 3}), g.switch())
+        self.assertEqual((3, 9), g.switch())
+
+    def test_switch_to_another_thread(self):
+        data = {}
+        error = None
+        created_event = threading.Event()
+        done_event = threading.Event()
+
+        def foo():
+            data['g'] = greenlet(lambda: None)
+            created_event.set()
+            done_event.wait()
+        thread = threading.Thread(target=foo)
+        thread.start()
+        created_event.wait()
+        try:
+            data['g'].switch()
+        except greenlet.error:
+            error = sys.exc_info()[1]
+        self.assertTrue(error != None, "greenlet.error was not raised!")
+        done_event.set()
+        thread.join()
+
+    def test_exc_state(self):
+        def f():
+            try:
+                raise ValueError('fun')
+            except:
+                exc_info = sys.exc_info()
+                greenlet(h).switch()
+                self.assertEqual(exc_info, sys.exc_info())
+
+        def h():
+            self.assertEqual(sys.exc_info(), (None, None, None))
+
+        greenlet(f).switch()
+
+    def test_instance_dict(self):
+        def f():
+            greenlet.getcurrent().test = 42
+        def deldict(g):
+            del g.__dict__
+        def setdict(g, value):
+            g.__dict__ = value
+        g = greenlet(f)
+        self.assertEqual(g.__dict__, {})
+        g.switch()
+        self.assertEqual(g.test, 42)
+        self.assertEqual(g.__dict__, {'test': 42})
+        g.__dict__ = g.__dict__
+        self.assertEqual(g.__dict__, {'test': 42})
+        self.assertRaises(TypeError, deldict, g)
+        self.assertRaises(TypeError, setdict, g, 42)
+
+    def test_threaded_reparent(self):
+        data = {}
+        created_event = threading.Event()
+        done_event = threading.Event()
+
+        def foo():
+            data['g'] = greenlet(lambda: None)
+            created_event.set()
+            done_event.wait()
+
+        def blank():
+            greenlet.getcurrent().parent.switch()
+
+        def setparent(g, value):
+            g.parent = value
+
+        thread = threading.Thread(target=foo)
+        thread.start()
+        created_event.wait()
+        g = greenlet(blank)
+        g.switch()
+        self.assertRaises(ValueError, setparent, g, data['g'])
+        done_event.set()
+        thread.join()
+
+    def test_deepcopy(self):
+        import copy
+        self.assertRaises(TypeError, copy.copy, greenlet())
+        self.assertRaises(TypeError, copy.deepcopy, greenlet())
+
+    def test_parent_restored_on_kill(self):
+        hub = greenlet(lambda: None)
+        main = greenlet.getcurrent()
+        result = []
+        def worker():
+            try:
+                # Wait to be killed
+                main.switch()
+            except greenlet.GreenletExit:
+                # Resurrect and switch to parent
+                result.append(greenlet.getcurrent().parent)
+                result.append(greenlet.getcurrent())
+                hub.switch()
+        g = greenlet(worker, parent=hub)
+        g.switch()
+        del g
+        self.assertTrue(result)
+        self.assertEqual(result[0], main)
+        self.assertEqual(result[1].parent, hub)
+
+    def test_parent_return_failure(self):
+        # No run causes AttributeError on switch
+        g1 = greenlet()
+        # Greenlet that implicitly switches to parent
+        g2 = greenlet(lambda: None, parent=g1)
+        # AttributeError should propagate to us, no fatal errors
+        self.assertRaises(AttributeError, g2.switch)
+
+    def test_throw_exception_not_lost(self):
+        class mygreenlet(greenlet):
+            def __getattribute__(self, name):
+                try:
+                    raise Exception()
+                except:
+                    pass
+                return greenlet.__getattribute__(self, name)
+        g = mygreenlet(lambda: None)
+        self.assertRaises(SomeError, g.throw, SomeError())
+
+    def test_throw_doesnt_crash(self):
+        result = []
+        def worker():
+            greenlet.getcurrent().parent.switch()
+        def creator():
+            g = greenlet(worker)
+            g.switch()
+            result.append(g)
+        t = threading.Thread(target=creator)
+        t.start()
+        t.join()
+        self.assertRaises(greenlet.error, result[0].throw, SomeError())
+
+    def test_recursive_startup(self):
+        class convoluted(greenlet):
+            def __init__(self):
+                greenlet.__init__(self)
+                self.count = 0
+            def __getattribute__(self, name):
+                if name == 'run' and self.count == 0:
+                    self.count = 1
+                    self.switch(43)
+                return greenlet.__getattribute__(self, name)
+            def run(self, value):
+                while True:
+                    self.parent.switch(value)
+        g = convoluted()
+        self.assertEqual(g.switch(42), 43)
+
+    def test_unexpected_reparenting(self):
+        another = []
+        def worker():
+            g = greenlet(lambda: None)
+            another.append(g)
+            g.switch()
+        t = threading.Thread(target=worker)
+        t.start()
+        t.join()
+        class convoluted(greenlet):
+            def __getattribute__(self, name):
+                if name == 'run':
+                    self.parent = another[0]
+                return greenlet.__getattribute__(self, name)
+        g = convoluted(lambda: None)
+        self.assertRaises(greenlet.error, g.switch)
+
+    def test_threaded_updatecurrent(self):
+        # released when main thread should execute
+        lock1 = threading.Lock()
+        lock1.acquire()
+        # released when another thread should execute
+        lock2 = threading.Lock()
+        lock2.acquire()
+        class finalized(object):
+            def __del__(self):
+                # happens while in green_updatecurrent() in main greenlet
+                # should be very careful not to accidentally call it again
+                # at the same time we must make sure another thread executes
+                lock2.release()
+                lock1.acquire()
+                # now ts_current belongs to another thread
+        def deallocator():
+            greenlet.getcurrent().parent.switch()
+        def fthread():
+            lock2.acquire()
+            greenlet.getcurrent()
+            del g[0]
+            lock1.release()
+            lock2.acquire()
+            greenlet.getcurrent()
+            lock1.release()
+        main = greenlet.getcurrent()
+        g = [greenlet(deallocator)]
+        g[0].bomb = finalized()
+        g[0].switch()
+        t = threading.Thread(target=fthread)
+        t.start()
+        # let another thread grab ts_current and deallocate g[0]
+        lock2.release()
+        lock1.acquire()
+        # this is the corner stone
+        # getcurrent() will notice that ts_current belongs to another thread
+        # and start the update process, which would notice that g[0] should
+        # be deallocated, and that will execute an object's finalizer. Now,
+        # that object will let another thread run so it can grab ts_current
+        # again, which would likely crash the interpreter if there's no
+        # check for this case at the end of green_updatecurrent(). This test
+        # passes if getcurrent() returns correct result, but it's likely
+        # to randomly crash if it's not anyway.
+        self.assertEqual(greenlet.getcurrent(), main)
+        # wait for another thread to complete, just in case
+        t.join()
+
+    def test_dealloc_switch_args_not_lost(self):
+        seen = []
+        def worker():
+            # wait for the value
+            value = greenlet.getcurrent().parent.switch()
+            # delete all references to ourself
+            del worker[0]
+            initiator.parent = greenlet.getcurrent().parent
+            # switch to main with the value, but because
+            # ts_current is the last reference to us we
+            # return immediately
+            try:
+                greenlet.getcurrent().parent.switch(value)
+            finally:
+                seen.append(greenlet.getcurrent())
+        def initiator():
+            return 42 # implicitly falls thru to parent
+        worker = [greenlet(worker)]
+        worker[0].switch() # prime worker
+        initiator = greenlet(initiator, worker[0])
+        value = initiator.switch()
+        self.assertTrue(seen)
+        self.assertEqual(value, 42)
+
+    if sys.version_info[0] == 2:
+        # There's no apply in Python 3.x
+        def test_tuple_subclass(self):
+            class mytuple(tuple):
+                def __len__(self):
+                    greenlet.getcurrent().switch()
+                    return tuple.__len__(self)
+            args = mytuple()
+            kwargs = dict(a=42)
+            def switchapply():
+                apply(greenlet.getcurrent().parent.switch, args, kwargs)
+            g = greenlet(switchapply)
+            self.assertEqual(g.switch(), kwargs)
+
+    if ABCMeta is not None and abstractmethod is not None:
+        def test_abstract_subclasses(self):
+            AbstractSubclass = ABCMeta(
+                'AbstractSubclass',
+                (greenlet,),
+                {'run': abstractmethod(lambda self: None)})
+
+            class BadSubclass(AbstractSubclass):
+                pass
+
+            class GoodSubclass(AbstractSubclass):
+                def run(self):
+                    pass
+
+            GoodSubclass() # should not raise
+            self.assertRaises(TypeError, BadSubclass)
+
+    def test_implicit_parent_with_threads(self):
+        if not gc.isenabled():
+            return # cannot test with disabled gc
+        N = gc.get_threshold()[0]
+        if N < 50:
+            return # cannot test with such a small N
+        def attempt():
+            lock1 = threading.Lock()
+            lock1.acquire()
+            lock2 = threading.Lock()
+            lock2.acquire()
+            recycled = [False]
+            def another_thread():
+                lock1.acquire() # wait for gc
+                greenlet.getcurrent() # update ts_current
+                lock2.release() # release gc
+            t = threading.Thread(target=another_thread)
+            t.start()
+            class gc_callback(object):
+                def __del__(self):
+                    lock1.release()
+                    lock2.acquire()
+                    recycled[0] = True
+            class garbage(object):
+                def __init__(self):
+                    self.cycle = self
+                    self.callback = gc_callback()
+            l = []
+            x = range(N*2)
+            current = greenlet.getcurrent()
+            g = garbage()
+            for i in x:
+                g = None # lose reference to garbage
+                if recycled[0]:
+                    # gc callback called prematurely
+                    t.join()
+                    return False
+                last = greenlet()
+                if recycled[0]:
+                    break # yes! gc called in green_new
+                l.append(last) # increase allocation counter
+            else:
+                # gc callback not called when expected
+                gc.collect()
+                if recycled[0]:
+                    t.join()
+                return False
+            self.assertEqual(last.parent, current)
+            for g in l:
+                self.assertEqual(g.parent, current)
+            return True
+        for i in range(5):
+            if attempt():
+                break

+ 85 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/test_leaks.py

@@ -0,0 +1,85 @@
+import unittest
+import sys
+import gc
+
+import time
+import weakref
+import greenlet
+import threading
+
+
+class ArgRefcountTests(unittest.TestCase):
+    def test_arg_refs(self):
+        args = ('a', 'b', 'c')
+        refcount_before = sys.getrefcount(args)
+        g = greenlet.greenlet(
+            lambda *args: greenlet.getcurrent().parent.switch(*args))
+        for i in range(100):
+            g.switch(*args)
+        self.assertEqual(sys.getrefcount(args), refcount_before)
+
+    def test_kwarg_refs(self):
+        kwargs = {}
+        g = greenlet.greenlet(
+            lambda **kwargs: greenlet.getcurrent().parent.switch(**kwargs))
+        for i in range(100):
+            g.switch(**kwargs)
+        self.assertEqual(sys.getrefcount(kwargs), 2)
+
+    if greenlet.GREENLET_USE_GC:
+        # These only work with greenlet gc support
+
+        def recycle_threads(self):
+            # By introducing a thread that does sleep we allow other threads,
+            # that have triggered their __block condition, but did not have a
+            # chance to deallocate their thread state yet, to finally do so.
+            # The way it works is by requring a GIL switch (different thread),
+            # which does a GIL release (sleep), which might do a GIL switch
+            # to finished threads and allow them to clean up.
+            def worker():
+                time.sleep(0.001)
+            t = threading.Thread(target=worker)
+            t.start()
+            time.sleep(0.001)
+            t.join()
+
+        def test_threaded_leak(self):
+            gg = []
+            def worker():
+                # only main greenlet present
+                gg.append(weakref.ref(greenlet.getcurrent()))
+            for i in range(2):
+                t = threading.Thread(target=worker)
+                t.start()
+                t.join()
+                del t
+            greenlet.getcurrent() # update ts_current
+            self.recycle_threads()
+            greenlet.getcurrent() # update ts_current
+            gc.collect()
+            greenlet.getcurrent() # update ts_current
+            for g in gg:
+                self.assertTrue(g() is None)
+
+        def test_threaded_adv_leak(self):
+            gg = []
+            def worker():
+                # main and additional *finished* greenlets
+                ll = greenlet.getcurrent().ll = []
+                def additional():
+                    ll.append(greenlet.getcurrent())
+                for i in range(2):
+                    greenlet.greenlet(additional).switch()
+                gg.append(weakref.ref(greenlet.getcurrent()))
+            for i in range(2):
+                t = threading.Thread(target=worker)
+                t.start()
+                t.join()
+                del t
+            greenlet.getcurrent() # update ts_current
+            self.recycle_threads()
+            greenlet.getcurrent() # update ts_current
+            gc.collect()
+            greenlet.getcurrent() # update ts_current
+            for g in gg:
+                self.assertTrue(g() is None)

+ 19 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/test_stack_saved.py

@@ -0,0 +1,19 @@
+import greenlet
+import unittest
+
+
+class Test(unittest.TestCase):
+
+    def test_stack_saved(self):
+        main = greenlet.getcurrent()
+        self.assertEqual(main._stack_saved, 0)
+
+        def func():
+            main.switch(main._stack_saved)
+
+        g = greenlet.greenlet(func)
+        x = g.switch()
+        assert x > 0, x
+        assert g._stack_saved > 0, g._stack_saved
+        g.switch()
+        assert g._stack_saved == 0, g._stack_saved

+ 100 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/test_throw.py

@@ -0,0 +1,100 @@
+import sys
+import unittest
+
+from greenlet import greenlet
+
+
+def switch(*args):
+    return greenlet.getcurrent().parent.switch(*args)
+
+
+class ThrowTests(unittest.TestCase):
+    def test_class(self):
+        def f():
+            try:
+                switch("ok")
+            except RuntimeError:
+                switch("ok")
+                return
+            switch("fail")
+        g = greenlet(f)
+        res = g.switch()
+        self.assertEqual(res, "ok")
+        res = g.throw(RuntimeError)
+        self.assertEqual(res, "ok")
+
+    def test_val(self):
+        def f():
+            try:
+                switch("ok")
+            except RuntimeError:
+                val = sys.exc_info()[1]
+                if str(val) == "ciao":
+                    switch("ok")
+                    return
+            switch("fail")
+
+        g = greenlet(f)
+        res = g.switch()
+        self.assertEqual(res, "ok")
+        res = g.throw(RuntimeError("ciao"))
+        self.assertEqual(res, "ok")
+
+        g = greenlet(f)
+        res = g.switch()
+        self.assertEqual(res, "ok")
+        res = g.throw(RuntimeError, "ciao")
+        self.assertEqual(res, "ok")
+
+    def test_kill(self):
+        def f():
+            switch("ok")
+            switch("fail")
+        g = greenlet(f)
+        res = g.switch()
+        self.assertEqual(res, "ok")
+        res = g.throw()
+        self.assertTrue(isinstance(res, greenlet.GreenletExit))
+        self.assertTrue(g.dead)
+        res = g.throw()    # immediately eaten by the already-dead greenlet
+        self.assertTrue(isinstance(res, greenlet.GreenletExit))
+
+    def test_throw_goes_to_original_parent(self):
+        main = greenlet.getcurrent()
+
+        def f1():
+            try:
+                main.switch("f1 ready to catch")
+            except IndexError:
+                return "caught"
+            else:
+                return "normal exit"
+
+        def f2():
+            main.switch("from f2")
+
+        g1 = greenlet(f1)
+        g2 = greenlet(f2, parent=g1)
+        self.assertRaises(IndexError, g2.throw, IndexError)
+        self.assertTrue(g2.dead)
+        self.assertTrue(g1.dead)
+
+        g1 = greenlet(f1)
+        g2 = greenlet(f2, parent=g1)
+        res = g1.switch()
+        self.assertEqual(res, "f1 ready to catch")
+        res = g2.throw(IndexError)
+        self.assertEqual(res, "caught")
+        self.assertTrue(g2.dead)
+        self.assertTrue(g1.dead)
+
+        g1 = greenlet(f1)
+        g2 = greenlet(f2, parent=g1)
+        res = g1.switch()
+        self.assertEqual(res, "f1 ready to catch")
+        res = g2.switch()
+        self.assertEqual(res, "from f2")
+        res = g2.throw(IndexError)
+        self.assertEqual(res, "caught")
+        self.assertTrue(g2.dead)
+        self.assertTrue(g1.dead)

+ 52 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/test_tracing.py

@@ -0,0 +1,52 @@
+import unittest
+import threading
+import greenlet
+
+class SomeError(Exception):
+    pass
+
+class TracingTests(unittest.TestCase):
+    if greenlet.GREENLET_USE_TRACING:
+        def test_greenlet_tracing(self):
+            main = greenlet.getcurrent()
+            actions = []
+            def trace(*args):
+                actions.append(args)
+            def dummy():
+                pass
+            def dummyexc():
+                raise SomeError()
+            oldtrace = greenlet.settrace(trace)
+            try:
+                g1 = greenlet.greenlet(dummy)
+                g1.switch()
+                g2 = greenlet.greenlet(dummyexc)
+                self.assertRaises(SomeError, g2.switch)
+            finally:
+                greenlet.settrace(oldtrace)
+            self.assertEqual(actions, [
+                ('switch', (main, g1)),
+                ('switch', (g1, main)),
+                ('switch', (main, g2)),
+                ('throw', (g2, main)),
+            ])
+
+        def test_exception_disables_tracing(self):
+            main = greenlet.getcurrent()
+            actions = []
+            def trace(*args):
+                actions.append(args)
+                raise SomeError()
+            def dummy():
+                main.switch()
+            g = greenlet.greenlet(dummy)
+            g.switch()
+            oldtrace = greenlet.settrace(trace)
+            try:
+                self.assertRaises(SomeError, g.switch)
+                self.assertEqual(greenlet.gettrace(), None)
+            finally:
+                greenlet.settrace(oldtrace)
+            self.assertEqual(actions, [
+                ('switch', (main, g)),
+            ])

+ 20 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/test_version.py

@@ -0,0 +1,20 @@
+#! /usr/bin/env python
+
+import sys, os, re, unittest, greenlet
+
+def readclose(f):
+    try:
+        return f.read()
+    finally:
+        f.close()
+
+def readfile(filename):
+    return readclose(open(filename))
+
+class VersionTests(unittest.TestCase):
+    def test_version(self):
+        upfile = lambda p: os.path.join(os.path.dirname(__file__), "..", p)
+        hversion, = re.findall('GREENLET_VERSION "(.*)"', readfile(upfile("greenlet.h")))
+        sversion = readclose(os.popen("%s %s --version" % (sys.executable, upfile("setup.py")))).strip()
+        self.assertFalse(sversion != hversion)
+        self.assertFalse(sversion != greenlet.__version__)

+ 34 - 0
desktop/core/ext-py/greenlet-0.4.15/tests/test_weakref.py

@@ -0,0 +1,34 @@
+import gc
+import greenlet
+import weakref
+import unittest
+
+
+class WeakRefTests(unittest.TestCase):
+    def test_dead_weakref(self):
+        def _dead_greenlet():
+            g = greenlet.greenlet(lambda: None)
+            g.switch()
+            return g
+        o = weakref.ref(_dead_greenlet())
+        gc.collect()
+        self.assertEqual(o(), None)
+
+    def test_inactive_weakref(self):
+        o = weakref.ref(greenlet.greenlet())
+        gc.collect()
+        self.assertEqual(o(), None)
+
+    def test_dealloc_weakref(self):
+        seen = []
+        def worker():
+            try:
+                greenlet.getcurrent().parent.switch()
+            finally:
+                seen.append(g())
+        g = greenlet.greenlet(worker)
+        g.switch()
+        g2 = greenlet.greenlet(lambda: None, g)
+        g = weakref.ref(g2)
+        g2 = None
+        self.assertEqual(seen, [None])

+ 0 - 0
desktop/core/ext-py/greenlet-0.4.12/tox.ini → desktop/core/ext-py/greenlet-0.4.15/tox.ini