_test_extension_cpp.cpp 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /* This is a set of functions used to test C++ exceptions are not
  2. * broken during greenlet switches
  3. */
  4. #include "../greenlet.h"
  5. struct exception_t {
  6. int depth;
  7. exception_t(int depth) : depth(depth) {}
  8. };
  9. /* Functions are called via pointers to prevent inlining */
  10. static void (*p_test_exception_throw)(int depth);
  11. static PyObject* (*p_test_exception_switch_recurse)(int depth, int left);
  12. static void
  13. test_exception_throw(int depth)
  14. {
  15. throw exception_t(depth);
  16. }
  17. static PyObject*
  18. test_exception_switch_recurse(int depth, int left)
  19. {
  20. if (left > 0) {
  21. return p_test_exception_switch_recurse(depth, left - 1);
  22. }
  23. PyObject* result = NULL;
  24. PyGreenlet* self = PyGreenlet_GetCurrent();
  25. if (self == NULL)
  26. return NULL;
  27. try {
  28. PyGreenlet_Switch(self->parent, NULL, NULL);
  29. p_test_exception_throw(depth);
  30. PyErr_SetString(PyExc_RuntimeError,
  31. "throwing C++ exception didn't work");
  32. }
  33. catch (exception_t& e) {
  34. if (e.depth != depth)
  35. PyErr_SetString(PyExc_AssertionError, "depth mismatch");
  36. else
  37. result = PyLong_FromLong(depth);
  38. }
  39. catch (...) {
  40. PyErr_SetString(PyExc_RuntimeError, "unexpected C++ exception");
  41. }
  42. Py_DECREF(self);
  43. return result;
  44. }
  45. /* test_exception_switch(int depth)
  46. * - recurses depth times
  47. * - switches to parent inside try/catch block
  48. * - throws an exception that (expected to be caught in the same function)
  49. * - verifies depth matches (exceptions shouldn't be caught in other greenlets)
  50. */
  51. static PyObject*
  52. test_exception_switch(PyObject* self, PyObject* args)
  53. {
  54. int depth;
  55. if (!PyArg_ParseTuple(args, "i", &depth))
  56. return NULL;
  57. return p_test_exception_switch_recurse(depth, depth);
  58. }
  59. static PyMethodDef test_methods[] = {
  60. {"test_exception_switch",
  61. (PyCFunction)&test_exception_switch,
  62. METH_VARARGS,
  63. "Switches to parent twice, to test exception handling and greenlet "
  64. "switching."},
  65. {NULL, NULL, 0, NULL}};
  66. #if PY_MAJOR_VERSION >= 3
  67. # define INITERROR return NULL
  68. static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT,
  69. "greenlet.tests._test_extension_cpp",
  70. NULL,
  71. 0,
  72. test_methods,
  73. NULL,
  74. NULL,
  75. NULL,
  76. NULL};
  77. PyMODINIT_FUNC
  78. PyInit__test_extension_cpp(void)
  79. #else
  80. # define INITERROR return
  81. PyMODINIT_FUNC
  82. init_test_extension_cpp(void)
  83. #endif
  84. {
  85. PyObject* module = NULL;
  86. #if PY_MAJOR_VERSION >= 3
  87. module = PyModule_Create(&moduledef);
  88. #else
  89. module = Py_InitModule("greenlet.tests._test_extension_cpp", test_methods);
  90. #endif
  91. if (module == NULL) {
  92. INITERROR;
  93. }
  94. PyGreenlet_Import();
  95. if (_PyGreenlet_API == NULL) {
  96. INITERROR;
  97. }
  98. p_test_exception_throw = test_exception_throw;
  99. p_test_exception_switch_recurse = test_exception_switch_recurse;
  100. #if PY_MAJOR_VERSION >= 3
  101. return module;
  102. #endif
  103. }