4949import com .oracle .graal .python .PythonLanguage ;
5050import com .oracle .graal .python .builtins .Builtin ;
5151import com .oracle .graal .python .builtins .CoreFunctions ;
52+ import com .oracle .graal .python .builtins .Python3Core ;
5253import com .oracle .graal .python .builtins .PythonBuiltinClassType ;
5354import com .oracle .graal .python .builtins .PythonBuiltins ;
5455import com .oracle .graal .python .builtins .objects .PNone ;
5556import com .oracle .graal .python .builtins .objects .exception .PBaseException ;
5657import com .oracle .graal .python .builtins .objects .function .PKeyword ;
58+ import com .oracle .graal .python .builtins .objects .module .PythonModule ;
5759import com .oracle .graal .python .builtins .objects .thread .PLock ;
5860import com .oracle .graal .python .builtins .objects .thread .PRLock ;
5961import com .oracle .graal .python .builtins .objects .thread .PThread ;
6769import com .oracle .graal .python .nodes .function .builtins .PythonUnaryBuiltinNode ;
6870import com .oracle .graal .python .runtime .GilNode ;
6971import com .oracle .graal .python .runtime .PythonContext ;
70- import com .oracle .graal .python .builtins .Python3Core ;
7172import com .oracle .graal .python .runtime .exception .PException ;
7273import com .oracle .graal .python .runtime .exception .PythonThreadKillException ;
7374import com .oracle .truffle .api .CompilerDirectives .TruffleBoundary ;
75+ import com .oracle .truffle .api .CompilerDirectives ;
7476import com .oracle .truffle .api .TruffleLanguage ;
7577import com .oracle .truffle .api .dsl .Cached ;
7678import com .oracle .truffle .api .dsl .CachedContext ;
7779import com .oracle .truffle .api .dsl .GenerateNodeFactory ;
7880import com .oracle .truffle .api .dsl .NodeFactory ;
7981import com .oracle .truffle .api .dsl .Specialization ;
8082import com .oracle .truffle .api .frame .VirtualFrame ;
83+ import com .oracle .truffle .api .nodes .UnexpectedResultException ;
84+ import com .oracle .truffle .api .object .DynamicObjectLibrary ;
85+ import com .oracle .truffle .api .object .HiddenKey ;
8186import com .oracle .truffle .api .profiles .ConditionProfile ;
8287
8388@ CoreFunctions (defineModule = "_thread" )
8489public class ThreadModuleBuiltins extends PythonBuiltins {
90+ private static final HiddenKey THREAD_COUNT = new HiddenKey ("thread_count" );
91+
8592 @ Override
8693 protected List <? extends NodeFactory <? extends PythonBuiltinBaseNode >> getNodeFactories () {
8794 return ThreadModuleBuiltinsFactory .getFactories ();
@@ -91,6 +98,7 @@ protected List<? extends NodeFactory<? extends PythonBuiltinBaseNode>> getNodeFa
9198 public void initialize (Python3Core core ) {
9299 builtinConstants .put ("error" , core .lookupType (PythonBuiltinClassType .RuntimeError ));
93100 builtinConstants .put ("TIMEOUT_MAX" , TIMEOUT_MAX );
101+ builtinConstants .put (THREAD_COUNT , 0 );
94102 super .initialize (core );
95103 }
96104
@@ -140,13 +148,17 @@ public static long getId() {
140148 }
141149 }
142150
143- @ Builtin (name = "_count" , minNumOfPositionalArgs = 0 )
151+ @ Builtin (name = "_count" , minNumOfPositionalArgs = 1 , declaresExplicitSelf = true )
144152 @ GenerateNodeFactory
145- abstract static class GetThreadCountNode extends PythonBuiltinNode {
153+ abstract static class GetThreadCountNode extends PythonUnaryBuiltinNode {
146154 @ Specialization
147155 @ TruffleBoundary
148- long getCount () {
149- return getContext ().getThreadGroup ().activeCount ();
156+ long getCount (PythonModule self ) {
157+ try {
158+ return DynamicObjectLibrary .getUncached ().getIntOrDefault (self , THREAD_COUNT , 0 );
159+ } catch (UnexpectedResultException e ) {
160+ throw CompilerDirectives .shouldNotReachHere ();
161+ }
150162 }
151163 }
152164
@@ -189,6 +201,7 @@ long start(VirtualFrame frame, Object cls, Object callable, Object args, Object
189201 @ Cached ExpandKeywordStarargsNode getKwArgsNode ) {
190202 PythonContext context = getContext ();
191203 TruffleLanguage .Env env = context .getEnv ();
204+ PythonModule threadModule = context .getCore ().lookupBuiltinModule ("_thread" );
192205
193206 // TODO: python thread stack size != java thread stack size
194207 // ignore setting the stack size for the moment
@@ -197,11 +210,31 @@ long start(VirtualFrame frame, Object cls, Object callable, Object args, Object
197210 PKeyword [] keywords = getKwArgsNode .execute (kwargs );
198211
199212 try (GilNode .UncachedAcquire gil = GilNode .uncachedAcquire ()) {
200- // n.b.: It is important to pass 'null' frame here because each thread has it's
201- // own stack and if we would pass the current frame, this would be connected as
202- // a caller which is incorrect. However, the thread-local 'topframeref' is
203- // initialized with EMPTY which will be picked up.
204- callNode .execute (null , callable , arguments , keywords );
213+ // the increment is protected by the gil
214+ DynamicObjectLibrary lib = DynamicObjectLibrary .getUncached ();
215+ int curCount = 0 ;
216+ try {
217+ curCount = lib .getIntOrDefault (threadModule , THREAD_COUNT , 0 );
218+ } catch (UnexpectedResultException ure ) {
219+ throw CompilerDirectives .shouldNotReachHere ();
220+ }
221+ lib .putInt (threadModule , THREAD_COUNT , curCount + 1 );
222+ try {
223+ // n.b.: It is important to pass 'null' frame here because each thread has
224+ // it's own stack and if we would pass the current frame, this would be
225+ // connected as a caller which is incorrect. However, the thread-local
226+ // 'topframeref' is initialized with EMPTY which will be picked up.
227+ callNode .execute (null , callable , arguments , keywords );
228+ } finally {
229+ // the catch blocks run ofter the gil is released, so we decrement the
230+ // threadcount here while still protected by the gil
231+ try {
232+ curCount = lib .getIntOrDefault (threadModule , THREAD_COUNT , 1 );
233+ } catch (UnexpectedResultException ure ) {
234+ throw CompilerDirectives .shouldNotReachHere ();
235+ }
236+ lib .putInt (threadModule , THREAD_COUNT , curCount - 1 );
237+ }
205238 } catch (PythonThreadKillException e ) {
206239 return ;
207240 } catch (PException e ) {
0 commit comments