PageRenderTime 43ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/pypy/module/thread/os_local.py

https://bitbucket.org/pypy/pypy/
Python | 102 lines | 76 code | 14 blank | 12 comment | 9 complexity | 68de5ec60d23c550ed925c8eaa4fa921 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import weakref
  2. from rpython.rlib import jit
  3. from pypy.interpreter.baseobjspace import W_Root
  4. from pypy.interpreter.executioncontext import ExecutionContext
  5. from pypy.interpreter.typedef import (TypeDef, interp2app, GetSetProperty,
  6. descr_get_dict)
  7. from rpython.rlib.rshrinklist import AbstractShrinkList
  8. class WRefShrinkList(AbstractShrinkList):
  9. def must_keep(self, wref):
  10. return wref() is not None
  11. ExecutionContext._thread_local_objs = None
  12. class Local(W_Root):
  13. """Thread-local data"""
  14. @jit.dont_look_inside
  15. def __init__(self, space, initargs):
  16. self.initargs = initargs
  17. self.dicts = {} # mapping ExecutionContexts to the wraped dict
  18. # The app-level __init__() will be called by the general
  19. # instance-creation logic. It causes getdict() to be
  20. # immediately called. If we don't prepare and set a w_dict
  21. # for the current thread, then this would in cause getdict()
  22. # to call __init__() a second time.
  23. ec = space.getexecutioncontext()
  24. w_dict = space.newdict(instance=True)
  25. self.dicts[ec] = w_dict
  26. self._register_in_ec(ec)
  27. # cache the last seen dict, works because we are protected by the GIL
  28. self.last_dict = w_dict
  29. self.last_ec = ec
  30. def _register_in_ec(self, ec):
  31. if not ec.space.config.translation.rweakref:
  32. return # without weakrefs, works but 'dicts' is never cleared
  33. if ec._thread_local_objs is None:
  34. ec._thread_local_objs = WRefShrinkList()
  35. ec._thread_local_objs.append(weakref.ref(self))
  36. @jit.dont_look_inside
  37. def create_new_dict(self, ec):
  38. # create a new dict for this thread
  39. space = ec.space
  40. w_dict = space.newdict(instance=True)
  41. self.dicts[ec] = w_dict
  42. # call __init__
  43. try:
  44. w_type = space.type(self)
  45. w_init = space.getattr(w_type, space.wrap("__init__"))
  46. space.call_obj_args(w_init, self, self.initargs)
  47. except:
  48. # failed, forget w_dict and propagate the exception
  49. del self.dicts[ec]
  50. raise
  51. # ready
  52. self._register_in_ec(ec)
  53. return w_dict
  54. def getdict(self, space):
  55. ec = space.getexecutioncontext()
  56. if ec is self.last_ec:
  57. return self.last_dict
  58. try:
  59. w_dict = self.dicts[ec]
  60. except KeyError:
  61. w_dict = self.create_new_dict(ec)
  62. self.last_ec = ec
  63. self.last_dict = w_dict
  64. return w_dict
  65. def descr_local__new__(space, w_subtype, __args__):
  66. local = space.allocate_instance(Local, w_subtype)
  67. Local.__init__(local, space, __args__)
  68. return space.wrap(local)
  69. def descr_local__init__(self, space):
  70. # No arguments allowed
  71. pass
  72. Local.typedef = TypeDef("thread._local",
  73. __doc__ = "Thread-local data",
  74. __new__ = interp2app(Local.descr_local__new__.im_func),
  75. __init__ = interp2app(Local.descr_local__init__),
  76. __dict__ = GetSetProperty(descr_get_dict, cls=Local),
  77. )
  78. def thread_is_stopping(ec):
  79. tlobjs = ec._thread_local_objs
  80. if tlobjs is None:
  81. return
  82. ec._thread_local_objs = None
  83. for wref in tlobjs.items():
  84. local = wref()
  85. if local is not None:
  86. del local.dicts[ec]
  87. local.last_dict = None
  88. local.last_ec = None