/pypy/module/_cffi_backend/errorbox.py

https://github.com/mozillazg/pypy · Python · 115 lines · 98 code · 16 blank · 1 comment · 5 complexity · b96d4580c6f11489e9190cf37f30864d MD5 · raw file

  1. # for Windows only
  2. import sys
  3. from rpython.rlib import jit
  4. from rpython.rtyper.lltypesystem import lltype, rffi
  5. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  6. MESSAGEBOX = sys.platform == "win32"
  7. MODULE = r"""
  8. #include <Windows.h>
  9. #pragma comment(lib, "user32.lib")
  10. static void *volatile _cffi_bootstrap_text;
  11. RPY_EXTERN int _cffi_errorbox1(void)
  12. {
  13. return InterlockedCompareExchangePointer(&_cffi_bootstrap_text,
  14. (void *)1, NULL) == NULL;
  15. }
  16. static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored)
  17. {
  18. Sleep(666); /* may be interrupted if the whole process is closing */
  19. MessageBoxA(NULL, (char *)_cffi_bootstrap_text,
  20. "PyPy: Python-CFFI error",
  21. MB_OK | MB_ICONERROR);
  22. _cffi_bootstrap_text = NULL;
  23. return 0;
  24. }
  25. RPY_EXTERN void _cffi_errorbox(char *text)
  26. {
  27. /* Show a dialog box, but in a background thread, and
  28. never show multiple dialog boxes at once. */
  29. HANDLE h;
  30. _cffi_bootstrap_text = text;
  31. h = CreateThread(NULL, 0, _cffi_bootstrap_dialog,
  32. NULL, 0, NULL);
  33. if (h != NULL)
  34. CloseHandle(h);
  35. }
  36. """
  37. if MESSAGEBOX:
  38. eci = ExternalCompilationInfo(
  39. separate_module_sources=[MODULE],
  40. post_include_bits=["RPY_EXTERN int _cffi_errorbox1(void);\n"
  41. "RPY_EXTERN void _cffi_errorbox(char *);\n"])
  42. cffi_errorbox1 = rffi.llexternal("_cffi_errorbox1", [],
  43. rffi.INT, compilation_info=eci)
  44. cffi_errorbox = rffi.llexternal("_cffi_errorbox", [rffi.CCHARP],
  45. lltype.Void, compilation_info=eci)
  46. class Message:
  47. def __init__(self, space):
  48. self.space = space
  49. self.text_p = lltype.nullptr(rffi.CCHARP.TO)
  50. def start_error_capture(self):
  51. ok = cffi_errorbox1()
  52. if rffi.cast(lltype.Signed, ok) != 1:
  53. return None
  54. return self.space.appexec([], """():
  55. import sys
  56. class FileLike:
  57. def write(self, x):
  58. try:
  59. of.write(x)
  60. except:
  61. pass
  62. self.buf += x
  63. fl = FileLike()
  64. fl.buf = ''
  65. of = sys.stderr
  66. sys.stderr = fl
  67. def done():
  68. sys.stderr = of
  69. return fl.buf
  70. return done
  71. """)
  72. def stop_error_capture(self, w_done):
  73. if w_done is None:
  74. return
  75. w_text = self.space.call_function(w_done)
  76. p = rffi.str2charp(self.space.bytes_w(w_text),
  77. track_allocation=False)
  78. if self.text_p:
  79. rffi.free_charp(self.text_p, track_allocation=False)
  80. self.text_p = p # keepalive
  81. cffi_errorbox(p)
  82. @jit.dont_look_inside
  83. def start_error_capture(space):
  84. msg = space.fromcache(Message)
  85. return msg.start_error_capture()
  86. @jit.dont_look_inside
  87. def stop_error_capture(space, x):
  88. msg = space.fromcache(Message)
  89. msg.stop_error_capture(x)
  90. else:
  91. def start_error_capture(space):
  92. return None
  93. def stop_error_capture(space, nothing):
  94. pass