PageRenderTime 39ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/_file/interp_stream.py

https://bitbucket.org/pypy/pypy/
Python | 131 lines | 84 code | 16 blank | 31 comment | 16 complexity | 99135a5cce1625af894fdb3e90fb7e68 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import py
  2. from rpython.rlib import streamio
  3. from rpython.rlib.streamio import StreamErrors
  4. from pypy.interpreter.error import OperationError, oefmt
  5. from pypy.interpreter.baseobjspace import ObjSpace, W_Root, CannotHaveLock
  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(W_Root):
  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. me = self.space.getexecutioncontext() # used as thread ident
  31. if self.slockowner is not None:
  32. if self.slockowner is me:
  33. return False # already acquired by the current thread
  34. if self.slockowner.thread_disappeared:
  35. self.slockowner = None
  36. self.slock = None
  37. try:
  38. if self.slock is None:
  39. self.slock = self.space.allocate_lock()
  40. except CannotHaveLock:
  41. pass
  42. else:
  43. self.slock.acquire(True)
  44. assert self.slockowner is None
  45. self.slockowner = me
  46. return True
  47. def _release_lock(self):
  48. self.slockowner = None
  49. if self.slock is not None:
  50. self.slock.release()
  51. def lock(self):
  52. if not self._try_acquire_lock():
  53. raise oefmt(self.space.w_RuntimeError, "stream lock already held")
  54. def unlock(self):
  55. me = self.space.getexecutioncontext() # used as thread ident
  56. if self.slockowner is not me:
  57. raise oefmt(self.space.w_RuntimeError, "stream lock is not held")
  58. self._release_lock()
  59. def _cleanup_(self):
  60. # remove the lock object, which will be created again as needed at
  61. # run-time.
  62. self.slock = None
  63. assert self.slockowner is None
  64. def stream_read(self, n):
  65. """
  66. An interface for direct interp-level usage of W_AbstractStream,
  67. e.g. from interp_marshal.py.
  68. NOTE: this assumes that the stream lock is already acquired.
  69. Like os.read(), this can return less than n bytes.
  70. """
  71. try:
  72. return self.stream.read(n)
  73. except StreamErrors as e:
  74. raise wrap_streamerror(self.space, e)
  75. def do_write(self, data):
  76. """
  77. An interface for direct interp-level usage of W_Stream,
  78. e.g. from interp_marshal.py.
  79. NOTE: this assumes that the stream lock is already acquired.
  80. """
  81. try:
  82. self.stream.write(data)
  83. except StreamErrors as e:
  84. raise wrap_streamerror(self.space, e)
  85. # ____________________________________________________________
  86. class W_Stream(W_AbstractStream):
  87. """A class that exposes the raw stream interface to app-level."""
  88. # this exists for historical reasons, and kept around in case we want
  89. # to re-expose the raw stream interface to app-level.
  90. for name, argtypes in streamio.STREAM_METHODS.iteritems():
  91. numargs = len(argtypes)
  92. args = ", ".join(["v%s" % i for i in range(numargs)])
  93. exec py.code.Source("""
  94. def %(name)s(self, space, %(args)s):
  95. acquired = self.try_acquire_lock()
  96. try:
  97. try:
  98. result = self.stream.%(name)s(%(args)s)
  99. except streamio.StreamError, e:
  100. raise OperationError(space.w_ValueError,
  101. space.wrap(e.message))
  102. except OSError, e:
  103. raise wrap_oserror_as_ioerror(space, e)
  104. finally:
  105. if acquired:
  106. self.release_lock()
  107. return space.wrap(result)
  108. %(name)s.unwrap_spec = [W_Stream, ObjSpace] + argtypes
  109. """ % locals()).compile() in globals()
  110. W_Stream.typedef = TypeDef("Stream",
  111. lock = interp2app(W_Stream.lock),
  112. unlock = interp2app(W_Stream.unlock),
  113. **dict([(name, interp2app(globals()[name]))
  114. for name, _ in streamio.STREAM_METHODS.iteritems()]))