PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/_file/interp_stream.py

https://bitbucket.org/quangquach/pypy
Python | 122 lines | 77 code | 14 blank | 31 comment | 10 complexity | b491a1b7ad27a62fe540b09b805364a3 MD5 | raw file
  1. import py
  2. from pypy.rlib import streamio
  3. from pypy.rlib.streamio import StreamErrors
  4. from pypy.interpreter.error import OperationError
  5. from pypy.interpreter.baseobjspace import ObjSpace, Wrappable
  6. from pypy.interpreter.typedef import TypeDef
  7. from pypy.interpreter.gateway import interp2app
  8. from pypy.interpreter.streamutil import wrap_streamerror, wrap_oserror_as_ioerror
  9. class W_AbstractStream(Wrappable):
  10. """Base class for interp-level objects that expose streams to app-level"""
  11. slock = None
  12. slockowner = None
  13. # Locking issues:
  14. # * Multiple threads can access the same W_AbstractStream in
  15. # parallel, because many of the streamio calls eventually
  16. # release the GIL in some external function call.
  17. # * Parallel accesses have bad (and crashing) effects on the
  18. # internal state of the buffering levels of the stream in
  19. # particular.
  20. # * We can't easily have a lock on each W_AbstractStream because we
  21. # can't translate prebuilt lock objects.
  22. # We are still protected by the GIL, so the easiest is to create
  23. # the lock on-demand.
  24. def __init__(self, space, stream):
  25. self.space = space
  26. self.stream = stream
  27. def _try_acquire_lock(self):
  28. # this function runs with the GIL acquired so there is no race
  29. # condition in the creation of the lock
  30. if self.slock is None:
  31. self.slock = self.space.allocate_lock()
  32. me = self.space.getexecutioncontext() # used as thread ident
  33. if self.slockowner is me:
  34. return False # already acquired by the current thread
  35. self.slock.acquire(True)
  36. assert self.slockowner is None
  37. self.slockowner = me
  38. return True
  39. def _release_lock(self):
  40. self.slockowner = None
  41. self.slock.release()
  42. def lock(self):
  43. if not self._try_acquire_lock():
  44. raise OperationError(self.space.w_RuntimeError,
  45. self.space.wrap("stream lock already held"))
  46. def unlock(self):
  47. me = self.space.getexecutioncontext() # used as thread ident
  48. if self.slockowner is not me:
  49. raise OperationError(self.space.w_RuntimeError,
  50. self.space.wrap("stream lock is not held"))
  51. self._release_lock()
  52. def _cleanup_(self):
  53. # remove the lock object, which will be created again as needed at
  54. # run-time.
  55. self.slock = None
  56. assert self.slockowner is None
  57. def stream_read(self, n):
  58. """
  59. An interface for direct interp-level usage of W_AbstractStream,
  60. e.g. from interp_marshal.py.
  61. NOTE: this assumes that the stream lock is already acquired.
  62. Like os.read(), this can return less than n bytes.
  63. """
  64. try:
  65. return self.stream.read(n)
  66. except StreamErrors, e:
  67. raise wrap_streamerror(self.space, e)
  68. def do_write(self, data):
  69. """
  70. An interface for direct interp-level usage of W_Stream,
  71. e.g. from interp_marshal.py.
  72. NOTE: this assumes that the stream lock is already acquired.
  73. """
  74. try:
  75. self.stream.write(data)
  76. except StreamErrors, e:
  77. raise wrap_streamerror(self.space, e)
  78. # ____________________________________________________________
  79. class W_Stream(W_AbstractStream):
  80. """A class that exposes the raw stream interface to app-level."""
  81. # this exists for historical reasons, and kept around in case we want
  82. # to re-expose the raw stream interface to app-level.
  83. for name, argtypes in streamio.STREAM_METHODS.iteritems():
  84. numargs = len(argtypes)
  85. args = ", ".join(["v%s" % i for i in range(numargs)])
  86. exec py.code.Source("""
  87. def %(name)s(self, space, %(args)s):
  88. acquired = self.try_acquire_lock()
  89. try:
  90. try:
  91. result = self.stream.%(name)s(%(args)s)
  92. except streamio.StreamError, e:
  93. raise OperationError(space.w_ValueError,
  94. space.wrap(e.message))
  95. except OSError, e:
  96. raise wrap_oserror_as_ioerror(space, e)
  97. finally:
  98. if acquired:
  99. self.release_lock()
  100. return space.wrap(result)
  101. %(name)s.unwrap_spec = [W_Stream, ObjSpace] + argtypes
  102. """ % locals()).compile() in globals()
  103. W_Stream.typedef = TypeDef("Stream",
  104. lock = interp2app(W_Stream.lock),
  105. unlock = interp2app(W_Stream.unlock),
  106. **dict([(name, interp2app(globals()[name]))
  107. for name, _ in streamio.STREAM_METHODS.iteritems()]))