PageRenderTime 50ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/module/_file/interp_stream.py

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